From 45a3ab42aa91513278d6988382a1ad8b10ba5f87 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Thu, 1 Jun 2023 10:29:41 +0200 Subject: [PATCH] core/state: move slot RLP encoding into the MPT implementation (#27000) Continuing with a series of PRs to make the Trie interface more generic, this PR moves the RLP encoding of storage slots inside the StateTrie and light.Trie implementations, as other types of tries don't use RLP. --- core/state/state_object.go | 33 ++++++++++++++++++--------------- light/trie.go | 13 +++++++++---- trie/secure_trie.go | 10 ++++++++-- 3 files changed, 35 insertions(+), 21 deletions(-) diff --git a/core/state/state_object.go b/core/state/state_object.go index 1e28b4c12..606441d2a 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -183,8 +183,9 @@ 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 + enc []byte + err error + value common.Hash ) if s.db.snap != nil { start := time.Now() @@ -192,6 +193,13 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has if metrics.EnabledExpensive { s.db.SnapshotStorageReads += time.Since(start) } + if len(enc) > 0 { + _, content, _, err := rlp.Split(enc) + if err != nil { + s.db.setError(err) + } + value.SetBytes(content) + } } // If the snapshot is unavailable or reading from it fails, load from the database. if s.db.snap == nil || err != nil { @@ -201,7 +209,7 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has s.db.setError(err) return common.Hash{} } - enc, err = tr.GetStorage(s.address, key.Bytes()) + val, err := tr.GetStorage(s.address, key.Bytes()) if metrics.EnabledExpensive { s.db.StorageReads += time.Since(start) } @@ -209,14 +217,7 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has s.db.setError(err) return common.Hash{} } - } - var value common.Hash - if len(enc) > 0 { - _, content, _, err := rlp.Split(enc) - if err != nil { - s.db.setError(err) - } - value.SetBytes(content) + value.SetBytes(val) } s.originStorage[key] = value return value @@ -292,7 +293,8 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) { } s.originStorage[key] = value - var v []byte + // rlp-encoded value to be used by the snapshot + var snapshotVal []byte if (value == common.Hash{}) { if err := tr.DeleteStorage(s.address, key[:]); err != nil { s.db.setError(err) @@ -300,9 +302,10 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) { } s.db.StorageDeleted += 1 } else { + trimmedVal := common.TrimLeftZeroes(value[:]) // Encoding []byte cannot fail, ok to ignore the error. - v, _ = rlp.EncodeToBytes(common.TrimLeftZeroes(value[:])) - if err := tr.UpdateStorage(s.address, key[:], v); err != nil { + snapshotVal, _ = rlp.EncodeToBytes(trimmedVal) + if err := tr.UpdateStorage(s.address, key[:], trimmedVal); err != nil { s.db.setError(err) return nil, err } @@ -317,7 +320,7 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) { s.db.snapStorage[s.addrHash] = storage } } - storage[crypto.HashData(hasher, key[:])] = v // v will be nil if it's deleted + storage[crypto.HashData(hasher, key[:])] = snapshotVal // will be nil if it's deleted } usedStorage = append(usedStorage, common.CopyBytes(key[:])) // Copy needed for closure } diff --git a/light/trie.go b/light/trie.go index 6d802a5fb..105a11fb3 100644 --- a/light/trie.go +++ b/light/trie.go @@ -108,12 +108,16 @@ type odrTrie struct { func (t *odrTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) { key = crypto.Keccak256(key) - var res []byte + var enc []byte err := t.do(key, func() (err error) { - res, err = t.trie.Get(key) + enc, err = t.trie.Get(key) return err }) - return res, err + if err != nil || len(enc) == 0 { + return nil, err + } + _, content, _, err := rlp.Split(enc) + return content, err } func (t *odrTrie) GetAccount(address common.Address) (*types.StateAccount, error) { @@ -145,8 +149,9 @@ func (t *odrTrie) UpdateAccount(address common.Address, acc *types.StateAccount) func (t *odrTrie) UpdateStorage(_ common.Address, key, value []byte) error { key = crypto.Keccak256(key) + v, _ := rlp.EncodeToBytes(value) return t.do(key, func() error { - return t.trie.Update(key, value) + return t.trie.Update(key, v) }) } diff --git a/trie/secure_trie.go b/trie/secure_trie.go index b3cdeadb6..62666c7f0 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -86,7 +86,12 @@ func (t *StateTrie) MustGet(key []byte) []byte { // If the specified storage slot is not in the trie, nil will be returned. // If a trie node is not found in the database, a MissingNodeError is returned. func (t *StateTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) { - return t.trie.Get(t.hashKey(key)) + enc, err := t.trie.Get(t.hashKey(key)) + if err != nil || len(enc) == 0 { + return nil, err + } + _, content, _, err := rlp.Split(enc) + return content, err } // GetAccount attempts to retrieve an account with provided account address. @@ -148,7 +153,8 @@ func (t *StateTrie) MustUpdate(key, value []byte) { // If a node is not found in the database, a MissingNodeError is returned. func (t *StateTrie) UpdateStorage(_ common.Address, key, value []byte) error { hk := t.hashKey(key) - err := t.trie.Update(hk, value) + v, _ := rlp.EncodeToBytes(value) + err := t.trie.Update(hk, v) if err != nil { return err }