Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate Wasmstore from normal db: initial #317

Merged
merged 13 commits into from
May 16, 2024
11 changes: 6 additions & 5 deletions arbitrum/recordingdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,13 @@ var (
type RecordingKV struct {
inner *trie.Database
diskDb ethdb.KeyValueStore
wasmDb ethdb.KeyValueStore
readDbEntries map[common.Hash][]byte
enableBypass bool
}

func newRecordingKV(inner *trie.Database, diskDb ethdb.KeyValueStore) *RecordingKV {
return &RecordingKV{inner, diskDb, make(map[common.Hash][]byte), false}
func newRecordingKV(inner *trie.Database, diskDb ethdb.KeyValueStore, wasmDb ethdb.KeyValueStore) *RecordingKV {
return &RecordingKV{inner, diskDb, wasmDb, make(map[common.Hash][]byte), false}
}

func (db *RecordingKV) Has(key []byte) (bool, error) {
Expand All @@ -57,10 +58,10 @@ func (db *RecordingKV) Get(key []byte) ([]byte, error) {
res, err = db.diskDb.Get(key)
} else if ok, _ := rawdb.IsActivatedAsmKey(key); ok {
// Arbitrum: the asm is non-consensus
return db.diskDb.Get(key)
return db.wasmDb.Get(key)
} else if ok, _ := rawdb.IsActivatedModuleKey(key); ok {
// Arbitrum: the module is non-consensus (only its hash is)
return db.diskDb.Get(key)
return db.wasmDb.Get(key)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will these ever be called? Shouldn't they be called on the wasm database instead?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved some things around and now it is indeed not needed

} else {
err = fmt.Errorf("recording KV attempted to access non-hash key %v", hex.EncodeToString(key))
}
Expand Down Expand Up @@ -273,7 +274,7 @@ func (r *RecordingDatabase) PrepareRecording(ctx context.Context, lastBlockHeade
}
finalDereference := lastBlockHeader // dereference in case of error
defer func() { r.Dereference(finalDereference) }()
recordingKeyValue := newRecordingKV(r.db.TrieDB(), r.db.DiskDB())
recordingKeyValue := newRecordingKV(r.db.TrieDB(), r.db.DiskDB(), r.db.WasmStore())

recordingStateDatabase := state.NewDatabase(rawdb.NewDatabase(recordingKeyValue))
var prevRoot common.Hash
Expand Down
24 changes: 24 additions & 0 deletions core/rawdb/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ type freezerdb struct {
ancientRoot string
ethdb.KeyValueStore
ethdb.AncientStore
wasmDB ethdb.KeyValueStore
}

// AncientDatadir returns the path of root ancient directory.
func (frdb *freezerdb) WasmDataBase() ethdb.KeyValueStore {
if frdb.wasmDB == nil {
return frdb
}
return frdb.wasmDB
}

// AncientDatadir returns the path of root ancient directory.
Expand Down Expand Up @@ -165,6 +174,11 @@ func (db *nofreezedb) AncientDatadir() (string, error) {
return "", errNotSupported
}

// AncientDatadir returns the path of root ancient directory.
func (db *nofreezedb) WasmDataBase() ethdb.KeyValueStore {
return db
}

// 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 {
Expand Down Expand Up @@ -360,6 +374,7 @@ type OpenOptions struct {
Directory string // the datadir
AncientsDirectory string // the ancients-dir
Namespace string // the namespace for database relevant metrics
WasmDirectory string // the wasm-dir
Cache int // the capacity(in megabytes) of the data caching
Handles int // number of files to be open simultaneously
ReadOnly bool
Expand Down Expand Up @@ -416,6 +431,15 @@ func Open(o OpenOptions) (ethdb.Database, error) {
kvdb.Close()
return nil, err
}
if len(o.WasmDirectory) != 0 {
wasmOptions := o
wasmOptions.Directory = o.WasmDirectory
wasmDb, err := openKeyValueDatabase(wasmOptions)
if err != nil {
return nil, err
}
frdb.(*freezerdb).wasmDB = wasmDb
}
return frdb, nil
}

Expand Down
4 changes: 4 additions & 0 deletions core/rawdb/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ func (t *table) Close() error {
return nil
}

func (t *table) WasmDataBase() ethdb.KeyValueStore {
return t.db.WasmDataBase()
}

// 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...))
Expand Down
8 changes: 8 additions & 0 deletions core/state/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ type Database interface {
// Arbitrum: Read activated Stylus contracts
ActivatedAsm(moduleHash common.Hash) (asm []byte, err error)
ActivatedModule(moduleHash common.Hash) (module []byte, err error)
WasmStore() ethdb.KeyValueStore

// OpenTrie opens the main account trie.
OpenTrie(root common.Hash) (Trie, error)
Expand Down Expand Up @@ -164,6 +165,7 @@ func NewDatabaseWithConfig(db ethdb.Database, config *trie.Config) Database {
activatedModuleCache: lru.NewSizeConstrainedCache[common.Hash, []byte](activatedWasmCacheSize),

disk: db,
wasmdb: db.WasmDataBase(),
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
triedb: trie.NewDatabase(db, config),
Expand All @@ -179,6 +181,7 @@ func NewDatabaseWithNodeDB(db ethdb.Database, triedb *trie.Database) Database {
activatedModuleCache: lru.NewSizeConstrainedCache[common.Hash, []byte](activatedWasmCacheSize),

disk: db,
wasmdb: db.WasmDataBase(),
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
triedb: triedb,
Expand All @@ -192,11 +195,16 @@ type cachingDB struct {
activatedModuleCache *lru.SizeConstrainedCache[common.Hash, []byte]

disk ethdb.KeyValueStore
wasmdb ethdb.KeyValueStore
codeSizeCache *lru.Cache[common.Hash, int]
codeCache *lru.SizeConstrainedCache[common.Hash, []byte]
triedb *trie.Database
}

func (db *cachingDB) WasmStore() ethdb.KeyValueStore {
return db.wasmdb
}

// OpenTrie opens the main account trie at a specific root hash.
func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
if db.triedb.IsVerkle() {
Expand Down
4 changes: 2 additions & 2 deletions core/state/database_arbitrum.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func (db *cachingDB) ActivatedAsm(moduleHash common.Hash) ([]byte, error) {
return asm, nil
}
wasmKey := rawdb.ActivatedAsmKey(moduleHash)
asm, err := db.disk.Get(wasmKey[:])
asm, err := db.wasmdb.Get(wasmKey[:])
if err != nil {
return nil, err
}
Expand All @@ -28,7 +28,7 @@ func (db *cachingDB) ActivatedModule(moduleHash common.Hash) ([]byte, error) {
return module, nil
}
wasmKey := rawdb.ActivatedModuleKey(moduleHash)
module, err := db.disk.Get(wasmKey[:])
module, err := db.wasmdb.Get(wasmKey[:])
if err != nil {
return nil, err
}
Expand Down
8 changes: 7 additions & 1 deletion core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -1249,6 +1249,7 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
storageTrieNodesDeleted int
nodes = trienode.NewMergedNodeSet()
codeWriter = s.db.DiskDB().NewBatch()
wasmCodeWriter = s.db.WasmStore().NewBatch()
)
// Handle all state deletions first
incomplete, err := s.handleDestruction(nodes)
Expand Down Expand Up @@ -1286,7 +1287,7 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er

// Arbitrum: write Stylus programs to disk
for moduleHash, info := range s.arbExtraData.activatedWasms {
rawdb.WriteActivation(codeWriter, moduleHash, info.Asm, info.Module)
rawdb.WriteActivation(wasmCodeWriter, moduleHash, info.Asm, info.Module)
}
if len(s.arbExtraData.activatedWasms) > 0 {
s.arbExtraData.activatedWasms = make(map[common.Hash]*ActivatedWasm)
Expand All @@ -1297,6 +1298,11 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
log.Crit("Failed to commit dirty codes", "error", err)
}
}
if wasmCodeWriter.ValueSize() > 0 {
if err := wasmCodeWriter.Write(); err != nil {
log.Crit("Failed to commit dirty stylus codes", "error", err)
}
}
// Write the account trie changes, measuring the amount of wasted time
var start time.Time
if metrics.EnabledExpensive {
Expand Down
10 changes: 7 additions & 3 deletions core/state/statedb_arbitrum.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,16 @@ func (s *StateDB) ActivateWasm(moduleHash common.Hash, asm, module []byte) {
})
}

func (s *StateDB) GetActivatedAsm(moduleHash common.Hash) []byte {
func (s *StateDB) TryGetActivatedAsm(moduleHash common.Hash) ([]byte, error) {
info, exists := s.arbExtraData.activatedWasms[moduleHash]
if exists {
return info.Asm
return info.Asm, nil
}
asm, err := s.db.ActivatedAsm(moduleHash)
return s.db.ActivatedAsm(moduleHash)
}

func (s *StateDB) GetActivatedAsm(moduleHash common.Hash) []byte {
asm, err := s.TryGetActivatedAsm(moduleHash)
if err != nil {
s.setError(fmt.Errorf("failed to load asm for %x: %v", moduleHash, err))
}
Expand Down
1 change: 1 addition & 0 deletions core/vm/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type StateDB interface {
// Arbitrum: manage Stylus wasms
ActivateWasm(moduleHash common.Hash, asm, module []byte)
GetActivatedAsm(moduleHash common.Hash) (asm []byte)
TryGetActivatedAsm(moduleHash common.Hash) (asm []byte, err error)
GetActivatedModule(moduleHash common.Hash) (module []byte)
RecordCacheWasm(wasm state.CacheWasm)
RecordEvictWasm(wasm state.EvictWasm)
Expand Down
5 changes: 5 additions & 0 deletions ethdb/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,10 @@ type AncientStore interface {
io.Closer
}

type WasmDataBaseRetriever interface {
WasmDataBase() KeyValueStore
}

// Database contains all the methods required by the high level database to not
// only access the key-value data store but also the chain freezer.
type Database interface {
Expand All @@ -189,4 +193,5 @@ type Database interface {
Compacter
Snapshotter
io.Closer
WasmDataBaseRetriever
}
4 changes: 4 additions & 0 deletions ethdb/remotedb/remotedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ func (db *Database) Has(key []byte) (bool, error) {
return true, nil
}

func (t *Database) WasmDataBase() ethdb.KeyValueStore {
return t
}

func (db *Database) Get(key []byte) ([]byte, error) {
var resp hexutil.Bytes
err := db.remote.Call(&resp, "debug_dbGet", hexutil.Bytes(key))
Expand Down
5 changes: 5 additions & 0 deletions internal/ethapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -962,12 +962,17 @@ type OverrideAccount struct {
// StateOverride is the collection of overridden accounts.
type StateOverride map[common.Address]OverrideAccount

var arbStorageAddress = common.HexToAddress("0xA4B05FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
PlasmaPower marked this conversation as resolved.
Show resolved Hide resolved

// Apply overrides the fields of specified accounts into the given state.
func (diff *StateOverride) Apply(state *state.StateDB) error {
if diff == nil {
return nil
}
for addr, account := range *diff {
if addr == arbStorageAddress {
return errors.New("overriding 0xA4B05FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF not allowed")
}
// Override account nonce.
if account.Nonce != nil {
state.SetNonce(addr, uint64(*account.Nonce))
Expand Down
28 changes: 28 additions & 0 deletions node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,34 @@ func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, ancient
ReadOnly: readonly,
})
}
if err == nil {
db = n.wrapDatabase(db)
}
return db, err
}

func (n *Node) OpenDatabaseWithFreezerAndWasm(name string, wasmPath string, cache, handles int, ancient string, namespace string, readonly bool) (ethdb.Database, error) {
n.lock.Lock()
defer n.lock.Unlock()
if n.state == closedState {
return nil, ErrNodeStopped
}
var db ethdb.Database
var err error
if n.config.DataDir == "" {
db = rawdb.NewMemoryDatabase()
} else {
db, err = rawdb.Open(rawdb.OpenOptions{
Type: n.config.DBEngine,
Directory: n.ResolvePath(name),
AncientsDirectory: n.ResolveAncient(name, ancient),
Namespace: namespace,
WasmDirectory: n.ResolvePath(wasmPath),
Cache: cache,
Handles: handles,
ReadOnly: readonly,
})
}

if err == nil {
db = n.wrapDatabase(db)
Expand Down
Loading