Skip to content

Commit

Permalink
eth_sendRawTransactionConditional
Browse files Browse the repository at this point in the history
  • Loading branch information
hamdiallam committed Jun 26, 2024
1 parent 5e9cb81 commit 7cf7964
Show file tree
Hide file tree
Showing 19 changed files with 1,378 additions and 2 deletions.
2 changes: 2 additions & 0 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ var (
utils.GpoIgnoreGasPriceFlag,
utils.GpoMinSuggestedPriorityFeeFlag,
utils.RollupSequencerHTTPFlag,
utils.RollupSequencerEnableTxConditionalFlag,
utils.RollupSequencerTxConditionalRateLimitFlag,
utils.RollupHistoricalRPCFlag,
utils.RollupHistoricalRPCTimeoutFlag,
utils.RollupDisableTxPoolGossipFlag,
Expand Down
17 changes: 17 additions & 0 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,18 @@ var (
Category: flags.RollupCategory,
Value: true,
}
RollupSequencerEnableTxConditionalFlag = &cli.BoolFlag{
Name: "rollup.sequencerenabletxconditional",
Usage: "Serve the eth_sendRawTransactionConditional endpoint and apply the conditional constraints on mempool inclusion & block building",
Category: flags.RollupCategory,
Value: false,
}
RollupSequencerTxConditionalRateLimitFlag = &cli.Uint64Flag{
Name: "rollup.sequencertxconditionalratelimit",
Usage: "Maximum cost -- storage lookups -- allowed for conditional transactions in a given second",
Category: flags.RollupCategory,
Value: 5000,
}

// Metrics flags
MetricsEnabledFlag = &cli.BoolFlag{
Expand Down Expand Up @@ -1635,6 +1647,9 @@ func setMiner(ctx *cli.Context, cfg *miner.Config) {
if ctx.IsSet(RollupComputePendingBlock.Name) {
cfg.RollupComputePendingBlock = ctx.Bool(RollupComputePendingBlock.Name)
}
if ctx.IsSet(RollupSequencerTxConditionalRateLimitFlag.Name) {
cfg.RollupTransactionConditionalBurstRate = int(ctx.Uint64(RollupSequencerTxConditionalRateLimitFlag.Name))
}
}

func setRequiredBlocks(ctx *cli.Context, cfg *ethconfig.Config) {
Expand Down Expand Up @@ -1866,6 +1881,8 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
cfg.RollupDisableTxPoolAdmission = cfg.RollupSequencerHTTP != "" && !ctx.Bool(RollupEnableTxPoolAdmissionFlag.Name)
cfg.RollupHaltOnIncompatibleProtocolVersion = ctx.String(RollupHaltOnIncompatibleProtocolVersionFlag.Name)
cfg.ApplySuperchainUpgrades = ctx.Bool(RollupSuperchainUpgradesFlag.Name)
cfg.RollupSequencerEnableTxConditional = ctx.Bool(RollupSequencerEnableTxConditionalFlag.Name)

// Override any default configs for hard coded networks.
switch {
case ctx.Bool(MainnetFlag.Name):
Expand Down
32 changes: 32 additions & 0 deletions core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,38 @@ func (s *StateDB) HasSelfDestructed(addr common.Address) bool {
return false
}

// CheckTransactionConditional validates the account preconditions against the statedb.
//
// NOTE: A lock is not held on the db while the conditional is checked. The caller must
// ensure no state changes occur while this check is executed.
func (s *StateDB) CheckTransactionConditional(cond *types.TransactionConditional) error {
cost := cond.Cost()
if cost > types.TransactionConditionalMaxCost {
return fmt.Errorf("conditional cost, %d, exceeded max: %d", cost, types.TransactionConditionalMaxCost)
}

for addr, acct := range cond.KnownAccounts {
if root, isRoot := acct.Root(); isRoot {
storageRoot := s.GetStorageRoot(addr)
if storageRoot == (common.Hash{}) { // if the root is not found, replace with the empty root hash
storageRoot = types.EmptyRootHash
}
if root != storageRoot {
return fmt.Errorf("failed account storage root constraint. Got %s, Expected %s", storageRoot, root)
}
}
if slots, isSlots := acct.Slots(); isSlots {
for key, state := range slots {
accState := s.GetState(addr, key)
if state != accState {
return fmt.Errorf("failed account storage slot key %s constraint. Got %s, Expected %s", key, accState, state)
}
}
}
}
return nil
}

/*
* SETTERS
*/
Expand Down
218 changes: 218 additions & 0 deletions core/state/statedb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1189,3 +1189,221 @@ func TestDeleteStorage(t *testing.T) {
t.Fatalf("difference found:\nfast: %v\nslow: %v\n", fastRes, slowRes)
}
}

func TestCheckTransactionConditional(t *testing.T) {
type preAction struct {
Account common.Address
Slots map[common.Hash]common.Hash
}

tests := []struct {
name string
preActions []preAction
cond types.TransactionConditional
valid bool
}{
{
// Clean Prestate, no defined cond
name: "clean prestate",
preActions: []preAction{},
cond: types.TransactionConditional{},
valid: true,
},
{
// Prestate:
// - address(1)
// - bytes32(0): bytes32(1)
// cond:
// - address(1)
// - bytes32(0): bytes32(1)
name: "matching storage slots",
preActions: []preAction{
{
Account: common.Address{19: 1},
Slots: map[common.Hash]common.Hash{
common.Hash{}: common.Hash{31: 1},
},
},
},
cond: types.TransactionConditional{
KnownAccounts: map[common.Address]types.KnownAccount{
common.Address{19: 1}: types.KnownAccount{
StorageSlots: map[common.Hash]common.Hash{
common.Hash{}: common.Hash{31: 1},
},
},
},
},
valid: true,
},
{
// Prestate:
// - address(1)
// - bytes32(0): bytes32(1)
// cond:
// - address(1)
// - bytes32(0): bytes32(2)
name: "mismatched storage slots",
preActions: []preAction{
{
Account: common.Address{19: 1},
Slots: map[common.Hash]common.Hash{
common.Hash{}: common.Hash{31: 1},
},
},
},
cond: types.TransactionConditional{
KnownAccounts: map[common.Address]types.KnownAccount{
common.Address{19: 1}: types.KnownAccount{
StorageSlots: map[common.Hash]common.Hash{
common.Hash{}: common.Hash{31: 2},
},
},
},
},
valid: false,
},
{
// Clean Prestate
// cond:
// - address(1)
// - emptyRoot
name: "matching storage root",
preActions: []preAction{},
cond: types.TransactionConditional{
KnownAccounts: map[common.Address]types.KnownAccount{
common.Address{19: 1}: types.KnownAccount{
StorageRoot: &types.EmptyRootHash,
},
},
},
valid: true,
},
{
// Prestate:
// - address(1)
// - bytes32(0): bytes32(1)
// cond:
// - address(1)
// - emptyRoot
name: "mismatched storage root",
preActions: []preAction{
{
Account: common.Address{19: 1},
Slots: map[common.Hash]common.Hash{
common.Hash{}: common.Hash{31: 1},
},
},
},
cond: types.TransactionConditional{
KnownAccounts: map[common.Address]types.KnownAccount{
common.Address{19: 1}: types.KnownAccount{
StorageRoot: &types.EmptyRootHash,
},
},
},
valid: false,
},
{
// Prestate:
// - address(1)
// - bytes32(0): bytes32(1)
// - address(2)
// - bytes32(0): bytes32(2)
// cond:
// - address(1)
// - bytes32(0): bytes32(1)
// - address(2)
// - bytes32(0): bytes32(2)
name: "multiple matching",
preActions: []preAction{
{
Account: common.Address{19: 1},
Slots: map[common.Hash]common.Hash{
common.Hash{}: common.Hash{31: 1},
},
},
{
Account: common.Address{19: 2},
Slots: map[common.Hash]common.Hash{
common.Hash{}: common.Hash{31: 2},
},
},
},
cond: types.TransactionConditional{
KnownAccounts: map[common.Address]types.KnownAccount{
common.Address{19: 1}: types.KnownAccount{
StorageSlots: map[common.Hash]common.Hash{
common.Hash{}: common.Hash{31: 1},
},
},
common.Address{19: 2}: types.KnownAccount{
StorageSlots: map[common.Hash]common.Hash{
common.Hash{}: common.Hash{31: 2},
},
},
},
},
valid: true,
},
{
// Prestate:
// - address(1)
// - bytes32(0): bytes32(1)
// - address(2)
// - bytes32(0): bytes32(3)
// cond:
// - address(1)
// - bytes32(0): bytes32(1)
// - address(2)
// - bytes32(0): bytes32(2)
name: "multiple mismatch single",
preActions: []preAction{
{
Account: common.Address{19: 1},
Slots: map[common.Hash]common.Hash{
common.Hash{}: common.Hash{31: 1},
},
},
{
Account: common.Address{19: 2},
Slots: map[common.Hash]common.Hash{
common.Hash{}: common.Hash{31: 3},
},
},
},
cond: types.TransactionConditional{
KnownAccounts: map[common.Address]types.KnownAccount{
common.Address{19: 1}: types.KnownAccount{
StorageSlots: map[common.Hash]common.Hash{
common.Hash{}: common.Hash{31: 1},
},
},
common.Address{19: 2}: types.KnownAccount{
StorageSlots: map[common.Hash]common.Hash{
common.Hash{}: common.Hash{31: 2},
},
},
},
},
valid: false,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil)
for _, action := range test.preActions {
for key, value := range action.Slots {
state.SetState(action.Account, key, value)
}
}

// write modifications to the trie
state.IntermediateRoot(false)
if err := state.CheckTransactionConditional(&test.cond); err == nil && !test.valid {
t.Errorf("Test %s got unvalid value: want %v, got err %v", test.name, test.valid, err)
}
})
}
}
1 change: 1 addition & 0 deletions core/txpool/legacypool/legacypool.go
Original file line number Diff line number Diff line change
Expand Up @@ -1739,6 +1739,7 @@ func (pool *LegacyPool) demoteUnexecutables() {
// Internal shuffle shouldn't touch the lookup set.
pool.enqueueTx(hash, tx, false, false)
}

pendingGauge.Dec(int64(len(olds) + len(drops) + len(invalids)))
if pool.locals.contains(addr) {
localGauge.Dec(int64(len(olds) + len(drops) + len(invalids)))
Expand Down
17 changes: 17 additions & 0 deletions core/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,23 @@ func (h *Header) EmptyReceipts() bool {
return h.ReceiptHash == EmptyReceiptsHash
}

// CheckTransactionConditional validates the block preconditions against the header
func (h *Header) CheckTransactionConditional(cond *TransactionConditional) error {
if cond.BlockNumberMin != nil && cond.BlockNumberMin.Cmp(h.Number) > 0 {
return fmt.Errorf("failed block number minimum constraint")
}
if cond.BlockNumberMax != nil && cond.BlockNumberMax.Cmp(h.Number) < 0 {
return fmt.Errorf("failed block number maximmum constraint")
}
if cond.TimestampMin != nil && *cond.TimestampMin > h.Time {
return fmt.Errorf("failed timestamp minimum constraint")
}
if cond.TimestampMax != nil && *cond.TimestampMax < h.Time {
return fmt.Errorf("failed timestamp maximum constraint")
}
return nil
}

// Body is a simple (mutable, non-safe) data container for storing and moving
// a block's data contents (transactions and uncles) together.
type Body struct {
Expand Down
Loading

0 comments on commit 7cf7964

Please sign in to comment.