diff --git a/arbitrum/apibackend.go b/arbitrum/apibackend.go index d78addcb8..db4a10142 100644 --- a/arbitrum/apibackend.go +++ b/arbitrum/apibackend.go @@ -46,8 +46,6 @@ var ( type APIBackend struct { b *Backend - dbForAPICalls ethdb.Database - fallbackClient types.FallbackClient sync SyncProgressBackend } @@ -129,15 +127,8 @@ func createRegisterAPIBackend(backend *Backend, filterConfig filters.Config, fal if err != nil { return nil, err } - // discard stylus-tag on any call made from api database - dbForAPICalls := backend.chainDb - wasmStore, tag := backend.chainDb.WasmDataBase() - if tag != 0 || len(backend.chainDb.WasmTargets()) > 1 { - dbForAPICalls = rawdb.WrapDatabaseWithWasm(backend.chainDb, wasmStore, 0, []ethdb.WasmTarget{rawdb.LocalTarget()}) - } backend.apiBackend = &APIBackend{ b: backend, - dbForAPICalls: dbForAPICalls, fallbackClient: fallbackClient, } filterSystem := filters.NewFilterSystem(backend.apiBackend, filterConfig) @@ -357,7 +348,7 @@ func (a *APIBackend) BlobBaseFee(ctx context.Context) *big.Int { } func (a *APIBackend) ChainDb() ethdb.Database { - return a.dbForAPICalls + return a.b.chainDb } func (a *APIBackend) AccountManager() *accounts.Manager { diff --git a/arbitrum/recordingdb.go b/arbitrum/recordingdb.go index 5f7d7459d..dda9b64a6 100644 --- a/arbitrum/recordingdb.go +++ b/arbitrum/recordingdb.go @@ -266,7 +266,7 @@ func (r *RecordingDatabase) PrepareRecording(ctx context.Context, lastBlockHeade defer func() { r.Dereference(finalDereference) }() recordingKeyValue := newRecordingKV(r.db.TrieDB(), r.db.DiskDB()) - recordingStateDatabase := state.NewDatabase(triedb.NewDatabase(rawdb.WrapDatabaseWithWasm(rawdb.NewDatabase(recordingKeyValue), r.db.WasmStore(), 0, r.db.WasmTargets()), nil), nil) + recordingStateDatabase := state.NewDatabase(triedb.NewDatabase(rawdb.WrapDatabaseWithWasm(rawdb.NewDatabase(recordingKeyValue), r.db.WasmStore()), nil), nil) var prevRoot common.Hash if lastBlockHeader != nil { prevRoot = lastBlockHeader.Root diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 2efdf1800..32070d84d 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -236,7 +236,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, rejectedTxs = append(rejectedTxs, &rejectedTx{i, errMsg}) continue } - msg, err := core.TransactionToMessage(tx, signer, pre.Env.BaseFee, core.MessageCommitMode) + msg, err := core.TransactionToMessage(tx, signer, pre.Env.BaseFee, core.NewMessageCommitContext(nil)) if err != nil { log.Warn("rejected tx", "index", i, "hash", tx.Hash(), "error", err) rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()}) diff --git a/core/rawdb/accessors_state_arbitrum.go b/core/rawdb/accessors_state_arbitrum.go index b6b282d67..7c7898cd1 100644 --- a/core/rawdb/accessors_state_arbitrum.go +++ b/core/rawdb/accessors_state_arbitrum.go @@ -25,14 +25,16 @@ import ( "github.com/ethereum/go-ethereum/log" ) +type WasmTarget string + const ( - TargetWavm ethdb.WasmTarget = "wavm" - TargetArm64 ethdb.WasmTarget = "arm64" - TargetAmd64 ethdb.WasmTarget = "amd64" - TargetHost ethdb.WasmTarget = "host" + TargetWavm WasmTarget = "wavm" + TargetArm64 WasmTarget = "arm64" + TargetAmd64 WasmTarget = "amd64" + TargetHost WasmTarget = "host" ) -func LocalTarget() ethdb.WasmTarget { +func LocalTarget() WasmTarget { if runtime.GOOS == "linux" { switch runtime.GOARCH { case "arm64": @@ -44,7 +46,7 @@ func LocalTarget() ethdb.WasmTarget { return TargetHost } -func activatedAsmKeyPrefix(target ethdb.WasmTarget) (WasmPrefix, error) { +func activatedAsmKeyPrefix(target WasmTarget) (WasmPrefix, error) { var prefix WasmPrefix switch target { case TargetWavm: @@ -61,19 +63,19 @@ func activatedAsmKeyPrefix(target ethdb.WasmTarget) (WasmPrefix, error) { return prefix, nil } -func IsSupportedWasmTarget(target ethdb.WasmTarget) bool { +func IsSupportedWasmTarget(target WasmTarget) bool { _, err := activatedAsmKeyPrefix(target) return err == nil } -func WriteActivation(db ethdb.KeyValueWriter, moduleHash common.Hash, asmMap map[ethdb.WasmTarget][]byte) { +func WriteActivation(db ethdb.KeyValueWriter, moduleHash common.Hash, asmMap map[WasmTarget][]byte) { for target, asm := range asmMap { WriteActivatedAsm(db, target, moduleHash, asm) } } // Stores the activated asm for a given moduleHash and target -func WriteActivatedAsm(db ethdb.KeyValueWriter, target ethdb.WasmTarget, moduleHash common.Hash, asm []byte) { +func WriteActivatedAsm(db ethdb.KeyValueWriter, target WasmTarget, moduleHash common.Hash, asm []byte) { prefix, err := activatedAsmKeyPrefix(target) if err != nil { log.Crit("Failed to store activated wasm asm", "err", err) @@ -85,7 +87,7 @@ func WriteActivatedAsm(db ethdb.KeyValueWriter, target ethdb.WasmTarget, moduleH } // Retrieves the activated asm for a given moduleHash and target -func ReadActivatedAsm(db ethdb.KeyValueReader, target ethdb.WasmTarget, moduleHash common.Hash) []byte { +func ReadActivatedAsm(db ethdb.KeyValueReader, target WasmTarget, moduleHash common.Hash) []byte { prefix, err := activatedAsmKeyPrefix(target) if err != nil { log.Crit("Failed to read activated wasm asm", "err", err) diff --git a/core/rawdb/database.go b/core/rawdb/database.go index ae8e57b20..9b2744c9e 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -41,11 +41,11 @@ type freezerdb struct { ancientRoot string } -func (frdb *freezerdb) WasmDataBase() (ethdb.KeyValueStore, uint32) { - return frdb, 0 +func (frdb *freezerdb) WasmDataBase() ethdb.KeyValueStore { + return frdb } -func (frdb *freezerdb) WasmTargets() []ethdb.WasmTarget { +func (frdb *freezerdb) WasmTargets() []WasmTarget { return nil } @@ -160,11 +160,11 @@ func (db *nofreezedb) AncientDatadir() (string, error) { return "", errNotSupported } -func (db *nofreezedb) WasmDataBase() (ethdb.KeyValueStore, uint32) { - return db, 0 +func (db *nofreezedb) WasmDataBase() ethdb.KeyValueStore { + return db } -func (db *nofreezedb) WasmTargets() []ethdb.WasmTarget { +func (db *nofreezedb) WasmTargets() []WasmTarget { return nil } @@ -176,17 +176,11 @@ func NewDatabase(db ethdb.KeyValueStore) ethdb.Database { type dbWithWasmEntry struct { ethdb.Database - wasmDb ethdb.KeyValueStore - wasmCacheTag uint32 - wasmTargets []ethdb.WasmTarget + wasmDb ethdb.KeyValueStore } -func (db *dbWithWasmEntry) WasmDataBase() (ethdb.KeyValueStore, uint32) { - return db.wasmDb, db.wasmCacheTag -} - -func (db *dbWithWasmEntry) WasmTargets() []ethdb.WasmTarget { - return db.wasmTargets +func (db *dbWithWasmEntry) WasmDataBase() ethdb.KeyValueStore { + return db.wasmDb } func (db *dbWithWasmEntry) Close() error { @@ -198,8 +192,8 @@ func (db *dbWithWasmEntry) Close() error { return wasmErr } -func WrapDatabaseWithWasm(db ethdb.Database, wasm ethdb.KeyValueStore, cacheTag uint32, targets []ethdb.WasmTarget) ethdb.Database { - return &dbWithWasmEntry{db, wasm, cacheTag, targets} +func WrapDatabaseWithWasm(db ethdb.Database, wasm ethdb.KeyValueStore) ethdb.Database { + return &dbWithWasmEntry{db, wasm} } // resolveChainFreezerDir is a helper function which resolves the absolute path diff --git a/core/rawdb/table.go b/core/rawdb/table.go index a404910a8..c57df0357 100644 --- a/core/rawdb/table.go +++ b/core/rawdb/table.go @@ -40,14 +40,10 @@ func (t *table) Close() error { return nil } -func (t *table) WasmDataBase() (ethdb.KeyValueStore, uint32) { +func (t *table) WasmDataBase() ethdb.KeyValueStore { return t.db.WasmDataBase() } -func (t *table) WasmTargets() []ethdb.WasmTarget { - return t.db.WasmTargets() -} - // Has retrieves if a prefixed version of a key is present in the database. func (t *table) Has(key []byte) (bool, error) { return t.db.Has(append([]byte(t.prefix), key...)) diff --git a/core/state/database.go b/core/state/database.go index f40560f03..d794527e8 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -49,10 +49,8 @@ const ( // Database wraps access to tries and contract code. type Database interface { // Arbitrum: Read activated Stylus contracts - ActivatedAsm(target ethdb.WasmTarget, moduleHash common.Hash) (asm []byte, err error) + ActivatedAsm(target rawdb.WasmTarget, moduleHash common.Hash) (asm []byte, err error) WasmStore() ethdb.KeyValueStore - WasmCacheTag() uint32 - WasmTargets() []ethdb.WasmTarget // Reader returns a state reader associated with the specified state root. Reader(root common.Hash) (Reader, error) @@ -155,7 +153,7 @@ type Trie interface { type activatedAsmCacheKey struct { moduleHash common.Hash - target ethdb.WasmTarget + target rawdb.WasmTarget } // CachingDB is an implementation of Database interface. It leverages both trie and @@ -163,9 +161,7 @@ type activatedAsmCacheKey struct { // long-live object and has a few caches inside for sharing between blocks. type CachingDB struct { // Arbitrum - activatedAsmCache *lru.SizeConstrainedCache[activatedAsmCacheKey, []byte] - wasmTag uint32 - wasmDatabaseRetriever ethdb.WasmDataBaseRetriever + activatedAsmCache *lru.SizeConstrainedCache[activatedAsmCacheKey, []byte] disk ethdb.KeyValueStore wasmdb ethdb.KeyValueStore @@ -178,12 +174,10 @@ type CachingDB struct { // NewDatabase creates a state database with the provided data sources. func NewDatabase(triedb *triedb.Database, snap *snapshot.Tree) *CachingDB { - wasmdb, wasmTag := triedb.Disk().WasmDataBase() + wasmdb := triedb.Disk().WasmDataBase() return &CachingDB{ // Arbitrum only - activatedAsmCache: lru.NewSizeConstrainedCache[activatedAsmCacheKey, []byte](activatedWasmCacheSize), - wasmTag: wasmTag, - wasmDatabaseRetriever: triedb.Disk(), + activatedAsmCache: lru.NewSizeConstrainedCache[activatedAsmCacheKey, []byte](activatedWasmCacheSize), disk: triedb.Disk(), wasmdb: wasmdb, @@ -312,14 +306,6 @@ func (db *CachingDB) WasmStore() ethdb.KeyValueStore { return db.wasmdb } -func (db *CachingDB) WasmCacheTag() uint32 { - return db.wasmTag -} - -func (db *CachingDB) WasmTargets() []ethdb.WasmTarget { - return db.wasmDatabaseRetriever.WasmTargets() -} - func (db *CachingDB) DiskDB() ethdb.KeyValueStore { return db.disk } diff --git a/core/state/database_arbitrum.go b/core/state/database_arbitrum.go index d975f50c4..30699a0cc 100644 --- a/core/state/database_arbitrum.go +++ b/core/state/database_arbitrum.go @@ -5,10 +5,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/ethdb" ) -func (db *CachingDB) ActivatedAsm(target ethdb.WasmTarget, moduleHash common.Hash) ([]byte, error) { +func (db *CachingDB) ActivatedAsm(target rawdb.WasmTarget, moduleHash common.Hash) ([]byte, error) { cacheKey := activatedAsmCacheKey{moduleHash, target} if asm, _ := db.activatedAsmCache.Get(cacheKey); len(asm) > 0 { return asm, nil diff --git a/core/state/statedb_arbitrum.go b/core/state/statedb_arbitrum.go index 591438fbb..1db394514 100644 --- a/core/state/statedb_arbitrum.go +++ b/core/state/statedb_arbitrum.go @@ -27,8 +27,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/lru" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" @@ -50,7 +50,7 @@ var ( StylusDiscriminant = []byte{stylusEOFMagic, stylusEOFMagicSuffix, stylusEOFVersion} ) -type ActivatedWasm map[ethdb.WasmTarget][]byte +type ActivatedWasm map[rawdb.WasmTarget][]byte // checks if a valid Stylus prefix is present func IsStylusProgram(b []byte) bool { @@ -74,7 +74,7 @@ func NewStylusPrefix(dictionary byte) []byte { return append(prefix, dictionary) } -func (s *StateDB) ActivateWasm(moduleHash common.Hash, asmMap map[ethdb.WasmTarget][]byte) { +func (s *StateDB) ActivateWasm(moduleHash common.Hash, asmMap map[rawdb.WasmTarget][]byte) { _, exists := s.arbExtraData.activatedWasms[moduleHash] if exists { return @@ -85,7 +85,7 @@ func (s *StateDB) ActivateWasm(moduleHash common.Hash, asmMap map[ethdb.WasmTarg }) } -func (s *StateDB) TryGetActivatedAsm(target ethdb.WasmTarget, moduleHash common.Hash) ([]byte, error) { +func (s *StateDB) TryGetActivatedAsm(target rawdb.WasmTarget, moduleHash common.Hash) ([]byte, error) { asmMap, exists := s.arbExtraData.activatedWasms[moduleHash] if exists { if asm, exists := asmMap[target]; exists { @@ -95,7 +95,7 @@ func (s *StateDB) TryGetActivatedAsm(target ethdb.WasmTarget, moduleHash common. return s.db.ActivatedAsm(target, moduleHash) } -func (s *StateDB) TryGetActivatedAsmMap(targets []ethdb.WasmTarget, moduleHash common.Hash) (map[ethdb.WasmTarget][]byte, error) { +func (s *StateDB) TryGetActivatedAsmMap(targets []rawdb.WasmTarget, moduleHash common.Hash) (map[rawdb.WasmTarget][]byte, error) { asmMap := s.arbExtraData.activatedWasms[moduleHash] if asmMap != nil { for _, target := range targets { @@ -106,7 +106,7 @@ func (s *StateDB) TryGetActivatedAsmMap(targets []ethdb.WasmTarget, moduleHash c return asmMap, nil } var err error - asmMap = make(map[ethdb.WasmTarget][]byte, len(targets)) + asmMap = make(map[rawdb.WasmTarget][]byte, len(targets)) for _, target := range targets { asm, dbErr := s.db.ActivatedAsm(target, moduleHash) if dbErr == nil { @@ -267,7 +267,7 @@ func (s *StateDB) StartRecording() { s.arbExtraData.userWasms = make(UserWasms) } -func (s *StateDB) RecordProgram(targets []ethdb.WasmTarget, moduleHash common.Hash) { +func (s *StateDB) RecordProgram(targets []rawdb.WasmTarget, moduleHash common.Hash) { if len(targets) == 0 { // nothing to record return diff --git a/core/state/statedb_hooked.go b/core/state/statedb_hooked.go index 83eede039..4a472d123 100644 --- a/core/state/statedb_hooked.go +++ b/core/state/statedb_hooked.go @@ -20,11 +20,11 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/stateless" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie/utils" "github.com/holiman/uint256" @@ -278,7 +278,7 @@ func (s *hookedStateDB) Finalise(deleteEmptyObjects bool) { } } -func (s *hookedStateDB) ActivateWasm(moduleHash common.Hash, asmMap map[ethdb.WasmTarget][]byte) { +func (s *hookedStateDB) ActivateWasm(moduleHash common.Hash, asmMap map[rawdb.WasmTarget][]byte) { s.inner.ActivateWasm(moduleHash, asmMap) } @@ -290,11 +290,11 @@ func (s *hookedStateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { return s.inner.IntermediateRoot(deleteEmptyObjects) } -func (s *hookedStateDB) TryGetActivatedAsm(target ethdb.WasmTarget, moduleHash common.Hash) (asm []byte, err error) { +func (s *hookedStateDB) TryGetActivatedAsm(target rawdb.WasmTarget, moduleHash common.Hash) (asm []byte, err error) { return s.inner.TryGetActivatedAsm(target, moduleHash) } -func (s *hookedStateDB) TryGetActivatedAsmMap(targets []ethdb.WasmTarget, moduleHash common.Hash) (asmMap map[ethdb.WasmTarget][]byte, err error) { +func (s *hookedStateDB) TryGetActivatedAsmMap(targets []rawdb.WasmTarget, moduleHash common.Hash) (asmMap map[rawdb.WasmTarget][]byte, err error) { return s.inner.TryGetActivatedAsmMap(targets, moduleHash) } diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index 9fba47fc2..fa3d950c1 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -54,13 +54,14 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c ) // Iterate over and process the individual transactions byzantium := p.config.IsByzantium(block.Number()) + runCtx := NewMessageEthcallContext() for i, tx := range block.Transactions() { // If block precaching was interrupted, abort if interrupt != nil && interrupt.Load() { return } // Convert the transaction into an executable message and pre-cache its sender - msg, err := TransactionToMessage(tx, signer, header.BaseFee, MessageEthcallMode) + msg, err := TransactionToMessage(tx, signer, header.BaseFee, runCtx) if err != nil { return // Also invalid block, bail out } diff --git a/core/state_processor.go b/core/state_processor.go index 9f1a7d472..4d1b3e226 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -22,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/misc" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" @@ -89,9 +90,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg ProcessParentBlockHash(block.ParentHash(), evm) } + runCtx := NewMessageReplayContext([]rawdb.WasmTarget{rawdb.LocalTarget()}) // Iterate over and process the individual transactions for i, tx := range block.Transactions() { - msg, err := TransactionToMessage(tx, signer, header.BaseFee, MessageReplayMode) + msg, err := TransactionToMessage(tx, signer, header.BaseFee, runCtx) if err != nil { return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } @@ -211,11 +213,11 @@ func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, b // for the transaction, gas used and an error if the transaction failed, // indicating the block was invalid. func ApplyTransaction(evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64) (*types.Receipt, *ExecutionResult, error) { - return ApplyTransactionWithResultFilter(evm, gp, statedb, header, tx, usedGas, MessageReplayMode, nil) + return ApplyTransactionWithResultFilter(evm, gp, statedb, header, tx, usedGas, NewMessageReplayContext([]rawdb.WasmTarget{rawdb.LocalTarget()}), nil) } -func ApplyTransactionWithResultFilter(evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, runMode MessageRunMode, resultFilter func(*ExecutionResult) error) (*types.Receipt, *ExecutionResult, error) { - msg, err := TransactionToMessage(tx, types.MakeSigner(evm.ChainConfig(), header.Number, header.Time, evm.Context.ArbOSVersion), header.BaseFee, runMode) +func ApplyTransactionWithResultFilter(evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, runCtx *MessageRunContext, resultFilter func(*ExecutionResult) error) (*types.Receipt, *ExecutionResult, error) { + msg, err := TransactionToMessage(tx, types.MakeSigner(evm.ChainConfig(), header.Number, header.Time, evm.Context.ArbOSVersion), header.BaseFee, runCtx) if err != nil { return nil, nil, err } diff --git a/core/state_transition.go b/core/state_transition.go index ab54b6e2e..a8b899cd4 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -23,6 +23,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -149,8 +150,8 @@ func toWordSize(size uint64) uint64 { // processing. type Message struct { // Arbitrum-specific - TxRunMode MessageRunMode - Tx *types.Transaction + TxRunContext *MessageRunContext + Tx *types.Transaction To *common.Address From common.Address @@ -178,24 +179,112 @@ type Message struct { SkipL1Charging bool } -type MessageRunMode uint8 +type messageRunMode uint8 const ( - MessageCommitMode MessageRunMode = iota - MessageGasEstimationMode - MessageEthcallMode - MessageReplayMode + messageCommitMode messageRunMode = iota + messageGasEstimationMode + messageEthcallMode + messageReplayMode ) +type MessageRunContext struct { + runMode messageRunMode + + wasmCacheTag uint32 + wasmTargets []rawdb.WasmTarget +} + +func NewMessageCommitContext(wasmTargets []rawdb.WasmTarget) *MessageRunContext { + if len(wasmTargets) == 0 { + wasmTargets = []rawdb.WasmTarget{rawdb.LocalTarget()} + } + return &MessageRunContext{ + runMode: messageCommitMode, + wasmCacheTag: 1, + wasmTargets: wasmTargets, + } +} + +func NewMessageReplayContext(wasmTargets []rawdb.WasmTarget) *MessageRunContext { + if len(wasmTargets) == 0 { + wasmTargets = []rawdb.WasmTarget{rawdb.LocalTarget()} + } + return &MessageRunContext{ + runMode: messageReplayMode, + wasmTargets: wasmTargets, + } +} + +func NewMessagePrefetchContext(wasmTargets []rawdb.WasmTarget) *MessageRunContext { + if len(wasmTargets) == 0 { + wasmTargets = []rawdb.WasmTarget{rawdb.LocalTarget()} + } + return NewMessageReplayContext(wasmTargets) +} + +func NewMessageEthcallContext() *MessageRunContext { + return &MessageRunContext{ + runMode: messageEthcallMode, + wasmTargets: []rawdb.WasmTarget{rawdb.LocalTarget()}, + } +} + +func NewMessageGasEstimationContext() *MessageRunContext { + return &MessageRunContext{ + runMode: messageGasEstimationMode, + wasmTargets: []rawdb.WasmTarget{rawdb.LocalTarget()}, + } +} + +func (c *MessageRunContext) IsCommitMode() bool { + return c.runMode == messageCommitMode +} + // these message modes are executed onchain so cannot make any gas shortcuts -func (m MessageRunMode) ExecutedOnChain() bool { - return m == MessageCommitMode || m == MessageReplayMode +func (c *MessageRunContext) IsExecutedOnChain() bool { + return c.runMode == messageCommitMode || c.runMode == messageReplayMode +} + +func (c *MessageRunContext) IsGasEstimation() bool { + return c.runMode == messageGasEstimationMode +} + +func (c *MessageRunContext) IsNonMutating() bool { + return c.runMode == messageGasEstimationMode || c.runMode == messageEthcallMode +} + +func (c *MessageRunContext) IsEthcall() bool { + return c.runMode == messageEthcallMode +} + +func (c *MessageRunContext) WasmCacheTag() uint32 { + return c.wasmCacheTag +} + +func (c *MessageRunContext) WasmTargets() []rawdb.WasmTarget { + return c.wasmTargets +} + +func (c *MessageRunContext) RunModeMetricName() string { + switch c.runMode { + case messageCommitMode: + return "commit_runmode" + case messageGasEstimationMode: + return "gas_estimation_runmode" + case messageEthcallMode: + return "eth_call_runmode" + case messageReplayMode: + return "replay_runmode" + default: + return "unknown_runmode" + } } // TransactionToMessage converts a transaction into a Message. -func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.Int, runmode MessageRunMode) (*Message, error) { +func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.Int, runCtx *MessageRunContext) (*Message, error) { msg := &Message{ - TxRunMode: runmode, + TxRunContext: runCtx, Tx: tx, diff --git a/core/vm/interface.go b/core/vm/interface.go index 173ccb146..eb48307ba 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -20,11 +20,11 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/stateless" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie/utils" "github.com/holiman/uint256" @@ -33,9 +33,9 @@ import ( // StateDB is an EVM database for full state querying. type StateDB interface { // Arbitrum: manage Stylus wasms - ActivateWasm(moduleHash common.Hash, asmMap map[ethdb.WasmTarget][]byte) - TryGetActivatedAsm(target ethdb.WasmTarget, moduleHash common.Hash) (asm []byte, err error) - TryGetActivatedAsmMap(targets []ethdb.WasmTarget, moduleHash common.Hash) (asmMap map[ethdb.WasmTarget][]byte, err error) + ActivateWasm(moduleHash common.Hash, asmMap map[rawdb.WasmTarget][]byte) + TryGetActivatedAsm(target rawdb.WasmTarget, moduleHash common.Hash) (asm []byte, err error) + TryGetActivatedAsmMap(targets []rawdb.WasmTarget, moduleHash common.Hash) (asmMap map[rawdb.WasmTarget][]byte, err error) RecordCacheWasm(wasm state.CacheWasm) RecordEvictWasm(wasm state.EvictWasm) GetRecentWasms() state.RecentWasms diff --git a/eth/gasestimator/gasestimator.go b/eth/gasestimator/gasestimator.go index 40f3af0f4..c1d232e83 100644 --- a/eth/gasestimator/gasestimator.go +++ b/eth/gasestimator/gasestimator.go @@ -49,7 +49,7 @@ type Options struct { State *state.StateDB // Pre-state on top of which to estimate the gas BlockOverrides *override.BlockOverrides // Block overrides to apply during the estimation Backend core.NodeInterfaceBackendAPI - RunScheduledTxes func(context.Context, core.NodeInterfaceBackendAPI, *state.StateDB, *types.Header, vm.BlockContext, core.MessageRunMode, *core.ExecutionResult) (*core.ExecutionResult, error) + RunScheduledTxes func(context.Context, core.NodeInterfaceBackendAPI, *state.StateDB, *types.Header, vm.BlockContext, *core.MessageRunContext, *core.ExecutionResult) (*core.ExecutionResult, error) ErrorRatio float64 // Allowed overestimation ratio for faster estimation termination } @@ -268,7 +268,7 @@ func run(ctx context.Context, call *core.Message, opts *Options) (*core.Executio } // Arbitrum: a tx can schedule another (see retryables) - result, err = opts.RunScheduledTxes(ctx, opts.Backend, dirtyState, opts.Header, evmContext, core.MessageGasEstimationMode, result) + result, err = opts.RunScheduledTxes(ctx, opts.Backend, dirtyState, opts.Header, evmContext, core.NewMessageGasEstimationContext(), result) if err != nil { return nil, err } diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 7d1e3a6e8..68fbf658d 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -269,12 +269,13 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, } // Recompute transactions up to the target index. signer := types.MakeSigner(eth.blockchain.Config(), block.Number(), block.Time(), evm.Context.ArbOSVersion) + runCtx := core.NewMessageReplayContext([]rawdb.WasmTarget{rawdb.LocalTarget()}) for idx, tx := range block.Transactions() { if idx == txIndex { return tx, context, statedb, release, nil } // Assemble the transaction call message and return if the requested offset - msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee(), core.MessageReplayMode) + msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee(), runCtx) // Not yet the searched for transaction, execute on top of the current state statedb.SetTxContext(tx.Hash(), idx) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 65b3326ac..0447e55fa 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -263,6 +263,9 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed resCh = make(chan *blockTraceTask, threads) tracker = newStateTracker(maximumPendingTraceStates, start.NumberU64()) ) + + runCtx := core.NewMessageReplayContext([]rawdb.WasmTarget{rawdb.LocalTarget()}) + for th := 0; th < threads; th++ { pend.Add(1) go func() { @@ -276,7 +279,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed ) // Trace all the transactions contained within for i, tx := range task.block.Transactions() { - msg, _ := core.TransactionToMessage(tx, signer, task.block.BaseFee(), core.MessageReplayMode) + msg, _ := core.TransactionToMessage(tx, signer, task.block.BaseFee(), runCtx) txctx := &Context{ BlockHash: task.block.Hash(), BlockNumber: task.block.Number(), @@ -547,11 +550,12 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config if chainConfig.IsPrague(block.Number(), block.Time(), vmctx.ArbOSVersion) { core.ProcessParentBlockHash(block.ParentHash(), evm) } + runCtx := core.NewMessageReplayContext([]rawdb.WasmTarget{rawdb.LocalTarget()}) for i, tx := range block.Transactions() { if err := ctx.Err(); err != nil { return nil, err } - msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee(), core.MessageReplayMode) + msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee(), runCtx) statedb.SetTxContext(tx.Hash(), i) if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil { log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err) @@ -628,9 +632,10 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time(), arbosVersion) results = make([]*txTraceResult, len(txs)) ) + runCtx := core.NewMessageReplayContext([]rawdb.WasmTarget{rawdb.LocalTarget()}) for i, tx := range txs { // Generate the next state snapshot fast without tracing - msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee(), core.MessageReplayMode) + msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee(), runCtx) txctx := &Context{ BlockHash: blockHash, BlockNumber: block.Number(), @@ -659,6 +664,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat results = make([]*txTraceResult, len(txs)) pend sync.WaitGroup ) + runCtx := core.NewMessageReplayContext([]rawdb.WasmTarget{rawdb.LocalTarget()}) threads := runtime.NumCPU() if threads > len(txs) { threads = len(txs) @@ -670,7 +676,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat defer pend.Done() // Fetch and execute the next transaction trace tasks for task := range jobs { - msg, _ := core.TransactionToMessage(txs[task.index], signer, block.BaseFee(), core.MessageReplayMode) + msg, _ := core.TransactionToMessage(txs[task.index], signer, block.BaseFee(), runCtx) txctx := &Context{ BlockHash: blockHash, BlockNumber: block.Number(), @@ -709,7 +715,7 @@ txloop: } // Generate the next state snapshot fast without tracing - msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee(), core.MessageReplayMode) + msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee(), runCtx) statedb.SetTxContext(tx.Hash(), i) if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil { failed = err @@ -790,10 +796,12 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block if chainConfig.IsPrague(block.Number(), block.Time(), vmctx.ArbOSVersion) { core.ProcessParentBlockHash(block.ParentHash(), evm) } + + runCtx := core.NewMessageReplayContext([]rawdb.WasmTarget{rawdb.LocalTarget()}) for i, tx := range block.Transactions() { // Prepare the transaction for un-traced execution var ( - msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee(), core.MessageReplayMode) + msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee(), runCtx) vmConf vm.Config dump *os.File writer *bufio.Writer @@ -889,7 +897,7 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config * return nil, err } defer release() - msg, err := core.TransactionToMessage(tx, types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time(), vmctx.ArbOSVersion), block.BaseFee(), core.MessageReplayMode) + msg, err := core.TransactionToMessage(tx, types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time(), vmctx.ArbOSVersion), block.BaseFee(), core.NewMessageReplayContext([]rawdb.WasmTarget{rawdb.LocalTarget()})) if err != nil { return nil, err } @@ -968,7 +976,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc return nil, err } var ( - msg = args.ToMessage(vmctx.BaseFee, api.backend.RPCGasCap(), block.Header(), statedb, core.MessageEthcallMode, true, true) + msg = args.ToMessage(vmctx.BaseFee, api.backend.RPCGasCap(), block.Header(), statedb, core.NewMessageEthcallContext(), true, true) tx = args.ToTransaction(types.LegacyTxType) traceConfig *TraceConfig ) diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index f0df72e9d..5d68f7bd2 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -179,11 +179,12 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block context := core.NewEVMBlockContext(block.Header(), b.chain, nil) signer := types.MakeSigner(b.chainConfig, block.Number(), block.Time(), context.ArbOSVersion) evm := vm.NewEVM(context, statedb, b.chainConfig, vm.Config{}) + runCtx := core.NewMessageReplayContext([]rawdb.WasmTarget{rawdb.LocalTarget()}) for idx, tx := range block.Transactions() { if idx == txIndex { return tx, context, statedb, release, nil } - msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee(), core.MessageReplayMode) + msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee(), runCtx) if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) } diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index c61b3ce20..5eaf06ff8 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -136,7 +136,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { if tracer.Hooks != nil { logState = state.NewHookedState(st.StateDB, tracer.Hooks) } - msg, err := core.TransactionToMessage(tx, signer, context.BaseFee, core.MessageReplayMode) + msg, err := core.TransactionToMessage(tx, signer, context.BaseFee, core.NewMessageReplayContext([]rawdb.WasmTarget{rawdb.LocalTarget()})) if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } @@ -214,7 +214,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { } context := test.Context.toBlockContext(test.Genesis) signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time), context.ArbOSVersion) - msg, err := core.TransactionToMessage(tx, signer, context.BaseFee, core.MessageReplayMode) + msg, err := core.TransactionToMessage(tx, signer, context.BaseFee, core.NewMessageReplayContext([]rawdb.WasmTarget{rawdb.LocalTarget()})) if err != nil { b.Fatalf("failed to prepare transaction for tracing: %v", err) } @@ -381,7 +381,7 @@ func TestInternals(t *testing.T) { t.Fatalf("test %v: failed to sign transaction: %v", tc.name, err) } evm := vm.NewEVM(context, logState, config, vm.Config{Tracer: tc.tracer.Hooks}) - msg, err := core.TransactionToMessage(tx, signer, big.NewInt(0), core.MessageReplayMode) + msg, err := core.TransactionToMessage(tx, signer, big.NewInt(0), core.NewMessageReplayContext([]rawdb.WasmTarget{rawdb.LocalTarget()})) if err != nil { t.Fatalf("test %v: failed to create message: %v", tc.name, err) } diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index 84a005f7e..299d403d3 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -107,7 +107,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string return fmt.Errorf("failed to create call tracer: %v", err) } - msg, err := core.TransactionToMessage(tx, signer, context.BaseFee, core.MessageReplayMode) + msg, err := core.TransactionToMessage(tx, signer, context.BaseFee, core.NewMessageReplayContext([]rawdb.WasmTarget{rawdb.LocalTarget()})) if err != nil { return fmt.Errorf("failed to prepare transaction for tracing: %v", err) } diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index eac1f25cb..98d153523 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -99,7 +99,7 @@ func testPrestateTracer(tracerName string, dirPath string, t *testing.T) { t.Fatalf("failed to create call tracer: %v", err) } - msg, err := core.TransactionToMessage(tx, signer, context.BaseFee, core.MessageReplayMode) + msg, err := core.TransactionToMessage(tx, signer, context.BaseFee, core.NewMessageReplayContext([]rawdb.WasmTarget{rawdb.LocalTarget()})) if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index eabde139a..c0c5762a4 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -79,7 +79,7 @@ func BenchmarkTransactionTraceV2(b *testing.B) { defer state.Close() evm := vm.NewEVM(context, state.StateDB, params.AllEthashProtocolChanges, vm.Config{}) - msg, err := core.TransactionToMessage(tx, signer, context.BaseFee, core.MessageReplayMode) + msg, err := core.TransactionToMessage(tx, signer, context.BaseFee, core.NewMessageReplayContext([]rawdb.WasmTarget{rawdb.LocalTarget()})) if err != nil { b.Fatalf("failed to prepare transaction for tracing: %v", err) } diff --git a/ethdb/database.go b/ethdb/database.go index f8ebdcaa6..362c644bb 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -171,10 +171,8 @@ type AncientStore interface { io.Closer } -type WasmTarget string type WasmDataBaseRetriever interface { - WasmDataBase() (KeyValueStore, uint32) - WasmTargets() []WasmTarget + WasmDataBase() KeyValueStore } // ResettableAncientStore extends the AncientStore interface by adding a Reset method. diff --git a/ethdb/remotedb/remotedb.go b/ethdb/remotedb/remotedb.go index 581398e91..e169340b1 100644 --- a/ethdb/remotedb/remotedb.go +++ b/ethdb/remotedb/remotedb.go @@ -39,12 +39,8 @@ func (db *Database) Has(key []byte) (bool, error) { return true, nil } -func (db *Database) WasmDataBase() (ethdb.KeyValueStore, uint32) { - return db, 0 -} - -func (db *Database) WasmTargets() []ethdb.WasmTarget { - return nil +func (db *Database) WasmDataBase() ethdb.KeyValueStore { + return db } func (db *Database) Get(key []byte) ([]byte, error) { diff --git a/graphql/graphql.go b/graphql/graphql.go index 2d7a323c3..cf0b82358 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -1193,7 +1193,7 @@ func (c *CallResult) Status() hexutil.Uint64 { func (b *Block) Call(ctx context.Context, args struct { Data ethapi.TransactionArgs }) (*CallResult, error) { - result, err := ethapi.DoCall(ctx, b.r.backend, args.Data, *b.numberOrHash, nil, nil, b.r.backend.RPCEVMTimeout(), b.r.backend.RPCGasCap(), core.MessageEthcallMode) + result, err := ethapi.DoCall(ctx, b.r.backend, args.Data, *b.numberOrHash, nil, nil, b.r.backend.RPCEVMTimeout(), b.r.backend.RPCGasCap(), core.NewMessageEthcallContext()) if err != nil { return nil, err } @@ -1256,7 +1256,7 @@ func (p *Pending) Call(ctx context.Context, args struct { Data ethapi.TransactionArgs }) (*CallResult, error) { pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber) - result, err := ethapi.DoCall(ctx, p.r.backend, args.Data, pendingBlockNr, nil, nil, p.r.backend.RPCEVMTimeout(), p.r.backend.RPCGasCap(), core.MessageEthcallMode) + result, err := ethapi.DoCall(ctx, p.r.backend, args.Data, pendingBlockNr, nil, nil, p.r.backend.RPCEVMTimeout(), p.r.backend.RPCGasCap(), core.NewMessageEthcallContext()) if err != nil { return nil, err } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index bd49b51a2..71c7825f4 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -677,7 +677,7 @@ func (context *ChainContext) Config() *params.ChainConfig { return context.b.ChainConfig() } -func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, overrides *override.StateOverride, blockOverrides *override.BlockOverrides, timeout time.Duration, globalGasCap uint64, runMode core.MessageRunMode) (*core.ExecutionResult, error) { +func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, overrides *override.StateOverride, blockOverrides *override.BlockOverrides, timeout time.Duration, globalGasCap uint64, runCtx *core.MessageRunContext) (*core.ExecutionResult, error) { blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil) if blockOverrides != nil { blockOverrides.Apply(&blockCtx) @@ -705,15 +705,15 @@ func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.S } else { gp.AddGas(globalGasCap) } - return applyMessage(ctx, b, args, state, header, timeout, gp, &blockCtx, &vm.Config{NoBaseFee: true}, precompiles, true, runMode) + return applyMessage(ctx, b, args, state, header, timeout, gp, &blockCtx, &vm.Config{NoBaseFee: true}, precompiles, true, runCtx) } -func applyMessage(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, timeout time.Duration, gp *core.GasPool, blockContext *vm.BlockContext, vmConfig *vm.Config, precompiles vm.PrecompiledContracts, skipChecks bool, runMode core.MessageRunMode) (*core.ExecutionResult, error) { +func applyMessage(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, timeout time.Duration, gp *core.GasPool, blockContext *vm.BlockContext, vmConfig *vm.Config, precompiles vm.PrecompiledContracts, skipChecks bool, runCtx *core.MessageRunContext) (*core.ExecutionResult, error) { // Get a new instance of the EVM. if err := args.CallDefaults(gp.Gas(), blockContext.BaseFee, b.ChainConfig().ChainID); err != nil { return nil, err } - msg := args.ToMessage(blockContext.BaseFee, gp.Gas(), header, state, runMode, skipChecks, skipChecks) + msg := args.ToMessage(blockContext.BaseFee, gp.Gas(), header, state, runCtx, skipChecks, skipChecks) // Arbitrum: raise the gas cap to ignore L1 costs so that it's compute-only if gp.Gas() > 0 { @@ -775,7 +775,7 @@ func applyMessageWithEVM(ctx context.Context, evm *vm.EVM, msg *core.Message, st } // Arbitrum: a tx can schedule another (see retryables) - result, err = runScheduledTxes(ctx, b, state, header, blockContext, core.MessageGasEstimationMode, result) + result, err = runScheduledTxes(ctx, b, state, header, blockContext, msg.TxRunContext, result) if err != nil { return nil, err } @@ -783,11 +783,11 @@ func applyMessageWithEVM(ctx context.Context, evm *vm.EVM, msg *core.Message, st return result, nil } -func runScheduledTxes(ctx context.Context, b core.NodeInterfaceBackendAPI, state *state.StateDB, header *types.Header, blockCtx vm.BlockContext, runMode core.MessageRunMode, result *core.ExecutionResult) (*core.ExecutionResult, error) { +func runScheduledTxes(ctx context.Context, b core.NodeInterfaceBackendAPI, state *state.StateDB, header *types.Header, blockCtx vm.BlockContext, runCtx *core.MessageRunContext, result *core.ExecutionResult) (*core.ExecutionResult, error) { scheduled := result.ScheduledTxes - for runMode == core.MessageGasEstimationMode && len(scheduled) > 0 { + for runCtx.IsGasEstimation() && len(scheduled) > 0 { // This will panic if the scheduled tx is signed, but we only schedule unsigned ones - msg, err := core.TransactionToMessage(scheduled[0], types.NewArbitrumSigner(nil), header.BaseFee, runMode) + msg, err := core.TransactionToMessage(scheduled[0], types.NewArbitrumSigner(nil), header.BaseFee, runCtx) if err != nil { return nil, err } @@ -838,7 +838,7 @@ func updateHeaderForPendingBlocks(blockNrOrHash rpc.BlockNumberOrHash, header *t return header } -func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *override.StateOverride, blockOverrides *override.BlockOverrides, timeout time.Duration, globalGasCap uint64, runMode core.MessageRunMode) (*core.ExecutionResult, error) { +func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *override.StateOverride, blockOverrides *override.BlockOverrides, timeout time.Duration, globalGasCap uint64, runCtx *core.MessageRunContext) (*core.ExecutionResult, error) { defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now()) state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) @@ -846,7 +846,7 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash return nil, err } header = updateHeaderForPendingBlocks(blockNrOrHash, header) - return doCall(ctx, b, args, state, header, overrides, blockOverrides, timeout, globalGasCap, runMode) + return doCall(ctx, b, args, state, header, overrides, blockOverrides, timeout, globalGasCap, runCtx) } // Call executes the given transaction on the state for the given block number. @@ -860,7 +860,7 @@ func (api *BlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockN latest := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) blockNrOrHash = &latest } - result, err := DoCall(ctx, api.b, args, *blockNrOrHash, overrides, blockOverrides, api.b.RPCEVMTimeout(), api.b.RPCGasCap(), core.MessageEthcallMode) + result, err := DoCall(ctx, api.b, args, *blockNrOrHash, overrides, blockOverrides, api.b.RPCEVMTimeout(), api.b.RPCGasCap(), core.NewMessageEthcallContext()) if err != nil { if client := fallbackClientFor(api.b, err); client != nil { var res hexutil.Bytes @@ -952,7 +952,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr } // Run the gas estimation and wrap any revertals into a custom return // Arbitrum: this also appropriately recursively calls another args.ToMessage with increased gasCap by posterCostInL2Gas amount - call := args.ToMessage(header.BaseFee, gasCap, header, state, core.MessageGasEstimationMode, true, true) + call := args.ToMessage(header.BaseFee, gasCap, header, state, core.NewMessageGasEstimationContext(), true, true) // Arbitrum: raise the gas cap to ignore L1 costs so that it's compute-only if gasCap > 0 { @@ -1402,6 +1402,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH if args.AccessList != nil { prevTracer = logger.NewAccessListTracer(*args.AccessList, args.from(), to, precompiles) } + runCtx := core.NewMessageEthcallContext() for { if err := ctx.Err(); err != nil { return nil, 0, nil, err @@ -1414,7 +1415,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH statedb := db.Copy() // Set the accesslist to the last al args.AccessList = &accessList - msg := args.ToMessage(header.BaseFee, b.RPCGasCap(), header, statedb, core.MessageEthcallMode, true, true) + msg := args.ToMessage(header.BaseFee, b.RPCGasCap(), header, statedb, runCtx, true, true) // Apply the transaction with the access list tracer tracer := logger.NewAccessListTracer(accessList, args.from(), to, precompiles) diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 621effce0..188f1e094 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -223,7 +223,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, txes[i] = tx tracer.reset(tx.Hash(), uint(i)) // EoA check is always skipped, even in validation mode. - msg := call.ToMessage(header.BaseFee, 0, nil, nil, 0, !sim.validate, true) + msg := call.ToMessage(header.BaseFee, 0, nil, nil, core.NewMessageCommitContext(nil), !sim.validate, true) result, err := applyMessageWithEVM(ctx, evm, msg, sim.state, timeout, sim.gp, sim.b, header, blockContext) if err != nil { txErr := txValidationError(err) diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index 53d02463f..7ee52050e 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -430,7 +430,7 @@ func (args *TransactionArgs) CallDefaults(globalGasCap uint64, baseFee *big.Int, } // Assumes that fields are not nil, i.e. setDefaults or CallDefaults has been called. -func (args *TransactionArgs) ToMessage(baseFee *big.Int, globalGasCap uint64, header *types.Header, state *state.StateDB, runMode core.MessageRunMode, skipNonceCheck, skipEoACheck bool) *core.Message { +func (args *TransactionArgs) ToMessage(baseFee *big.Int, globalGasCap uint64, header *types.Header, state *state.StateDB, runCtx *core.MessageRunContext, skipNonceCheck, skipEoACheck bool) *core.Message { var ( gasPrice *big.Int gasFeeCap *big.Int @@ -483,7 +483,7 @@ func (args *TransactionArgs) ToMessage(baseFee *big.Int, globalGasCap uint64, he BlobGasFeeCap: (*big.Int)(args.BlobFeeCap), BlobHashes: args.BlobHashes, SetCodeAuthorizations: args.AuthorizationList, - TxRunMode: runMode, + TxRunContext: runCtx, SkipNonceChecks: skipNonceCheck, SkipFromEOACheck: skipEoACheck, SkipL1Charging: skipL1Charging,