all: implement witness

This commit is contained in:
Gary Rong 2023-10-07 20:17:27 +08:00
parent 4e1e37323d
commit 213a0eb149
23 changed files with 173 additions and 131 deletions

View file

@ -115,7 +115,7 @@ type Trie interface {
// The returned nodeset can be nil if the trie is clean(nothing to commit). // The returned nodeset can be nil if the trie is clean(nothing to commit).
// Once the trie is committed, it's not usable anymore. A new trie must // Once the trie is committed, it's not usable anymore. A new trie must
// be created with new root and updated trie database for following usage // be created with new root and updated trie database for following usage
Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, *trienode.Witness, error)
// NodeIterator returns an iterator that returns nodes of the trie. Iteration // NodeIterator returns an iterator that returns nodes of the trie. Iteration
// starts at the key after the given start key. And error will be returned // starts at the key after the given start key. And error will be returned

View file

@ -362,7 +362,7 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, trieId *trie.ID, prefi
for i, key := range result.keys { for i, key := range result.keys {
snapTrie.Update(key, result.vals[i]) snapTrie.Update(key, result.vals[i])
} }
root, nodes, err := snapTrie.Commit(false) root, nodes, _, err := snapTrie.Commit(false)
if err != nil { if err != nil {
return false, nil, err return false, nil, err
} }

View file

@ -209,7 +209,7 @@ func (t *testHelper) makeStorageTrie(owner common.Hash, keys []string, vals []st
if !commit { if !commit {
return stTrie.Hash() return stTrie.Hash()
} }
root, nodes, _ := stTrie.Commit(false) root, nodes, _, _ := stTrie.Commit(false)
if nodes != nil { if nodes != nil {
t.nodes.Merge(nodes) t.nodes.Merge(nodes)
} }
@ -217,7 +217,7 @@ func (t *testHelper) makeStorageTrie(owner common.Hash, keys []string, vals []st
} }
func (t *testHelper) Commit() common.Hash { func (t *testHelper) Commit() common.Hash {
root, nodes, _ := t.accTrie.Commit(true) root, nodes, _, _ := t.accTrie.Commit(true)
if nodes != nil { if nodes != nil {
t.nodes.Merge(nodes) t.nodes.Merge(nodes)
} }

View file

@ -388,7 +388,7 @@ func (s *stateObject) commit() (*trienode.NodeSet, error) {
// The trie is currently in an open state and could potentially contain // The trie is currently in an open state and could potentially contain
// cached mutations. Call commit to acquire a set of nodes that have been // cached mutations. Call commit to acquire a set of nodes that have been
// modified, the set can be nil if nothing to commit. // modified, the set can be nil if nothing to commit.
root, nodes, err := s.trie.Commit(false) root, nodes, _, err := s.trie.Commit(false)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -1222,7 +1222,7 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
if metrics.EnabledExpensive { if metrics.EnabledExpensive {
start = time.Now() start = time.Now()
} }
root, set, err := s.trie.Commit(true) root, set, _, err := s.trie.Commit(true)
if err != nil { if err != nil {
return common.Hash{}, err return common.Hash{}, err
} }

View file

@ -1482,7 +1482,7 @@ func makeAccountTrieNoStorage(n int, scheme string) (string, *trie.Trie, []*kv)
// Commit the state changes into db and re-create the trie // Commit the state changes into db and re-create the trie
// for accessing later. // for accessing later.
root, nodes, _ := accTrie.Commit(false) root, nodes, _, _ := accTrie.Commit(false)
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
accTrie, _ = trie.New(trie.StateTrieID(root), db) accTrie, _ = trie.New(trie.StateTrieID(root), db)
@ -1544,7 +1544,7 @@ func makeBoundaryAccountTrie(scheme string, n int) (string, *trie.Trie, []*kv) {
// Commit the state changes into db and re-create the trie // Commit the state changes into db and re-create the trie
// for accessing later. // for accessing later.
root, nodes, _ := accTrie.Commit(false) root, nodes, _, _ := accTrie.Commit(false)
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
accTrie, _ = trie.New(trie.StateTrieID(root), db) accTrie, _ = trie.New(trie.StateTrieID(root), db)
@ -1590,7 +1590,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(scheme string, accounts, slots
slices.SortFunc(entries, (*kv).cmp) slices.SortFunc(entries, (*kv).cmp)
// Commit account trie // Commit account trie
root, set, _ := accTrie.Commit(true) root, set, _, _ := accTrie.Commit(true)
nodes.Merge(set) nodes.Merge(set)
// Commit gathered dirty nodes into database // Commit gathered dirty nodes into database
@ -1655,7 +1655,7 @@ func makeAccountTrieWithStorage(scheme string, accounts, slots int, code, bounda
slices.SortFunc(entries, (*kv).cmp) slices.SortFunc(entries, (*kv).cmp)
// Commit account trie // Commit account trie
root, set, _ := accTrie.Commit(true) root, set, _, _ := accTrie.Commit(true)
nodes.Merge(set) nodes.Merge(set)
// Commit gathered dirty nodes into database // Commit gathered dirty nodes into database
@ -1697,7 +1697,7 @@ func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Databas
entries = append(entries, elem) entries = append(entries, elem)
} }
slices.SortFunc(entries, (*kv).cmp) slices.SortFunc(entries, (*kv).cmp)
root, nodes, _ := trie.Commit(false) root, nodes, _, _ := trie.Commit(false)
return root, nodes, entries return root, nodes, entries
} }
@ -1748,7 +1748,7 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (commo
entries = append(entries, elem) entries = append(entries, elem)
} }
slices.SortFunc(entries, (*kv).cmp) slices.SortFunc(entries, (*kv).cmp)
root, nodes, _ := trie.Commit(false) root, nodes, _, _ := trie.Commit(false)
return root, nodes, entries return root, nodes, entries
} }

View file

@ -214,7 +214,7 @@ func (c *ChtIndexerBackend) Process(ctx context.Context, header *types.Header) e
// Commit implements core.ChainIndexerBackend // Commit implements core.ChainIndexerBackend
func (c *ChtIndexerBackend) Commit() error { func (c *ChtIndexerBackend) Commit() error {
root, nodes, err := c.trie.Commit(false) root, nodes, _, err := c.trie.Commit(false)
if err != nil { if err != nil {
return err return err
} }
@ -467,7 +467,7 @@ func (b *BloomTrieIndexerBackend) Commit() error {
return terr return terr
} }
} }
root, nodes, err := b.trie.Commit(false) root, nodes, _, err := b.trie.Commit(false)
if err != nil { if err != nil {
return err return err
} }

View file

@ -177,9 +177,9 @@ func (t *odrTrie) DeleteAccount(address common.Address) error {
}) })
} }
func (t *odrTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) { func (t *odrTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, *trienode.Witness, error) {
if t.trie == nil { if t.trie == nil {
return t.id.Root, nil, nil return t.id.Root, nil, nil, nil
} }
return t.trie.Commit(collectLeaf) return t.trie.Commit(collectLeaf)
} }

View file

@ -171,7 +171,7 @@ func (f *fuzzer) fuzz() int {
return 0 return 0
} }
// Flush trie -> database // Flush trie -> database
rootA, nodes, err := trieA.Commit(false) rootA, nodes, _, err := trieA.Commit(false)
if err != nil { if err != nil {
panic(err) panic(err)
} }

View file

@ -165,7 +165,7 @@ func runRandTest(rt randTest) error {
case opHash: case opHash:
tr.Hash() tr.Hash()
case opCommit: case opCommit:
hash, nodes, err := tr.Commit(false) hash, nodes, _, err := tr.Commit(false)
if err != nil { if err != nil {
return err return err
} }

View file

@ -28,15 +28,15 @@ import (
// insertion order. // insertion order.
type committer struct { type committer struct {
nodes *trienode.NodeSet nodes *trienode.NodeSet
tracer *tracer witness *trienode.Witness
collectLeaf bool collectLeaf bool
} }
// newCommitter creates a new committer or picks one from the pool. // newCommitter creates a new committer or picks one from the pool.
func newCommitter(nodeset *trienode.NodeSet, tracer *tracer, collectLeaf bool) *committer { func newCommitter(nodeset *trienode.NodeSet, witness *trienode.Witness, collectLeaf bool) *committer {
return &committer{ return &committer{
nodes: nodeset, nodes: nodeset,
tracer: tracer, witness: witness,
collectLeaf: collectLeaf, collectLeaf: collectLeaf,
} }
} }
@ -131,8 +131,7 @@ func (c *committer) store(path []byte, n node) node {
// The node is embedded in its parent, in other words, this node // The node is embedded in its parent, in other words, this node
// will not be stored in the database independently, mark it as // will not be stored in the database independently, mark it as
// deleted only if the node was existent in database before. // deleted only if the node was existent in database before.
_, ok := c.tracer.accessList[string(path)] if c.witness.Has(string(path)) {
if ok {
c.nodes.AddNode(path, trienode.NewDeleted()) c.nodes.AddNode(path, trienode.NewDeleted())
} }
return n return n

View file

@ -59,7 +59,7 @@ func TestIterator(t *testing.T) {
all[val.k] = val.v all[val.k] = val.v
trie.MustUpdate([]byte(val.k), []byte(val.v)) trie.MustUpdate([]byte(val.k), []byte(val.v))
} }
root, nodes, _ := trie.Commit(false) root, nodes, _, _ := trie.Commit(false)
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
trie, _ = New(TrieID(root), db) trie, _ = New(TrieID(root), db)
@ -251,7 +251,7 @@ func TestDifferenceIterator(t *testing.T) {
for _, val := range testdata1 { for _, val := range testdata1 {
triea.MustUpdate([]byte(val.k), []byte(val.v)) triea.MustUpdate([]byte(val.k), []byte(val.v))
} }
rootA, nodesA, _ := triea.Commit(false) rootA, nodesA, _, _ := triea.Commit(false)
dba.Update(rootA, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodesA), nil) dba.Update(rootA, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodesA), nil)
triea, _ = New(TrieID(rootA), dba) triea, _ = New(TrieID(rootA), dba)
@ -260,7 +260,7 @@ func TestDifferenceIterator(t *testing.T) {
for _, val := range testdata2 { for _, val := range testdata2 {
trieb.MustUpdate([]byte(val.k), []byte(val.v)) trieb.MustUpdate([]byte(val.k), []byte(val.v))
} }
rootB, nodesB, _ := trieb.Commit(false) rootB, nodesB, _, _ := trieb.Commit(false)
dbb.Update(rootB, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodesB), nil) dbb.Update(rootB, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodesB), nil)
trieb, _ = New(TrieID(rootB), dbb) trieb, _ = New(TrieID(rootB), dbb)
@ -293,7 +293,7 @@ func TestUnionIterator(t *testing.T) {
for _, val := range testdata1 { for _, val := range testdata1 {
triea.MustUpdate([]byte(val.k), []byte(val.v)) triea.MustUpdate([]byte(val.k), []byte(val.v))
} }
rootA, nodesA, _ := triea.Commit(false) rootA, nodesA, _, _ := triea.Commit(false)
dba.Update(rootA, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodesA), nil) dba.Update(rootA, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodesA), nil)
triea, _ = New(TrieID(rootA), dba) triea, _ = New(TrieID(rootA), dba)
@ -302,7 +302,7 @@ func TestUnionIterator(t *testing.T) {
for _, val := range testdata2 { for _, val := range testdata2 {
trieb.MustUpdate([]byte(val.k), []byte(val.v)) trieb.MustUpdate([]byte(val.k), []byte(val.v))
} }
rootB, nodesB, _ := trieb.Commit(false) rootB, nodesB, _, _ := trieb.Commit(false)
dbb.Update(rootB, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodesB), nil) dbb.Update(rootB, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodesB), nil)
trieb, _ = New(TrieID(rootB), dbb) trieb, _ = New(TrieID(rootB), dbb)
@ -364,7 +364,7 @@ func testIteratorContinueAfterError(t *testing.T, memonly bool, scheme string) {
for _, val := range testdata1 { for _, val := range testdata1 {
tr.MustUpdate([]byte(val.k), []byte(val.v)) tr.MustUpdate([]byte(val.k), []byte(val.v))
} }
root, nodes, _ := tr.Commit(false) root, nodes, _, _ := tr.Commit(false)
tdb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) tdb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
if !memonly { if !memonly {
tdb.Commit(root, false) tdb.Commit(root, false)
@ -474,7 +474,7 @@ func testIteratorContinueAfterSeekError(t *testing.T, memonly bool, scheme strin
for _, val := range testdata1 { for _, val := range testdata1 {
ctr.MustUpdate([]byte(val.k), []byte(val.v)) ctr.MustUpdate([]byte(val.k), []byte(val.v))
} }
root, nodes, _ := ctr.Commit(false) root, nodes, _, _ := ctr.Commit(false)
for path, n := range nodes.Nodes { for path, n := range nodes.Nodes {
if n.Hash == barNodeHash { if n.Hash == barNodeHash {
barNodePath = []byte(path) barNodePath = []byte(path)
@ -554,7 +554,7 @@ func testIteratorNodeBlob(t *testing.T, scheme string) {
all[val.k] = val.v all[val.k] = val.v
trie.MustUpdate([]byte(val.k), []byte(val.v)) trie.MustUpdate([]byte(val.k), []byte(val.v))
} }
root, nodes, _ := trie.Commit(false) root, nodes, _, _ := trie.Commit(false)
triedb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) triedb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
triedb.Commit(root, false) triedb.Commit(root, false)

View file

@ -223,7 +223,7 @@ func (t *StateTrie) GetKey(shaKey []byte) []byte {
// All cached preimages will be also flushed if preimages recording is enabled. // All cached preimages will be also flushed if preimages recording is enabled.
// Once the trie is committed, it's not usable anymore. A new trie must // Once the trie is committed, it's not usable anymore. A new trie must
// be created with new root and updated trie database for following usage // be created with new root and updated trie database for following usage
func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) { func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, *trienode.Witness, error) {
// Write all the pre-images to the actual disk database // Write all the pre-images to the actual disk database
if len(t.getSecKeyCache()) > 0 { if len(t.getSecKeyCache()) > 0 {
if t.preimages != nil { if t.preimages != nil {

View file

@ -60,7 +60,7 @@ func makeTestStateTrie() (*Database, *StateTrie, map[string][]byte) {
trie.MustUpdate(key, val) trie.MustUpdate(key, val)
} }
} }
root, nodes, _ := trie.Commit(false) root, nodes, _, _ := trie.Commit(false)
if err := triedb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil); err != nil { if err := triedb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil); err != nil {
panic(fmt.Errorf("failed to commit db %v", err)) panic(fmt.Errorf("failed to commit db %v", err))
} }

View file

@ -56,7 +56,7 @@ func makeTestTrie(scheme string) (ethdb.Database, *Database, *StateTrie, map[str
trie.MustUpdate(key, val) trie.MustUpdate(key, val)
} }
} }
root, nodes, _ := trie.Commit(false) root, nodes, _, _ := trie.Commit(false)
if err := triedb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil); err != nil { if err := triedb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil); err != nil {
panic(fmt.Errorf("failed to commit db %v", err)) panic(fmt.Errorf("failed to commit db %v", err))
} }
@ -759,7 +759,7 @@ func testSyncMovingTarget(t *testing.T, scheme string) {
srcTrie.MustUpdate(key, val) srcTrie.MustUpdate(key, val)
diff[string(key)] = val diff[string(key)] = val
} }
root, nodes, _ := srcTrie.Commit(false) root, nodes, _, _ := srcTrie.Commit(false)
if err := srcDb.Update(root, preRoot, 0, trienode.NewWithNodeSet(nodes), nil); err != nil { if err := srcDb.Update(root, preRoot, 0, trienode.NewWithNodeSet(nodes), nil); err != nil {
panic(err) panic(err)
} }
@ -784,7 +784,7 @@ func testSyncMovingTarget(t *testing.T, scheme string) {
srcTrie.MustUpdate([]byte(k), val) srcTrie.MustUpdate([]byte(k), val)
reverted[k] = val reverted[k] = val
} }
root, nodes, _ = srcTrie.Commit(false) root, nodes, _, _ = srcTrie.Commit(false)
if err := srcDb.Update(root, preRoot, 0, trienode.NewWithNodeSet(nodes), nil); err != nil { if err := srcDb.Update(root, preRoot, 0, trienode.NewWithNodeSet(nodes), nil); err != nil {
panic(err) panic(err)
} }
@ -842,7 +842,7 @@ func testPivotMove(t *testing.T, scheme string, tiny bool) {
writeFn([]byte{0x02, 0x34}, nil, srcTrie, stateA) writeFn([]byte{0x02, 0x34}, nil, srcTrie, stateA)
writeFn([]byte{0x13, 0x44}, nil, srcTrie, stateA) writeFn([]byte{0x13, 0x44}, nil, srcTrie, stateA)
rootA, nodesA, _ := srcTrie.Commit(false) rootA, nodesA, _, _ := srcTrie.Commit(false)
if err := srcTrieDB.Update(rootA, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodesA), nil); err != nil { if err := srcTrieDB.Update(rootA, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodesA), nil); err != nil {
panic(err) panic(err)
} }
@ -861,7 +861,7 @@ func testPivotMove(t *testing.T, scheme string, tiny bool) {
deleteFn([]byte{0x13, 0x44}, srcTrie, stateB) deleteFn([]byte{0x13, 0x44}, srcTrie, stateB)
writeFn([]byte{0x01, 0x24}, nil, srcTrie, stateB) writeFn([]byte{0x01, 0x24}, nil, srcTrie, stateB)
rootB, nodesB, _ := srcTrie.Commit(false) rootB, nodesB, _, _ := srcTrie.Commit(false)
if err := srcTrieDB.Update(rootB, rootA, 0, trienode.NewWithNodeSet(nodesB), nil); err != nil { if err := srcTrieDB.Update(rootB, rootA, 0, trienode.NewWithNodeSet(nodesB), nil); err != nil {
panic(err) panic(err)
} }
@ -879,7 +879,7 @@ func testPivotMove(t *testing.T, scheme string, tiny bool) {
writeFn([]byte{0x02, 0x34}, nil, srcTrie, stateC) writeFn([]byte{0x02, 0x34}, nil, srcTrie, stateC)
writeFn([]byte{0x13, 0x44}, nil, srcTrie, stateC) writeFn([]byte{0x13, 0x44}, nil, srcTrie, stateC)
rootC, nodesC, _ := srcTrie.Commit(false) rootC, nodesC, _, _ := srcTrie.Commit(false)
if err := srcTrieDB.Update(rootC, rootB, 0, trienode.NewWithNodeSet(nodesC), nil); err != nil { if err := srcTrieDB.Update(rootC, rootB, 0, trienode.NewWithNodeSet(nodesC), nil); err != nil {
panic(err) panic(err)
} }

View file

@ -16,10 +16,6 @@
package trie package trie
import (
"github.com/ethereum/go-ethereum/common"
)
// tracer tracks the changes of trie nodes. During the trie operations, // tracer tracks the changes of trie nodes. During the trie operations,
// some nodes can be deleted from the trie, while these deleted nodes // some nodes can be deleted from the trie, while these deleted nodes
// won't be captured by trie.Hasher or trie.Committer. Thus, these deleted // won't be captured by trie.Hasher or trie.Committer. Thus, these deleted
@ -33,16 +29,11 @@ import (
// This tool can track all of them no matter the node is embedded in its // This tool can track all of them no matter the node is embedded in its
// parent or not, but valueNode is never tracked. // parent or not, but valueNode is never tracked.
// //
// Besides, it's also used for recording the original value of the nodes
// when they are resolved from the disk. The pre-value of the nodes will
// be used to construct trie history in the future.
//
// Note tracer is not thread-safe, callers should be responsible for handling // Note tracer is not thread-safe, callers should be responsible for handling
// the concurrency issues by themselves. // the concurrency issues by themselves.
type tracer struct { type tracer struct {
inserts map[string]struct{} inserts map[string]struct{}
deletes map[string]struct{} deletes map[string]struct{}
accessList map[string][]byte
} }
// newTracer initializes the tracer for capturing trie changes. // newTracer initializes the tracer for capturing trie changes.
@ -50,17 +41,9 @@ func newTracer() *tracer {
return &tracer{ return &tracer{
inserts: make(map[string]struct{}), inserts: make(map[string]struct{}),
deletes: make(map[string]struct{}), deletes: make(map[string]struct{}),
accessList: make(map[string][]byte),
} }
} }
// onRead tracks the newly loaded trie node and caches the rlp-encoded
// blob internally. Don't change the value outside of function since
// it's not deep-copied.
func (t *tracer) onRead(path []byte, val []byte) {
t.accessList[string(path)] = val
}
// onInsert tracks the newly inserted trie node. If it's already // onInsert tracks the newly inserted trie node. If it's already
// in the deletion set (resurrected node), then just wipe it from // in the deletion set (resurrected node), then just wipe it from
// the deletion set as it's "untouched". // the deletion set as it's "untouched".
@ -83,19 +66,11 @@ func (t *tracer) onDelete(path []byte) {
t.deletes[string(path)] = struct{}{} t.deletes[string(path)] = struct{}{}
} }
// reset clears the content tracked by tracer.
func (t *tracer) reset() {
t.inserts = make(map[string]struct{})
t.deletes = make(map[string]struct{})
t.accessList = make(map[string][]byte)
}
// copy returns a deep copied tracer instance. // copy returns a deep copied tracer instance.
func (t *tracer) copy() *tracer { func (t *tracer) copy() *tracer {
var ( var (
inserts = make(map[string]struct{}) inserts = make(map[string]struct{})
deletes = make(map[string]struct{}) deletes = make(map[string]struct{})
accessList = make(map[string][]byte)
) )
for path := range t.inserts { for path := range t.inserts {
inserts[path] = struct{}{} inserts[path] = struct{}{}
@ -103,27 +78,16 @@ func (t *tracer) copy() *tracer {
for path := range t.deletes { for path := range t.deletes {
deletes[path] = struct{}{} deletes[path] = struct{}{}
} }
for path, blob := range t.accessList {
accessList[path] = common.CopyBytes(blob)
}
return &tracer{ return &tracer{
inserts: inserts, inserts: inserts,
deletes: deletes, deletes: deletes,
accessList: accessList,
} }
} }
// deletedNodes returns a list of node paths which are deleted from the trie. // deleteList returns a list of node paths which are marked as deleted.
func (t *tracer) deletedNodes() []string { func (t *tracer) deleteList() []string {
var paths []string var paths []string
for path := range t.deletes { for path := range t.deletes {
// It's possible a few deleted nodes were embedded
// in their parent before, the deletions can be no
// effect by deleting nothing, filter them out.
_, ok := t.accessList[path]
if !ok {
continue
}
paths = append(paths, path) paths = append(paths, path)
} }
return paths return paths

View file

@ -70,7 +70,7 @@ func testTrieTracer(t *testing.T, vals []struct{ k, v string }) {
} }
insertSet := copySet(trie.tracer.inserts) // copy before commit insertSet := copySet(trie.tracer.inserts) // copy before commit
deleteSet := copySet(trie.tracer.deletes) // copy before commit deleteSet := copySet(trie.tracer.deletes) // copy before commit
root, nodes, _ := trie.Commit(false) root, nodes, _, _ := trie.Commit(false)
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
seen := setKeys(iterNodes(db, root)) seen := setKeys(iterNodes(db, root))
@ -136,7 +136,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
for _, val := range vals { for _, val := range vals {
trie.MustUpdate([]byte(val.k), []byte(val.v)) trie.MustUpdate([]byte(val.k), []byte(val.v))
} }
root, nodes, _ := trie.Commit(false) root, nodes, _, _ := trie.Commit(false)
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
trie, _ = New(TrieID(root), db) trie, _ = New(TrieID(root), db)
@ -151,7 +151,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
for _, val := range vals { for _, val := range vals {
trie.MustUpdate([]byte(val.k), randBytes(32)) trie.MustUpdate([]byte(val.k), randBytes(32))
} }
root, nodes, _ = trie.Commit(false) root, nodes, _, _ = trie.Commit(false)
db.Update(root, parent, 0, trienode.NewWithNodeSet(nodes), nil) db.Update(root, parent, 0, trienode.NewWithNodeSet(nodes), nil)
trie, _ = New(TrieID(root), db) trie, _ = New(TrieID(root), db)
@ -169,7 +169,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
keys = append(keys, string(key)) keys = append(keys, string(key))
trie.MustUpdate(key, randBytes(32)) trie.MustUpdate(key, randBytes(32))
} }
root, nodes, _ = trie.Commit(false) root, nodes, _, _ = trie.Commit(false)
db.Update(root, parent, 0, trienode.NewWithNodeSet(nodes), nil) db.Update(root, parent, 0, trienode.NewWithNodeSet(nodes), nil)
trie, _ = New(TrieID(root), db) trie, _ = New(TrieID(root), db)
@ -184,7 +184,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
for _, key := range keys { for _, key := range keys {
trie.MustUpdate([]byte(key), nil) trie.MustUpdate([]byte(key), nil)
} }
root, nodes, _ = trie.Commit(false) root, nodes, _, _ = trie.Commit(false)
db.Update(root, parent, 0, trienode.NewWithNodeSet(nodes), nil) db.Update(root, parent, 0, trienode.NewWithNodeSet(nodes), nil)
trie, _ = New(TrieID(root), db) trie, _ = New(TrieID(root), db)
@ -199,7 +199,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) {
for _, val := range vals { for _, val := range vals {
trie.MustUpdate([]byte(val.k), nil) trie.MustUpdate([]byte(val.k), nil)
} }
root, nodes, _ = trie.Commit(false) root, nodes, _, _ = trie.Commit(false)
db.Update(root, parent, 0, trienode.NewWithNodeSet(nodes), nil) db.Update(root, parent, 0, trienode.NewWithNodeSet(nodes), nil)
trie, _ = New(TrieID(root), db) trie, _ = New(TrieID(root), db)
@ -218,7 +218,7 @@ func TestAccessListLeak(t *testing.T) {
for _, val := range standard { for _, val := range standard {
trie.MustUpdate([]byte(val.k), []byte(val.v)) trie.MustUpdate([]byte(val.k), []byte(val.v))
} }
root, nodes, _ := trie.Commit(false) root, nodes, _, _ := trie.Commit(false)
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
var cases = []struct { var cases = []struct {
@ -248,9 +248,9 @@ func TestAccessListLeak(t *testing.T) {
} }
for _, c := range cases { for _, c := range cases {
trie, _ = New(TrieID(root), db) trie, _ = New(TrieID(root), db)
n1 := len(trie.tracer.accessList) n1 := trie.witness.Len()
c.op(trie) c.op(trie)
n2 := len(trie.tracer.accessList) n2 := trie.witness.Len()
if n1 != n2 { if n1 != n2 {
t.Fatalf("AccessList is leaked, prev %d after %d", n1, n2) t.Fatalf("AccessList is leaked, prev %d after %d", n1, n2)
@ -268,7 +268,7 @@ func TestTinyTree(t *testing.T) {
for _, val := range tiny { for _, val := range tiny {
trie.MustUpdate([]byte(val.k), randBytes(32)) trie.MustUpdate([]byte(val.k), randBytes(32))
} }
root, set, _ := trie.Commit(false) root, set, _, _ := trie.Commit(false)
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(set), nil) db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(set), nil)
parent := root parent := root
@ -277,7 +277,7 @@ func TestTinyTree(t *testing.T) {
for _, val := range tiny { for _, val := range tiny {
trie.MustUpdate([]byte(val.k), []byte(val.v)) trie.MustUpdate([]byte(val.k), []byte(val.v))
} }
root, set, _ = trie.Commit(false) root, set, _, _ = trie.Commit(false)
db.Update(root, parent, 0, trienode.NewWithNodeSet(set), nil) db.Update(root, parent, 0, trienode.NewWithNodeSet(set), nil)
trie, _ = New(TrieID(root), db) trie, _ = New(TrieID(root), db)

View file

@ -54,6 +54,7 @@ type Trie struct {
// tracer is the tool to track the trie changes. // tracer is the tool to track the trie changes.
// It will be reset after each commit operation. // It will be reset after each commit operation.
tracer *tracer tracer *tracer
witness *trienode.Witness
} }
// newFlag returns the cache flag value for a newly created node. // newFlag returns the cache flag value for a newly created node.
@ -70,6 +71,7 @@ func (t *Trie) Copy() *Trie {
unhashed: t.unhashed, unhashed: t.unhashed,
reader: t.reader, reader: t.reader,
tracer: t.tracer.copy(), tracer: t.tracer.copy(),
witness: t.witness.Copy(),
} }
} }
@ -88,6 +90,7 @@ func New(id *ID, db *Database) (*Trie, error) {
owner: id.Owner, owner: id.Owner,
reader: reader, reader: reader,
tracer: newTracer(), tracer: newTracer(),
witness: trienode.NewWitness(id.Owner),
} }
if id.Root != (common.Hash{}) && id.Root != types.EmptyRootHash { if id.Root != (common.Hash{}) && id.Root != types.EmptyRootHash {
rootnode, err := trie.resolveAndTrack(id.Root[:], nil) rootnode, err := trie.resolveAndTrack(id.Root[:], nil)
@ -589,7 +592,7 @@ func (t *Trie) resolveAndTrack(n hashNode, prefix []byte) (node, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
t.tracer.onRead(prefix, blob) t.witness.Add(string(prefix), blob)
return mustDecodeNode(n, blob), nil return mustDecodeNode(n, blob), nil
} }
@ -607,9 +610,11 @@ func (t *Trie) Hash() common.Hash {
// The returned nodeset can be nil if the trie is clean (nothing to commit). // The returned nodeset can be nil if the trie is clean (nothing to commit).
// Once the trie is committed, it's not usable anymore. A new trie must // Once the trie is committed, it's not usable anymore. A new trie must
// be created with new root and updated trie database for following usage // be created with new root and updated trie database for following usage
func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) { func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, *trienode.Witness, error) {
defer t.tracer.reset() // Reset the trie internal states at the end.
defer func() { defer func() {
t.tracer = newTracer()
t.witness = trienode.NewWitness(t.owner)
t.committed = true t.committed = true
}() }()
// Trie is empty and can be classified into two types of situations: // Trie is empty and can be classified into two types of situations:
@ -617,15 +622,22 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error)
// (b) The trie was non-empty and all nodes are dropped => return // (b) The trie was non-empty and all nodes are dropped => return
// the node set includes all deleted nodes // the node set includes all deleted nodes
if t.root == nil { if t.root == nil {
paths := t.tracer.deletedNodes() // It's possible a few deleted nodes were embedded in their parent before,
// the deletions can be no effect by deleting nothing, filter them out.
var paths []string
for _, p := range t.tracer.deleteList() {
if t.witness.Has(p) {
paths = append(paths, p)
}
}
if len(paths) == 0 { if len(paths) == 0 {
return types.EmptyRootHash, nil, nil // case (a) return types.EmptyRootHash, nil, nil, nil // case (a)
} }
nodes := trienode.NewNodeSet(t.owner) nodes := trienode.NewNodeSet(t.owner)
for _, path := range paths { for _, path := range paths {
nodes.AddNode([]byte(path), trienode.NewDeleted()) nodes.AddNode([]byte(path), trienode.NewDeleted())
} }
return types.EmptyRootHash, nodes, nil // case (b) return types.EmptyRootHash, nodes, t.witness, nil // case (b)
} }
// Derive the hash for all dirty nodes first. We hold the assumption // Derive the hash for all dirty nodes first. We hold the assumption
// in the following procedure that all nodes are hashed. // in the following procedure that all nodes are hashed.
@ -637,14 +649,19 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error)
// Replace the root node with the origin hash in order to // Replace the root node with the origin hash in order to
// ensure all resolved nodes are dropped after the commit. // ensure all resolved nodes are dropped after the commit.
t.root = hashedNode t.root = hashedNode
return rootHash, nil, nil return rootHash, nil, t.witness, nil
} }
nodes := trienode.NewNodeSet(t.owner) nodes := trienode.NewNodeSet(t.owner)
for _, path := range t.tracer.deletedNodes() {
nodes.AddNode([]byte(path), trienode.NewDeleted()) // It's possible a few deleted nodes were embedded in their parent before,
// the deletions can be no effect by deleting nothing, filter them out.
for _, p := range t.tracer.deleteList() {
if t.witness.Has(p) {
nodes.AddNode([]byte(p), trienode.NewDeleted())
} }
t.root = newCommitter(nodes, t.tracer, collectLeaf).Commit(t.root) }
return rootHash, nodes, nil t.root = newCommitter(nodes, t.witness, collectLeaf).Commit(t.root)
return rootHash, nodes, t.witness, nil
} }
// hashRoot calculates the root hash of the given trie // hashRoot calculates the root hash of the given trie
@ -667,6 +684,7 @@ func (t *Trie) Reset() {
t.root = nil t.root = nil
t.owner = common.Hash{} t.owner = common.Hash{}
t.unhashed = 0 t.unhashed = 0
t.tracer.reset() t.tracer = newTracer()
t.witness = trienode.NewWitness(common.Hash{})
t.committed = false t.committed = false
} }

View file

@ -93,7 +93,7 @@ func testMissingNode(t *testing.T, memonly bool, scheme string) {
trie := NewEmpty(triedb) trie := NewEmpty(triedb)
updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer") updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer")
updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf") updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf")
root, nodes, _ := trie.Commit(false) root, nodes, _, _ := trie.Commit(false)
triedb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) triedb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
if !memonly { if !memonly {
@ -182,7 +182,7 @@ func TestInsert(t *testing.T) {
updateString(trie, "A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") updateString(trie, "A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
exp = common.HexToHash("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab") exp = common.HexToHash("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab")
root, _, _ = trie.Commit(false) root, _, _, _ = trie.Commit(false)
if root != exp { if root != exp {
t.Errorf("case 2: exp %x got %x", exp, root) t.Errorf("case 2: exp %x got %x", exp, root)
} }
@ -207,7 +207,7 @@ func TestGet(t *testing.T) {
if i == 1 { if i == 1 {
return return
} }
root, nodes, _ := trie.Commit(false) root, nodes, _, _ := trie.Commit(false)
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
trie, _ = New(TrieID(root), db) trie, _ = New(TrieID(root), db)
} }
@ -279,7 +279,7 @@ func TestReplication(t *testing.T) {
for _, val := range vals { for _, val := range vals {
updateString(trie, val.k, val.v) updateString(trie, val.k, val.v)
} }
root, nodes, _ := trie.Commit(false) root, nodes, _, _ := trie.Commit(false)
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
// create a new trie on top of the database and check that lookups work. // create a new trie on top of the database and check that lookups work.
@ -292,7 +292,7 @@ func TestReplication(t *testing.T) {
t.Errorf("trie2 doesn't have %q => %q", kv.k, kv.v) t.Errorf("trie2 doesn't have %q => %q", kv.k, kv.v)
} }
} }
hash, nodes, _ := trie2.Commit(false) hash, nodes, _, _ := trie2.Commit(false)
if hash != root { if hash != root {
t.Errorf("root failure. expected %x got %x", root, hash) t.Errorf("root failure. expected %x got %x", root, hash)
} }
@ -506,7 +506,7 @@ func runRandTest(rt randTest) bool {
case opHash: case opHash:
tr.Hash() tr.Hash()
case opCommit: case opCommit:
root, nodes, _ := tr.Commit(true) root, nodes, _, _ := tr.Commit(true)
if nodes != nil { if nodes != nil {
triedb.Update(root, origin, 0, trienode.NewWithNodeSet(nodes), nil) triedb.Update(root, origin, 0, trienode.NewWithNodeSet(nodes), nil)
} }
@ -743,7 +743,7 @@ func TestCommitAfterHash(t *testing.T) {
if exp != root { if exp != root {
t.Errorf("got %x, exp %x", root, exp) t.Errorf("got %x, exp %x", root, exp)
} }
root, _, _ = trie.Commit(false) root, _, _, _ = trie.Commit(false)
if exp != root { if exp != root {
t.Errorf("got %x, exp %x", root, exp) t.Errorf("got %x, exp %x", root, exp)
} }
@ -852,7 +852,7 @@ func TestCommitSequence(t *testing.T) {
trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i])
} }
// Flush trie -> database // Flush trie -> database
root, nodes, _ := trie.Commit(false) root, nodes, _, _ := trie.Commit(false)
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
// Flush memdb -> disk (sponge) // Flush memdb -> disk (sponge)
db.Commit(root, false) db.Commit(root, false)
@ -893,7 +893,7 @@ func TestCommitSequenceRandomBlobs(t *testing.T) {
trie.MustUpdate(key, val) trie.MustUpdate(key, val)
} }
// Flush trie -> database // Flush trie -> database
root, nodes, _ := trie.Commit(false) root, nodes, _, _ := trie.Commit(false)
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
// Flush memdb -> disk (sponge) // Flush memdb -> disk (sponge)
db.Commit(root, false) db.Commit(root, false)
@ -932,7 +932,7 @@ func TestCommitSequenceStackTrie(t *testing.T) {
stTrie.Update(key, val) stTrie.Update(key, val)
} }
// Flush trie -> database // Flush trie -> database
root, nodes, _ := trie.Commit(false) root, nodes, _, _ := trie.Commit(false)
// Flush memdb -> disk (sponge) // Flush memdb -> disk (sponge)
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
db.Commit(root, false) db.Commit(root, false)
@ -980,7 +980,7 @@ func TestCommitSequenceSmallRoot(t *testing.T) {
trie.Update(key, []byte{0x1}) trie.Update(key, []byte{0x1})
stTrie.Update(key, []byte{0x1}) stTrie.Update(key, []byte{0x1})
// Flush trie -> database // Flush trie -> database
root, nodes, _ := trie.Commit(false) root, nodes, _, _ := trie.Commit(false)
// Flush memdb -> disk (sponge) // Flush memdb -> disk (sponge)
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
db.Commit(root, false) db.Commit(root, false)
@ -1153,7 +1153,7 @@ func benchmarkDerefRootFixedSize(b *testing.B, addresses [][20]byte, accounts []
trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i])
} }
h := trie.Hash() h := trie.Hash()
root, nodes, _ := trie.Commit(false) root, nodes, _, _ := trie.Commit(false)
triedb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) triedb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
b.StartTimer() b.StartTimer()
triedb.Dereference(h) triedb.Dereference(h)

View file

@ -46,7 +46,7 @@ func updateTrie(addrHash common.Hash, root common.Hash, dirties, cleans map[comm
h.Update(key.Bytes(), val) h.Update(key.Bytes(), val)
} }
} }
root, nodes, _ := h.Commit(false) root, nodes, _, _ := h.Commit(false)
return root, nodes return root, nodes
} }

View file

@ -80,7 +80,7 @@ func (h *testHasher) Delete(key []byte) error {
// Commit computes the new hash of the states and returns the set with all // Commit computes the new hash of the states and returns the set with all
// state changes. // state changes.
func (h *testHasher) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) { func (h *testHasher) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, *trienode.Witness, error) {
var ( var (
nodes = make(map[common.Hash][]byte) nodes = make(map[common.Hash][]byte)
set = trienode.NewNodeSet(h.owner) set = trienode.NewNodeSet(h.owner)
@ -108,7 +108,7 @@ func (h *testHasher) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, e
if root == types.EmptyRootHash && h.root != types.EmptyRootHash { if root == types.EmptyRootHash && h.root != types.EmptyRootHash {
set.AddNode(nil, trienode.NewDeleted()) set.AddNode(nil, trienode.NewDeleted())
} }
return root, set, nil return root, set, nil, nil
} }
// hash performs the hash computation upon the provided states. // hash performs the hash computation upon the provided states.

61
trie/trienode/witness.go Normal file
View file

@ -0,0 +1,61 @@
// Copyright 2023 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/
package trienode
import "github.com/ethereum/go-ethereum/common"
// Witness is the set of nodes retrieved from the database for executing a state
// transition. It can be considered as the previous state for the state transition,
// effectively serving as the witness for that transition.
type Witness struct {
Owner common.Hash
Nodes map[string][]byte
}
// NewWitness constructs a witness structure.
func NewWitness(owner common.Hash) *Witness {
return &Witness{Owner: owner, Nodes: make(map[string][]byte)}
}
// Add tracks the node resolved from database. Don't change the blob outside of
// function since it's not deep-copied.
func (w *Witness) Add(path string, blob []byte) {
w.Nodes[path] = common.CopyBytes(blob)
}
// Has returns the indicator whether the specified node is in witness.
func (w *Witness) Has(path string) bool {
_, ok := w.Nodes[path]
return ok
}
// Len returns the number of nodes resolved in the witness.
func (w *Witness) Len() int {
return len(w.Nodes)
}
// Copy returns a deep copied witness structure.
func (w *Witness) Copy() *Witness {
cpy := &Witness{
Owner: w.Owner,
Nodes: make(map[string][]byte),
}
for p, n := range w.Nodes {
cpy.Nodes[p] = n // it's not deep-copied
}
return cpy
}

View file

@ -43,7 +43,7 @@ type Trie interface {
// Commit the trie and returns a set of dirty nodes generated along with // Commit the trie and returns a set of dirty nodes generated along with
// the new root hash. // the new root hash.
Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, *trienode.Witness, error)
} }
// TrieLoader wraps functions to load tries. // TrieLoader wraps functions to load tries.
@ -129,7 +129,7 @@ func Apply(prevRoot common.Hash, postRoot common.Hash, accounts map[common.Addre
return nil, fmt.Errorf("failed to revert state, err: %w", err) return nil, fmt.Errorf("failed to revert state, err: %w", err)
} }
} }
root, result, err := tr.Commit(false) root, result, _, err := tr.Commit(false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -184,7 +184,7 @@ func updateAccount(ctx *context, loader TrieLoader, addr common.Address) error {
return err return err
} }
} }
root, result, err := st.Commit(false) root, result, _, err := st.Commit(false)
if err != nil { if err != nil {
return err return err
} }
@ -238,7 +238,7 @@ func deleteAccount(ctx *context, loader TrieLoader, addr common.Address) error {
return err return err
} }
} }
root, result, err := st.Commit(false) root, result, _, err := st.Commit(false)
if err != nil { if err != nil {
return err return err
} }