Skip to content

Commit 045b971

Browse files
authored
trie: relocate state execution logic into pathdb package (#29861)
1 parent 269e80b commit 045b971

File tree

10 files changed

+259
-445
lines changed

10 files changed

+259
-445
lines changed

trie/secure_trie.go

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@ import (
2424
"github.com/ethereum/go-ethereum/triedb/database"
2525
)
2626

27+
// preimageStore wraps the methods of a backing store for reading and writing
28+
// trie node preimages.
29+
type preimageStore interface {
30+
// Preimage retrieves the preimage of the specified hash.
31+
Preimage(hash common.Hash) []byte
32+
33+
// InsertPreimage commits a set of preimages along with their hashes.
34+
InsertPreimage(preimages map[common.Hash][]byte)
35+
}
36+
2737
// SecureTrie is the old name of StateTrie.
2838
// Deprecated: use StateTrie.
2939
type SecureTrie = StateTrie
@@ -52,6 +62,7 @@ func NewSecure(stateRoot common.Hash, owner common.Hash, root common.Hash, db da
5262
type StateTrie struct {
5363
trie Trie
5464
db database.Database
65+
preimages preimageStore
5566
hashKeyBuf [common.HashLength]byte
5667
secKeyCache map[string][]byte
5768
secKeyCacheOwner *StateTrie // Pointer to self, replace the key cache on mismatch
@@ -70,7 +81,14 @@ func NewStateTrie(id *ID, db database.Database) (*StateTrie, error) {
7081
if err != nil {
7182
return nil, err
7283
}
73-
return &StateTrie{trie: *trie, db: db}, nil
84+
tr := &StateTrie{trie: *trie, db: db}
85+
86+
// link the preimage store if it's supported
87+
preimages, ok := db.(preimageStore)
88+
if ok {
89+
tr.preimages = preimages
90+
}
91+
return tr, nil
7492
}
7593

7694
// MustGet returns the value for key stored in the trie.
@@ -211,7 +229,10 @@ func (t *StateTrie) GetKey(shaKey []byte) []byte {
211229
if key, ok := t.getSecKeyCache()[string(shaKey)]; ok {
212230
return key
213231
}
214-
return t.db.Preimage(common.BytesToHash(shaKey))
232+
if t.preimages == nil {
233+
return nil
234+
}
235+
return t.preimages.Preimage(common.BytesToHash(shaKey))
215236
}
216237

217238
// Witness returns a set containing all trie nodes that have been accessed.
@@ -233,7 +254,9 @@ func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) {
233254
for hk, key := range t.secKeyCache {
234255
preimages[common.BytesToHash([]byte(hk))] = key
235256
}
236-
t.db.InsertPreimage(preimages)
257+
if t.preimages != nil {
258+
t.preimages.InsertPreimage(preimages)
259+
}
237260
t.secKeyCache = make(map[string][]byte)
238261
}
239262
// Commit the trie and return its modified nodeset.

trie/trie_reader.go

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"github.com/ethereum/go-ethereum/common"
2121
"github.com/ethereum/go-ethereum/core/types"
2222
"github.com/ethereum/go-ethereum/log"
23-
"github.com/ethereum/go-ethereum/trie/triestate"
2423
"github.com/ethereum/go-ethereum/triedb/database"
2524
)
2625

@@ -72,23 +71,3 @@ func (r *trieReader) node(path []byte, hash common.Hash) ([]byte, error) {
7271
}
7372
return blob, nil
7473
}
75-
76-
// MerkleLoader implements triestate.TrieLoader for constructing tries.
77-
type MerkleLoader struct {
78-
db database.Database
79-
}
80-
81-
// NewMerkleLoader creates the merkle trie loader.
82-
func NewMerkleLoader(db database.Database) *MerkleLoader {
83-
return &MerkleLoader{db: db}
84-
}
85-
86-
// OpenTrie opens the main account trie.
87-
func (l *MerkleLoader) OpenTrie(root common.Hash) (triestate.Trie, error) {
88-
return New(TrieID(root), l.db)
89-
}
90-
91-
// OpenStorageTrie opens the storage trie of an account.
92-
func (l *MerkleLoader) OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (triestate.Trie, error) {
93-
return New(StorageTrieID(stateRoot, addrHash, root), l.db)
94-
}

trie/triestate/state.go

Lines changed: 1 addition & 211 deletions
Original file line numberDiff line numberDiff line change
@@ -16,43 +16,7 @@
1616

1717
package triestate
1818

19-
import (
20-
"errors"
21-
"fmt"
22-
"sync"
23-
24-
"github.com/ethereum/go-ethereum/common"
25-
"github.com/ethereum/go-ethereum/core/types"
26-
"github.com/ethereum/go-ethereum/crypto"
27-
"github.com/ethereum/go-ethereum/rlp"
28-
"github.com/ethereum/go-ethereum/trie/trienode"
29-
)
30-
31-
// Trie is an Ethereum state trie, can be implemented by Ethereum Merkle Patricia
32-
// tree or Verkle tree.
33-
type Trie interface {
34-
// Get returns the value for key stored in the trie.
35-
Get(key []byte) ([]byte, error)
36-
37-
// Update associates key with value in the trie.
38-
Update(key, value []byte) error
39-
40-
// Delete removes any existing value for key from the trie.
41-
Delete(key []byte) error
42-
43-
// Commit the trie and returns a set of dirty nodes generated along with
44-
// the new root hash.
45-
Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet)
46-
}
47-
48-
// TrieLoader wraps functions to load tries.
49-
type TrieLoader interface {
50-
// OpenTrie opens the main account trie.
51-
OpenTrie(root common.Hash) (Trie, error)
52-
53-
// OpenStorageTrie opens the storage trie of an account.
54-
OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (Trie, error)
55-
}
19+
import "github.com/ethereum/go-ethereum/common"
5620

5721
// Set represents a collection of mutated states during a state transition.
5822
// The value refers to the original content of state before the transition
@@ -87,177 +51,3 @@ func (s *Set) Size() common.StorageSize {
8751
}
8852
return s.size
8953
}
90-
91-
// context wraps all fields for executing state diffs.
92-
type context struct {
93-
prevRoot common.Hash
94-
postRoot common.Hash
95-
accounts map[common.Address][]byte
96-
storages map[common.Address]map[common.Hash][]byte
97-
accountTrie Trie
98-
nodes *trienode.MergedNodeSet
99-
}
100-
101-
// Apply traverses the provided state diffs, apply them in the associated
102-
// post-state and return the generated dirty trie nodes. The state can be
103-
// loaded via the provided trie loader.
104-
func Apply(prevRoot common.Hash, postRoot common.Hash, accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte, loader TrieLoader) (map[common.Hash]map[string]*trienode.Node, error) {
105-
tr, err := loader.OpenTrie(postRoot)
106-
if err != nil {
107-
return nil, err
108-
}
109-
ctx := &context{
110-
prevRoot: prevRoot,
111-
postRoot: postRoot,
112-
accounts: accounts,
113-
storages: storages,
114-
accountTrie: tr,
115-
nodes: trienode.NewMergedNodeSet(),
116-
}
117-
for addr, account := range accounts {
118-
var err error
119-
if len(account) == 0 {
120-
err = deleteAccount(ctx, loader, addr)
121-
} else {
122-
err = updateAccount(ctx, loader, addr)
123-
}
124-
if err != nil {
125-
return nil, fmt.Errorf("failed to revert state, err: %w", err)
126-
}
127-
}
128-
root, result := tr.Commit(false)
129-
if root != prevRoot {
130-
return nil, fmt.Errorf("failed to revert state, want %#x, got %#x", prevRoot, root)
131-
}
132-
if err := ctx.nodes.Merge(result); err != nil {
133-
return nil, err
134-
}
135-
return ctx.nodes.Flatten(), nil
136-
}
137-
138-
// updateAccount the account was present in prev-state, and may or may not
139-
// existent in post-state. Apply the reverse diff and verify if the storage
140-
// root matches the one in prev-state account.
141-
func updateAccount(ctx *context, loader TrieLoader, addr common.Address) error {
142-
// The account was present in prev-state, decode it from the
143-
// 'slim-rlp' format bytes.
144-
h := newHasher()
145-
defer h.release()
146-
147-
addrHash := h.hash(addr.Bytes())
148-
prev, err := types.FullAccount(ctx.accounts[addr])
149-
if err != nil {
150-
return err
151-
}
152-
// The account may or may not existent in post-state, try to
153-
// load it and decode if it's found.
154-
blob, err := ctx.accountTrie.Get(addrHash.Bytes())
155-
if err != nil {
156-
return err
157-
}
158-
post := types.NewEmptyStateAccount()
159-
if len(blob) != 0 {
160-
if err := rlp.DecodeBytes(blob, &post); err != nil {
161-
return err
162-
}
163-
}
164-
// Apply all storage changes into the post-state storage trie.
165-
st, err := loader.OpenStorageTrie(ctx.postRoot, addrHash, post.Root)
166-
if err != nil {
167-
return err
168-
}
169-
for key, val := range ctx.storages[addr] {
170-
var err error
171-
if len(val) == 0 {
172-
err = st.Delete(key.Bytes())
173-
} else {
174-
err = st.Update(key.Bytes(), val)
175-
}
176-
if err != nil {
177-
return err
178-
}
179-
}
180-
root, result := st.Commit(false)
181-
if root != prev.Root {
182-
return errors.New("failed to reset storage trie")
183-
}
184-
// The returned set can be nil if storage trie is not changed
185-
// at all.
186-
if result != nil {
187-
if err := ctx.nodes.Merge(result); err != nil {
188-
return err
189-
}
190-
}
191-
// Write the prev-state account into the main trie
192-
full, err := rlp.EncodeToBytes(prev)
193-
if err != nil {
194-
return err
195-
}
196-
return ctx.accountTrie.Update(addrHash.Bytes(), full)
197-
}
198-
199-
// deleteAccount the account was not present in prev-state, and is expected
200-
// to be existent in post-state. Apply the reverse diff and verify if the
201-
// account and storage is wiped out correctly.
202-
func deleteAccount(ctx *context, loader TrieLoader, addr common.Address) error {
203-
// The account must be existent in post-state, load the account.
204-
h := newHasher()
205-
defer h.release()
206-
207-
addrHash := h.hash(addr.Bytes())
208-
blob, err := ctx.accountTrie.Get(addrHash.Bytes())
209-
if err != nil {
210-
return err
211-
}
212-
if len(blob) == 0 {
213-
return fmt.Errorf("account is non-existent %#x", addrHash)
214-
}
215-
var post types.StateAccount
216-
if err := rlp.DecodeBytes(blob, &post); err != nil {
217-
return err
218-
}
219-
st, err := loader.OpenStorageTrie(ctx.postRoot, addrHash, post.Root)
220-
if err != nil {
221-
return err
222-
}
223-
for key, val := range ctx.storages[addr] {
224-
if len(val) != 0 {
225-
return errors.New("expect storage deletion")
226-
}
227-
if err := st.Delete(key.Bytes()); err != nil {
228-
return err
229-
}
230-
}
231-
root, result := st.Commit(false)
232-
if root != types.EmptyRootHash {
233-
return errors.New("failed to clear storage trie")
234-
}
235-
// The returned set can be nil if storage trie is not changed
236-
// at all.
237-
if result != nil {
238-
if err := ctx.nodes.Merge(result); err != nil {
239-
return err
240-
}
241-
}
242-
// Delete the post-state account from the main trie.
243-
return ctx.accountTrie.Delete(addrHash.Bytes())
244-
}
245-
246-
// hasher is used to compute the sha256 hash of the provided data.
247-
type hasher struct{ sha crypto.KeccakState }
248-
249-
var hasherPool = sync.Pool{
250-
New: func() interface{} { return &hasher{sha: crypto.NewKeccakState()} },
251-
}
252-
253-
func newHasher() *hasher {
254-
return hasherPool.Get().(*hasher)
255-
}
256-
257-
func (h *hasher) hash(data []byte) common.Hash {
258-
return crypto.HashData(h.sha, data)
259-
}
260-
261-
func (h *hasher) release() {
262-
hasherPool.Put(h)
263-
}

triedb/database.go

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -264,14 +264,7 @@ func (db *Database) Recover(target common.Hash) error {
264264
if !ok {
265265
return errors.New("not supported")
266266
}
267-
var loader triestate.TrieLoader
268-
if db.config.IsVerkle {
269-
// TODO define verkle loader
270-
log.Crit("Verkle loader is not defined")
271-
} else {
272-
loader = trie.NewMerkleLoader(db)
273-
}
274-
return pdb.Recover(target, loader)
267+
return pdb.Recover(target)
275268
}
276269

277270
// Recoverable returns the indicator if the specified state is enabled to be

triedb/database/database.go

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@
1616

1717
package database
1818

19-
import (
20-
"github.com/ethereum/go-ethereum/common"
21-
)
19+
import "github.com/ethereum/go-ethereum/common"
2220

2321
// Reader wraps the Node method of a backing trie reader.
2422
type Reader interface {
@@ -31,20 +29,8 @@ type Reader interface {
3129
Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error)
3230
}
3331

34-
// PreimageStore wraps the methods of a backing store for reading and writing
35-
// trie node preimages.
36-
type PreimageStore interface {
37-
// Preimage retrieves the preimage of the specified hash.
38-
Preimage(hash common.Hash) []byte
39-
40-
// InsertPreimage commits a set of preimages along with their hashes.
41-
InsertPreimage(preimages map[common.Hash][]byte)
42-
}
43-
4432
// Database wraps the methods of a backing trie store.
4533
type Database interface {
46-
PreimageStore
47-
4834
// Reader returns a node reader associated with the specific state.
4935
// An error will be returned if the specified state is not available.
5036
Reader(stateRoot common.Hash) (Reader, error)

triedb/pathdb/database.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ func (db *Database) Enable(root common.Hash) error {
345345
// Recover rollbacks the database to a specified historical point.
346346
// The state is supported as the rollback destination only if it's
347347
// canonical state and the corresponding trie histories are existent.
348-
func (db *Database) Recover(root common.Hash, loader triestate.TrieLoader) error {
348+
func (db *Database) Recover(root common.Hash) error {
349349
db.lock.Lock()
350350
defer db.lock.Unlock()
351351

@@ -371,7 +371,7 @@ func (db *Database) Recover(root common.Hash, loader triestate.TrieLoader) error
371371
if err != nil {
372372
return err
373373
}
374-
dl, err = dl.revert(h, loader)
374+
dl, err = dl.revert(h)
375375
if err != nil {
376376
return err
377377
}

0 commit comments

Comments
 (0)