diff --git a/arbitrum/apibackend.go b/arbitrum/apibackend.go index 3e90a3738c..99890e46a0 100644 --- a/arbitrum/apibackend.go +++ b/arbitrum/apibackend.go @@ -105,8 +105,8 @@ func createRegisterAPIBackend(backend *Backend, filterConfig filters.Config, fal // discard stylus-tag on any call made from api database dbForAPICalls := backend.chainDb wasmStore, tag := backend.chainDb.WasmDataBase() - if tag != 0 { - dbForAPICalls = rawdb.WrapDatabaseWithWasm(backend.chainDb, wasmStore, 0) + if tag != 0 || len(backend.chainDb.WasmTargets()) > 1 { + dbForAPICalls = rawdb.WrapDatabaseWithWasm(backend.chainDb, wasmStore, 0, []ethdb.WasmTarget{rawdb.LocalTarget()}) } backend.apiBackend = &APIBackend{ b: backend, diff --git a/arbitrum/recordingdb.go b/arbitrum/recordingdb.go index aa405c5c02..b2350f9c4e 100644 --- a/arbitrum/recordingdb.go +++ b/arbitrum/recordingdb.go @@ -269,7 +269,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(rawdb.WrapDatabaseWithWasm(rawdb.NewDatabase(recordingKeyValue), r.db.WasmStore(), 0)) + recordingStateDatabase := state.NewDatabase(rawdb.WrapDatabaseWithWasm(rawdb.NewDatabase(recordingKeyValue), r.db.WasmStore(), 0, r.db.WasmTargets())) var prevRoot common.Hash if lastBlockHeader != nil { prevRoot = lastBlockHeader.Root diff --git a/core/rawdb/accessors_state_arbitrum.go b/core/rawdb/accessors_state_arbitrum.go index 455ba6f4f6..b6b282d67f 100644 --- a/core/rawdb/accessors_state_arbitrum.go +++ b/core/rawdb/accessors_state_arbitrum.go @@ -25,16 +25,14 @@ import ( "github.com/ethereum/go-ethereum/log" ) -type Target string - const ( - TargetWavm Target = "wavm" - TargetArm64 Target = "arm64" - TargetAmd64 Target = "amd64" - TargetHost Target = "host" + TargetWavm ethdb.WasmTarget = "wavm" + TargetArm64 ethdb.WasmTarget = "arm64" + TargetAmd64 ethdb.WasmTarget = "amd64" + TargetHost ethdb.WasmTarget = "host" ) -func LocalTarget() Target { +func LocalTarget() ethdb.WasmTarget { if runtime.GOOS == "linux" { switch runtime.GOARCH { case "arm64": @@ -46,9 +44,9 @@ func LocalTarget() Target { return TargetHost } -func (t Target) keyPrefix() (WasmPrefix, error) { +func activatedAsmKeyPrefix(target ethdb.WasmTarget) (WasmPrefix, error) { var prefix WasmPrefix - switch t { + switch target { case TargetWavm: prefix = activatedAsmWavmPrefix case TargetArm64: @@ -58,27 +56,25 @@ func (t Target) keyPrefix() (WasmPrefix, error) { case TargetHost: prefix = activatedAsmHostPrefix default: - return WasmPrefix{}, fmt.Errorf("invalid target: %v", t) + return WasmPrefix{}, fmt.Errorf("invalid target: %v", target) } return prefix, nil } -func (t Target) IsValid() bool { - _, err := t.keyPrefix() +func IsSupportedWasmTarget(target ethdb.WasmTarget) bool { + _, err := activatedAsmKeyPrefix(target) return err == nil } -var Targets = []Target{TargetWavm, TargetArm64, TargetAmd64, TargetHost} - -func WriteActivation(db ethdb.KeyValueWriter, moduleHash common.Hash, asmMap map[Target][]byte) { +func WriteActivation(db ethdb.KeyValueWriter, moduleHash common.Hash, asmMap map[ethdb.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 Target, moduleHash common.Hash, asm []byte) { - prefix, err := target.keyPrefix() +func WriteActivatedAsm(db ethdb.KeyValueWriter, target ethdb.WasmTarget, moduleHash common.Hash, asm []byte) { + prefix, err := activatedAsmKeyPrefix(target) if err != nil { log.Crit("Failed to store activated wasm asm", "err", err) } @@ -89,8 +85,8 @@ func WriteActivatedAsm(db ethdb.KeyValueWriter, target Target, moduleHash common } // Retrieves the activated asm for a given moduleHash and target -func ReadActivatedAsm(db ethdb.KeyValueReader, target Target, moduleHash common.Hash) []byte { - prefix, err := target.keyPrefix() +func ReadActivatedAsm(db ethdb.KeyValueReader, target ethdb.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 3aa099c0f8..1d039f6935 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -42,11 +42,14 @@ type freezerdb struct { ethdb.AncientStore } -// AncientDatadir returns the path of root ancient directory. func (frdb *freezerdb) WasmDataBase() (ethdb.KeyValueStore, uint32) { return frdb, 0 } +func (frdb *freezerdb) WasmTargets() []ethdb.WasmTarget { + return nil +} + // AncientDatadir returns the path of root ancient directory. func (frdb *freezerdb) AncientDatadir() (string, error) { return frdb.ancientRoot, nil @@ -170,11 +173,14 @@ func (db *nofreezedb) AncientDatadir() (string, error) { return "", errNotSupported } -// AncientDatadir returns the path of root ancient directory. func (db *nofreezedb) WasmDataBase() (ethdb.KeyValueStore, uint32) { return db, 0 } +func (db *nofreezedb) WasmTargets() []ethdb.WasmTarget { + return nil +} + // NewDatabase creates a high level database on top of a given key-value data // store without a freezer moving immutable chain segments into cold storage. func NewDatabase(db ethdb.KeyValueStore) ethdb.Database { @@ -185,12 +191,17 @@ type dbWithWasmEntry struct { ethdb.Database wasmDb ethdb.KeyValueStore wasmCacheTag uint32 + wasmTargets []ethdb.WasmTarget } func (db *dbWithWasmEntry) WasmDataBase() (ethdb.KeyValueStore, uint32) { return db.wasmDb, db.wasmCacheTag } +func (db *dbWithWasmEntry) WasmTargets() []ethdb.WasmTarget { + return db.wasmTargets +} + func (db *dbWithWasmEntry) Close() error { dbErr := db.Database.Close() wasmErr := db.wasmDb.Close() @@ -200,8 +211,8 @@ func (db *dbWithWasmEntry) Close() error { return wasmErr } -func WrapDatabaseWithWasm(db ethdb.Database, wasm ethdb.KeyValueStore, cacheTag uint32) ethdb.Database { - return &dbWithWasmEntry{db, wasm, cacheTag} +func WrapDatabaseWithWasm(db ethdb.Database, wasm ethdb.KeyValueStore, cacheTag uint32, targets []ethdb.WasmTarget) ethdb.Database { + return &dbWithWasmEntry{db, wasm, cacheTag, targets} } // resolveChainFreezerDir is a helper function which resolves the absolute path diff --git a/core/rawdb/table.go b/core/rawdb/table.go index 5f09b48203..7d21e5e5eb 100644 --- a/core/rawdb/table.go +++ b/core/rawdb/table.go @@ -44,6 +44,10 @@ func (t *table) WasmDataBase() (ethdb.KeyValueStore, uint32) { 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 b21ef47a42..4b344bd1d2 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -53,9 +53,10 @@ const ( // Database wraps access to tries and contract code. type Database interface { // Arbitrum: Read activated Stylus contracts - ActivatedAsm(target rawdb.Target, moduleHash common.Hash) (asm []byte, err error) + ActivatedAsm(target ethdb.WasmTarget, moduleHash common.Hash) (asm []byte, err error) WasmStore() ethdb.KeyValueStore WasmCacheTag() uint32 + WasmTargets() []ethdb.WasmTarget // OpenTrie opens the main account trie. OpenTrie(root common.Hash) (Trie, error) @@ -163,8 +164,9 @@ func NewDatabaseWithConfig(db ethdb.Database, config *triedb.Config) Database { wasmdb, wasmTag := db.WasmDataBase() cdb := &cachingDB{ // Arbitrum only - activatedAsmCache: lru.NewSizeConstrainedCache[activatedAsmCacheKey, []byte](activatedWasmCacheSize), - wasmTag: wasmTag, + activatedAsmCache: lru.NewSizeConstrainedCache[activatedAsmCacheKey, []byte](activatedWasmCacheSize), + wasmTag: wasmTag, + wasmDatabaseRetriever: db, disk: db, wasmdb: wasmdb, @@ -180,8 +182,9 @@ func NewDatabaseWithNodeDB(db ethdb.Database, triedb *triedb.Database) Database wasmdb, wasmTag := db.WasmDataBase() cdb := &cachingDB{ // Arbitrum only - activatedAsmCache: lru.NewSizeConstrainedCache[activatedAsmCacheKey, []byte](activatedWasmCacheSize), - wasmTag: wasmTag, + activatedAsmCache: lru.NewSizeConstrainedCache[activatedAsmCacheKey, []byte](activatedWasmCacheSize), + wasmTag: wasmTag, + wasmDatabaseRetriever: db, disk: db, wasmdb: wasmdb, @@ -194,13 +197,14 @@ func NewDatabaseWithNodeDB(db ethdb.Database, triedb *triedb.Database) Database type activatedAsmCacheKey struct { moduleHash common.Hash - target rawdb.Target + target ethdb.WasmTarget } type cachingDB struct { // Arbitrum - activatedAsmCache *lru.SizeConstrainedCache[activatedAsmCacheKey, []byte] - wasmTag uint32 + activatedAsmCache *lru.SizeConstrainedCache[activatedAsmCacheKey, []byte] + wasmTag uint32 + wasmDatabaseRetriever ethdb.WasmDataBaseRetriever disk ethdb.KeyValueStore wasmdb ethdb.KeyValueStore @@ -217,6 +221,10 @@ func (db *cachingDB) WasmCacheTag() uint32 { return db.wasmTag } +func (db *cachingDB) WasmTargets() []ethdb.WasmTarget { + return db.wasmDatabaseRetriever.WasmTargets() +} + // OpenTrie opens the main account trie at a specific root hash. func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { if db.triedb.IsVerkle() { diff --git a/core/state/database_arbitrum.go b/core/state/database_arbitrum.go index b05733520b..851e54ff4e 100644 --- a/core/state/database_arbitrum.go +++ b/core/state/database_arbitrum.go @@ -5,9 +5,10 @@ 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 rawdb.Target, moduleHash common.Hash) ([]byte, error) { +func (db *cachingDB) ActivatedAsm(target ethdb.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 99e7835231..0eadd2306f 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[rawdb.Target][]byte +type ActivatedWasm map[ethdb.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[rawdb.Target][]byte) { +func (s *StateDB) ActivateWasm(moduleHash common.Hash, asmMap map[ethdb.WasmTarget][]byte) { _, exists := s.arbExtraData.activatedWasms[moduleHash] if exists { return @@ -85,7 +85,7 @@ func (s *StateDB) ActivateWasm(moduleHash common.Hash, asmMap map[rawdb.Target][ }) } -func (s *StateDB) TryGetActivatedAsm(target rawdb.Target, moduleHash common.Hash) ([]byte, error) { +func (s *StateDB) TryGetActivatedAsm(target ethdb.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 rawdb.Target, moduleHash common.Hash return s.db.ActivatedAsm(target, moduleHash) } -func (s *StateDB) TryGetActivatedAsmMap(targets []rawdb.Target, moduleHash common.Hash) (map[rawdb.Target][]byte, error) { +func (s *StateDB) TryGetActivatedAsmMap(targets []ethdb.WasmTarget, moduleHash common.Hash) (map[ethdb.WasmTarget][]byte, error) { asmMap := s.arbExtraData.activatedWasms[moduleHash] if asmMap != nil { for _, target := range targets { @@ -106,7 +106,7 @@ func (s *StateDB) TryGetActivatedAsmMap(targets []rawdb.Target, moduleHash commo return asmMap, nil } var err error - asmMap = make(map[rawdb.Target][]byte, len(targets)) + asmMap = make(map[ethdb.WasmTarget][]byte, len(targets)) for _, target := range targets { asm, dbErr := s.db.ActivatedAsm(target, moduleHash) if dbErr == nil { @@ -241,7 +241,7 @@ func (s *StateDB) StartRecording() { s.arbExtraData.userWasms = make(UserWasms) } -func (s *StateDB) RecordProgram(targets []rawdb.Target, moduleHash common.Hash) { +func (s *StateDB) RecordProgram(targets []ethdb.WasmTarget, moduleHash common.Hash) { if len(targets) == 0 { // nothing to record return diff --git a/core/vm/interface.go b/core/vm/interface.go index 70171a5ecc..baff7157b8 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -20,9 +20,9 @@ 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/types" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) @@ -30,9 +30,9 @@ import ( // StateDB is an EVM database for full state querying. type StateDB interface { // Arbitrum: manage Stylus wasms - ActivateWasm(moduleHash common.Hash, asmMap map[rawdb.Target][]byte) - TryGetActivatedAsm(target rawdb.Target, moduleHash common.Hash) (asm []byte, err error) - TryGetActivatedAsmMap(targets []rawdb.Target, moduleHash common.Hash) (asmMap map[rawdb.Target][]byte, err error) + 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) RecordCacheWasm(wasm state.CacheWasm) RecordEvictWasm(wasm state.EvictWasm) GetRecentWasms() state.RecentWasms diff --git a/ethdb/database.go b/ethdb/database.go index f8e9be0ca3..e846767243 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -178,8 +178,10 @@ type AncientStore interface { io.Closer } +type WasmTarget string type WasmDataBaseRetriever interface { WasmDataBase() (KeyValueStore, uint32) + WasmTargets() []WasmTarget } // Database contains all the methods required by the high level database to not diff --git a/ethdb/remotedb/remotedb.go b/ethdb/remotedb/remotedb.go index ef38ce786d..0168aefef8 100644 --- a/ethdb/remotedb/remotedb.go +++ b/ethdb/remotedb/remotedb.go @@ -43,6 +43,10 @@ func (t *Database) WasmDataBase() (ethdb.KeyValueStore, uint32) { return t, 0 } +func (t *Database) WasmTargets() []ethdb.WasmTarget { + return nil +} + func (db *Database) Get(key []byte) ([]byte, error) { var resp hexutil.Bytes err := db.remote.Call(&resp, "debug_dbGet", hexutil.Bytes(key))