From ae70c88e192cec02c19aa027dccf55e4ffd70a05 Mon Sep 17 00:00:00 2001 From: i-norden Date: Mon, 27 Feb 2023 15:51:04 -0600 Subject: [PATCH] remove snapshot usage and unused internal methods; note this is different than the journaling used to simulate state transitions --- config.go | 1 - database.go | 9 +++- journal.go | 3 -- state_object.go | 43 ------------------ statedb.go | 118 +++++++----------------------------------------- 5 files changed, 23 insertions(+), 151 deletions(-) diff --git a/config.go b/config.go index 77f9730..c7c83f7 100644 --- a/config.go +++ b/config.go @@ -37,7 +37,6 @@ func makePGXConfig(config Config) (*pgxpool.Config, error) { return nil, err } - //conf.ConnConfig.BuildStatementCache = nil conf.ConnConfig.Config.Host = config.Hostname conf.ConnConfig.Config.Port = uint16(config.Port) conf.ConnConfig.Config.Database = config.DatabaseName diff --git a/database.go b/database.go index b3d4fa8..d347b9c 100644 --- a/database.go +++ b/database.go @@ -3,6 +3,8 @@ package ipld_eth_statedb import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/trie" "github.com/jackc/pgx/pgxpool" ) @@ -15,10 +17,13 @@ type Database interface { } type StateDatabase struct { - pgxpool.Pool + db pgxpool.Pool + trieDB *trie.Database + ethDB ethdb.Database } func (sd *StateDatabase) ContractCode(addrHash common.Hash, codeHash common.Hash) ([]byte, error) { + panic("implement me") } @@ -27,7 +32,7 @@ func (sd *StateDatabase) ContractCodeSize(addrHash common.Hash, codeHash common. } func (sd *StateDatabase) OpenTrie(root common.Hash) (state.Trie, error) { - panic("replace my usage") + return trie.NewStateTrie(common.Hash{}, root, sd.trieDB), nil } func (sd *StateDatabase) OpenStorageTrie(addrHash common.Hash, root common.Hash) (state.Trie, error) { diff --git a/journal.go b/journal.go index 1206865..7226171 100644 --- a/journal.go +++ b/journal.go @@ -135,9 +135,6 @@ func (ch createObjectChange) dirtied() *common.Address { func (ch resetObjectChange) revert(s *StateDB) { s.setStateObject(ch.prev) - if !ch.prevdestruct && s.snap != nil { - delete(s.snapDestructs, ch.prev.addrHash) - } } func (ch resetObjectChange) dirtied() *common.Address { diff --git a/state_object.go b/state_object.go index 7e58b2d..d34170f 100644 --- a/state_object.go +++ b/state_object.go @@ -186,36 +186,7 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has // If no live objects are available, attempt to use snapshots var ( enc []byte - err error ) - if s.db.snap != nil { - // If the object was destructed in *this* block (and potentially resurrected), - // the storage has been cleared out, and we should *not* consult the previous - // snapshot about any storage values. The only possible alternatives are: - // 1) resurrect happened, and new slot values were set -- those should - // have been handles via pendingStorage above. - // 2) we don't have new values, and can deliver empty response back - if _, destructed := s.db.snapDestructs[s.addrHash]; destructed { - return common.Hash{} - } - start := time.Now() - enc, err = s.db.snap.Storage(s.addrHash, crypto.Keccak256Hash(key.Bytes())) - if metrics.EnabledExpensive { - s.db.SnapshotStorageReads += time.Since(start) - } - } - // If the snapshot is unavailable or reading from it fails, load from the database. - if s.db.snap == nil || err != nil { - start := time.Now() - enc, err = s.getTrie(db).TryGet(key.Bytes()) - if metrics.EnabledExpensive { - s.db.StorageReads += time.Since(start) - } - if err != nil { - s.setError(err) - return common.Hash{} - } - } var value common.Hash if len(enc) > 0 { _, content, _, err := rlp.Split(enc) @@ -301,11 +272,8 @@ func (s *stateObject) updateTrie(db Database) state.Trie { if metrics.EnabledExpensive { defer func(start time.Time) { s.db.StorageUpdates += time.Since(start) }(time.Now()) } - // The snapshot storage map for the object - var storage map[common.Hash][]byte // Insert all the pending updates into the trie tr := s.getTrie(db) - hasher := s.db.hasher usedStorage := make([][]byte, 0, len(s.pendingStorage)) for key, value := range s.pendingStorage { @@ -325,17 +293,6 @@ func (s *stateObject) updateTrie(db Database) state.Trie { s.setError(tr.TryUpdate(key[:], v)) s.db.StorageUpdated += 1 } - // If state snapshotting is active, cache the data til commit - if s.db.snap != nil { - if storage == nil { - // Retrieve the old storage map, if available, create a new one otherwise - if storage = s.db.snapStorage[s.addrHash]; storage == nil { - storage = make(map[common.Hash][]byte) - s.db.snapStorage[s.addrHash] = storage - } - } - storage[crypto.HashData(hasher, key[:])] = v // v will be nil if it's deleted - } usedStorage = append(usedStorage, common.CopyBytes(key[:])) // Copy needed for closure } if s.db.prefetcher != nil { diff --git a/statedb.go b/statedb.go index 4698f51..13c95cd 100644 --- a/statedb.go +++ b/statedb.go @@ -65,7 +65,6 @@ type StateDB struct { originalRoot common.Hash snaps *snapshot.Tree - snap snapshot.Snapshot snapDestructs map[common.Hash]struct{} snapAccounts map[common.Hash][]byte snapStorage map[common.Hash]map[common.Hash][]byte @@ -140,13 +139,6 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) accessList: newAccessList(), hasher: crypto.NewKeccakState(), } - if sdb.snaps != nil { - if sdb.snap = sdb.snaps.Snapshot(root); sdb.snap != nil { - sdb.snapDestructs = make(map[common.Hash]struct{}) - sdb.snapAccounts = make(map[common.Hash][]byte) - sdb.snapStorage = make(map[common.Hash]map[common.Hash][]byte) - } - } return sdb, nil } @@ -347,42 +339,6 @@ func (s *StateDB) Suicide(addr common.Address) bool { // Setting, updating & deleting state object methods. // -// updateStateObject writes the given object to the trie. -// TODO: -func (s *StateDB) updateStateObject(obj *stateObject) { - // Track the amount of time wasted on updating the account from the trie - if metrics.EnabledExpensive { - defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now()) - } - // Encode the account and update the account trie - addr := obj.Address() - if err := s.trie.TryUpdateAccount(addr[:], &obj.data); err != nil { - s.setError(fmt.Errorf("updateStateObject (%x) error: %v", addr[:], err)) - } - - // If state snapshotting is active, cache the data til commit. Note, this - // update mechanism is not symmetric to the deletion, because whereas it is - // enough to track account updates at commit time, deletions need tracking - // at transaction boundary level to ensure we capture state clearing. - if s.snap != nil { - s.snapAccounts[obj.addrHash] = snapshot.SlimAccountRLP(obj.data.Nonce, obj.data.Balance, obj.data.Root, obj.data.CodeHash) - } -} - -// deleteStateObject removes the given object from the state trie. -// TODO: -func (s *StateDB) deleteStateObject(obj *stateObject) { - // Track the amount of time wasted on deleting the account from the trie - if metrics.EnabledExpensive { - defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now()) - } - // Delete the account from the trie - addr := obj.Address() - if err := s.trie.TryDeleteAccount(addr[:]); err != nil { - s.setError(fmt.Errorf("deleteStateObject (%x) error: %v", addr[:], err)) - } -} - // getStateObject retrieves a state object given by the address, returning nil if // the object is not found or was deleted in this execution context. If you need // to differentiate between non-existent/just-deleted, use getDeletedStateObject. @@ -403,47 +359,20 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject { if obj := s.stateObjects[addr]; obj != nil { return obj } - // If no live objects are available, attempt to use snapshots - var data *types.StateAccount - if s.snap != nil { - start := time.Now() - acc, err := s.snap.Account(crypto.HashData(s.hasher, addr.Bytes())) - if metrics.EnabledExpensive { - s.SnapshotAccountReads += time.Since(start) - } - if err == nil { - if acc == nil { - return nil - } - data = &types.StateAccount{ - Nonce: acc.Nonce, - Balance: acc.Balance, - CodeHash: acc.CodeHash, - Root: common.BytesToHash(acc.Root), - } - if len(data.CodeHash) == 0 { - data.CodeHash = emptyCodeHash - } - if data.Root == (common.Hash{}) { - data.Root = emptyRoot - } - } + // If no live objects are available, load from the database + // TODO: REPLACE TRIE ACCESS HERE + // can add a fallback option to use ipfsethdb to do the trie access if direct access fails + start := time.Now() + data, err := s.trie.TryGetAccount(addr.Bytes()) + if metrics.EnabledExpensive { + s.AccountReads += time.Since(start) + } + if err != nil { + s.setError(fmt.Errorf("getDeleteStateObject (%x) error: %w", addr.Bytes(), err)) + return nil } - // If snapshot unavailable or reading from it failed, load from the database if data == nil { - start := time.Now() - var err error - data, err = s.trie.TryGetAccount(addr.Bytes()) - if metrics.EnabledExpensive { - s.AccountReads += time.Since(start) - } - if err != nil { - s.setError(fmt.Errorf("getDeleteStateObject (%x) error: %w", addr.Bytes(), err)) - return nil - } - if data == nil { - return nil - } + return nil } // Insert into the live set obj := newObject(s, addr, *data) @@ -468,19 +397,11 @@ func (s *StateDB) getOrNewStateObject(addr common.Address) *stateObject { // the given address, it is overwritten and returned as the second return value. func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) { prev = s.getDeletedStateObject(addr) // Note, prev might have been deleted, we need that! - - var prevdestruct bool - if s.snap != nil && prev != nil { - _, prevdestruct = s.snapDestructs[prev.addrHash] - if !prevdestruct { - s.snapDestructs[prev.addrHash] = struct{}{} - } - } newobj = newObject(s, addr, types.StateAccount{}) if prev == nil { s.journal.append(createObjectChange{account: &addr}) } else { - s.journal.append(resetObjectChange{prev: prev, prevdestruct: prevdestruct}) + s.journal.append(resetObjectChange{prev: prev}) // NOTE: prevdestruct used to be set here from snapshot } s.setStateObject(newobj) if prev != nil && !prev.deleted { @@ -506,6 +427,7 @@ func (s *StateDB) CreateAccount(addr common.Address) { } } +// TODO: not sure trie access can be replaced for this method, might need to use ipfs-ethdb func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common.Hash) bool) error { so := db.getStateObject(addr) if so == nil { @@ -552,10 +474,10 @@ func (s *StateDB) RevertToSnapshot(revid int) { if idx == len(s.validRevisions) || s.validRevisions[idx].id != revid { panic(fmt.Errorf("revision id %v cannot be reverted", revid)) } - snapshot := s.validRevisions[idx].journalIndex + snp := s.validRevisions[idx].journalIndex // Replay the journal to undo changes and remove invalidated snapshots - s.journal.revert(s, snapshot) + s.journal.revert(s, snp) s.validRevisions = s.validRevisions[:idx] } @@ -564,14 +486,6 @@ func (s *StateDB) GetRefund() uint64 { return s.refund } -func (s *StateDB) clearJournalAndRefund() { - if len(s.journal.entries) > 0 { - s.journal = newJournal() - s.refund = 0 - } - s.validRevisions = s.validRevisions[:0] // Snapshots can be created without journal entries -} - // PrepareAccessList handles the preparatory steps for executing a state transition with // regards to both EIP-2929 and EIP-2930: //