Skip to content

Commit 8629c58

Browse files
committed
all: rework trie and trie committer
1 parent d804a59 commit 8629c58

24 files changed

+723
-310
lines changed

core/state/database.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,11 @@ type Trie interface {
8888
// can be used even if the trie doesn't have one.
8989
Hash() common.Hash
9090

91-
// Commit writes all nodes to the trie's memory database, tracking the internal
92-
// and external (for account tries) references.
93-
Commit(onleaf trie.LeafCallback) (common.Hash, int, error)
91+
// Commit collects all dirty nodes in the trie and replace them with the
92+
// corresponding node hash. All collected nodes(including dirty leaves if
93+
// collectLeaf is true) will be encapsulated into a nodeset for return.
94+
// The returned nodeset can be nil if the trie is clean(nothing to commit).
95+
Commit(collectLeaf bool) (common.Hash, *trie.NodeSet, error)
9496

9597
// NodeIterator returns an iterator that returns nodes of the trie. Iteration
9698
// starts at the key after the given start key.

core/state/snapshot/generate.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,10 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, owner common.Hash, roo
367367
for i, key := range result.keys {
368368
snapTrie.Update(key, result.vals[i])
369369
}
370-
root, _, _ := snapTrie.Commit(nil)
370+
root, nodes, _ := snapTrie.Commit(false)
371+
if nodes != nil {
372+
snapTrieDb.Update(trie.NewWithNodeSet(nodes))
373+
}
371374
snapTrieDb.Commit(root, false, nil)
372375
}
373376
// Construct the trie for state iteration, reuse the trie

core/state/snapshot/generate_test.go

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ type testHelper struct {
143143
diskdb ethdb.Database
144144
triedb *trie.Database
145145
accTrie *trie.SecureTrie
146+
nodes *trie.MergedNodeSet
146147
}
147148

148149
func newHelper() *testHelper {
@@ -153,6 +154,7 @@ func newHelper() *testHelper {
153154
diskdb: diskdb,
154155
triedb: triedb,
155156
accTrie: accTrie,
157+
nodes: trie.NewMergedNodeSet(),
156158
}
157159
}
158160

@@ -184,17 +186,22 @@ func (t *testHelper) makeStorageTrie(stateRoot, owner common.Hash, keys []string
184186
for i, k := range keys {
185187
stTrie.Update([]byte(k), []byte(vals[i]))
186188
}
187-
var root common.Hash
188189
if !commit {
189-
root = stTrie.Hash()
190-
} else {
191-
root, _, _ = stTrie.Commit(nil)
190+
return stTrie.Hash().Bytes()
191+
}
192+
root, nodes, _ := stTrie.Commit(false)
193+
if nodes != nil {
194+
t.nodes.Merge(nodes)
192195
}
193196
return root.Bytes()
194197
}
195198

196199
func (t *testHelper) Commit() common.Hash {
197-
root, _, _ := t.accTrie.Commit(nil)
200+
root, nodes, _ := t.accTrie.Commit(false)
201+
if nodes != nil {
202+
t.nodes.Merge(nodes)
203+
}
204+
t.triedb.Update(t.nodes)
198205
t.triedb.Commit(root, false, nil)
199206
return root
200207
}
@@ -378,7 +385,7 @@ func TestGenerateCorruptAccountTrie(t *testing.T) {
378385
helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7
379386
helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) // 0x19ead688e907b0fab07176120dceec244a72aff2f0aa51e8b827584e378772f4
380387

381-
root, _, _ := helper.accTrie.Commit(nil) // Root: 0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978
388+
root, _, _ := helper.accTrie.Commit(false) // Root: 0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978
382389

383390
// Delete an account trie leaf and ensure the generator chokes
384391
helper.triedb.Commit(root, false, nil)
@@ -413,7 +420,7 @@ func TestGenerateMissingStorageTrie(t *testing.T) {
413420
helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7
414421
stRoot = helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
415422
helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: emptyCode.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2
416-
root, _, _ := helper.accTrie.Commit(nil)
423+
root, _, _ := helper.accTrie.Commit(false)
417424

418425
// We can only corrupt the disk database, so flush the tries out
419426
helper.triedb.Reference(
@@ -458,7 +465,7 @@ func TestGenerateCorruptStorageTrie(t *testing.T) {
458465
stRoot = helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
459466
helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: emptyCode.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2
460467

461-
root, _, _ := helper.accTrie.Commit(nil)
468+
root, _, _ := helper.accTrie.Commit(false)
462469

463470
// We can only corrupt the disk database, so flush the tries out
464471
helper.triedb.Reference(
@@ -825,10 +832,12 @@ func populateDangling(disk ethdb.KeyValueStore) {
825832
// This test will populate some dangling storages to see if they can be cleaned up.
826833
func TestGenerateCompleteSnapshotWithDanglingStorage(t *testing.T) {
827834
var helper = newHelper()
828-
stRoot := helper.makeStorageTrie(common.Hash{}, common.Hash{}, []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
829835

836+
stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
830837
helper.addAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
831838
helper.addAccount("acc-2", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()})
839+
840+
helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
832841
helper.addAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
833842

834843
helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
@@ -858,10 +867,12 @@ func TestGenerateCompleteSnapshotWithDanglingStorage(t *testing.T) {
858867
// This test will populate some dangling storages to see if they can be cleaned up.
859868
func TestGenerateBrokenSnapshotWithDanglingStorage(t *testing.T) {
860869
var helper = newHelper()
861-
stRoot := helper.makeStorageTrie(common.Hash{}, common.Hash{}, []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
862870

871+
stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
863872
helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
864873
helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()})
874+
875+
helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
865876
helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: emptyCode.Bytes()})
866877

867878
populateDangling(helper.diskdb)

core/state/state_object.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"github.com/ethereum/go-ethereum/crypto"
2929
"github.com/ethereum/go-ethereum/metrics"
3030
"github.com/ethereum/go-ethereum/rlp"
31+
"github.com/ethereum/go-ethereum/trie"
3132
)
3233

3334
var emptyCodeHash = crypto.Keccak256(nil)
@@ -375,23 +376,23 @@ func (s *stateObject) updateRoot(db Database) {
375376

376377
// CommitTrie the storage trie of the object to db.
377378
// This updates the trie root.
378-
func (s *stateObject) CommitTrie(db Database) (int, error) {
379+
func (s *stateObject) CommitTrie(db Database) (*trie.NodeSet, error) {
379380
// If nothing changed, don't bother with hashing anything
380381
if s.updateTrie(db) == nil {
381-
return 0, nil
382+
return nil, nil
382383
}
383384
if s.dbErr != nil {
384-
return 0, s.dbErr
385+
return nil, s.dbErr
385386
}
386387
// Track the amount of time wasted on committing the storage trie
387388
if metrics.EnabledExpensive {
388389
defer func(start time.Time) { s.db.StorageCommits += time.Since(start) }(time.Now())
389390
}
390-
root, committed, err := s.trie.Commit(nil)
391+
root, nodes, err := s.trie.Commit(false)
391392
if err == nil {
392393
s.data.Root = root
393394
}
394-
return committed, err
395+
return nodes, err
395396
}
396397

397398
// AddBalance adds amount to s's balance.

core/state/statedb.go

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -907,7 +907,11 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
907907
s.IntermediateRoot(deleteEmptyObjects)
908908

909909
// Commit objects to the trie, measuring the elapsed time
910-
var storageCommitted int
910+
var (
911+
accounts int
912+
storages int
913+
nodes = trie.NewMergedNodeSet()
914+
)
911915
codeWriter := s.db.TrieDB().DiskDB().NewBatch()
912916
for addr := range s.stateObjectsDirty {
913917
if obj := s.stateObjects[addr]; !obj.deleted {
@@ -917,11 +921,17 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
917921
obj.dirtyCode = false
918922
}
919923
// Write any storage changes in the state object to its storage trie
920-
committed, err := obj.CommitTrie(s.db)
924+
set, err := obj.CommitTrie(s.db)
921925
if err != nil {
922926
return common.Hash{}, err
923927
}
924-
storageCommitted += committed
928+
// Merge the dirty nodes of storage trie into global set
929+
if set != nil {
930+
if err := nodes.Merge(set); err != nil {
931+
return common.Hash{}, err
932+
}
933+
storages += set.Len()
934+
}
925935
}
926936
}
927937
if len(s.stateObjectsDirty) > 0 {
@@ -937,30 +947,26 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
937947
if metrics.EnabledExpensive {
938948
start = time.Now()
939949
}
940-
// The onleaf func is called _serially_, so we can reuse the same account
941-
// for unmarshalling every time.
942-
var account types.StateAccount
943-
root, accountCommitted, err := s.trie.Commit(func(_ [][]byte, _ []byte, leaf []byte, parent common.Hash, _ []byte) error {
944-
if err := rlp.DecodeBytes(leaf, &account); err != nil {
945-
return nil
946-
}
947-
if account.Root != emptyRoot {
948-
s.db.TrieDB().Reference(account.Root, parent)
949-
}
950-
return nil
951-
})
950+
root, set, err := s.trie.Commit(true)
952951
if err != nil {
953952
return common.Hash{}, err
954953
}
954+
// Merge the dirty nodes of account trie into global set
955+
if set != nil {
956+
if err := nodes.Merge(set); err != nil {
957+
return common.Hash{}, err
958+
}
959+
accounts = set.Len()
960+
}
955961
if metrics.EnabledExpensive {
956962
s.AccountCommits += time.Since(start)
957963

958964
accountUpdatedMeter.Mark(int64(s.AccountUpdated))
959965
storageUpdatedMeter.Mark(int64(s.StorageUpdated))
960966
accountDeletedMeter.Mark(int64(s.AccountDeleted))
961967
storageDeletedMeter.Mark(int64(s.StorageDeleted))
962-
accountCommittedMeter.Mark(int64(accountCommitted))
963-
storageCommittedMeter.Mark(int64(storageCommitted))
968+
accountCommittedMeter.Mark(int64(accounts))
969+
storageCommittedMeter.Mark(int64(storages))
964970
s.AccountUpdated, s.AccountDeleted = 0, 0
965971
s.StorageUpdated, s.StorageDeleted = 0, 0
966972
}
@@ -984,6 +990,9 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
984990
}
985991
s.snap, s.snapDestructs, s.snapAccounts, s.snapStorage = nil, nil, nil, nil
986992
}
993+
if err := s.db.TrieDB().Update(nodes); err != nil {
994+
return common.Hash{}, err
995+
}
987996
s.originalRoot = root
988997
return root, err
989998
}

eth/protocols/snap/sync_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,7 +1364,7 @@ func makeAccountTrieNoStorage(n int) (*trie.Trie, entrySlice) {
13641364
entries = append(entries, elem)
13651365
}
13661366
sort.Sort(entries)
1367-
accTrie.Commit(nil)
1367+
accTrie.Commit(false)
13681368
return accTrie, entries
13691369
}
13701370

@@ -1420,7 +1420,7 @@ func makeBoundaryAccountTrie(n int) (*trie.Trie, entrySlice) {
14201420
entries = append(entries, elem)
14211421
}
14221422
sort.Sort(entries)
1423-
trie.Commit(nil)
1423+
trie.Commit(false)
14241424
return trie, entries
14251425
}
14261426

@@ -1444,7 +1444,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool)
14441444
// Create a storage trie
14451445
stTrie, stEntries := makeStorageTrieWithSeed(common.BytesToHash(key), uint64(slots), i, db)
14461446
stRoot := stTrie.Hash()
1447-
stTrie.Commit(nil)
1447+
stTrie.Commit(false)
14481448
value, _ := rlp.EncodeToBytes(&types.StateAccount{
14491449
Nonce: i,
14501450
Balance: big.NewInt(int64(i)),
@@ -1460,7 +1460,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool)
14601460
}
14611461
sort.Sort(entries)
14621462

1463-
accTrie.Commit(nil)
1463+
accTrie.Commit(false)
14641464
return accTrie, entries, storageTries, storageEntries
14651465
}
14661466

@@ -1491,7 +1491,7 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (*trie
14911491
stTrie, stEntries = makeStorageTrieWithSeed(common.BytesToHash(key), uint64(slots), 0, db)
14921492
}
14931493
stRoot := stTrie.Hash()
1494-
stTrie.Commit(nil)
1494+
stTrie.Commit(false)
14951495

14961496
value, _ := rlp.EncodeToBytes(&types.StateAccount{
14971497
Nonce: i,
@@ -1507,7 +1507,7 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (*trie
15071507
storageEntries[common.BytesToHash(key)] = stEntries
15081508
}
15091509
sort.Sort(entries)
1510-
accTrie.Commit(nil)
1510+
accTrie.Commit(false)
15111511
return accTrie, entries, storageTries, storageEntries
15121512
}
15131513

@@ -1530,7 +1530,7 @@ func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Databas
15301530
entries = append(entries, elem)
15311531
}
15321532
sort.Sort(entries)
1533-
trie.Commit(nil)
1533+
trie.Commit(false)
15341534
return trie, entries
15351535
}
15361536

@@ -1581,7 +1581,7 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (*trie
15811581
entries = append(entries, elem)
15821582
}
15831583
sort.Sort(entries)
1584-
trie.Commit(nil)
1584+
trie.Commit(false)
15851585
return trie, entries
15861586
}
15871587

light/postprocess.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,10 +217,15 @@ func (c *ChtIndexerBackend) Process(ctx context.Context, header *types.Header) e
217217

218218
// Commit implements core.ChainIndexerBackend
219219
func (c *ChtIndexerBackend) Commit() error {
220-
root, _, err := c.trie.Commit(nil)
220+
root, nodes, err := c.trie.Commit(false)
221221
if err != nil {
222222
return err
223223
}
224+
if nodes != nil {
225+
if err := c.triedb.Update(trie.NewWithNodeSet(nodes)); err != nil {
226+
return err
227+
}
228+
}
224229
// Pruning historical trie nodes if necessary.
225230
if !c.disablePruning {
226231
// Flush the triedb and track the latest trie nodes.
@@ -453,10 +458,15 @@ func (b *BloomTrieIndexerBackend) Commit() error {
453458
b.trie.Delete(encKey[:])
454459
}
455460
}
456-
root, _, err := b.trie.Commit(nil)
461+
root, nodes, err := b.trie.Commit(false)
457462
if err != nil {
458463
return err
459464
}
465+
if nodes != nil {
466+
if err := b.triedb.Update(trie.NewWithNodeSet(nodes)); err != nil {
467+
return err
468+
}
469+
}
460470
// Pruning historical trie nodes if necessary.
461471
if !b.disablePruning {
462472
// Flush the triedb and track the latest trie nodes.

light/trie.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,11 @@ func (t *odrTrie) TryDelete(key []byte) error {
137137
})
138138
}
139139

140-
func (t *odrTrie) Commit(onleaf trie.LeafCallback) (common.Hash, int, error) {
140+
func (t *odrTrie) Commit(collectLeaf bool) (common.Hash, *trie.NodeSet, error) {
141141
if t.trie == nil {
142-
return t.id.Root, 0, nil
142+
return t.id.Root, nil, nil
143143
}
144-
return t.trie.Commit(onleaf)
144+
return t.trie.Commit(collectLeaf)
145145
}
146146

147147
func (t *odrTrie) Hash() common.Hash {

tests/fuzzers/stacktrie/trie_fuzzer.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,13 @@ func (f *fuzzer) fuzz() int {
173173
return 0
174174
}
175175
// Flush trie -> database
176-
rootA, _, err := trieA.Commit(nil)
176+
rootA, nodes, err := trieA.Commit(false)
177177
if err != nil {
178178
panic(err)
179179
}
180+
if nodes != nil {
181+
dbA.Update(trie.NewWithNodeSet(nodes))
182+
}
180183
// Flush memdb -> disk (sponge)
181184
dbA.Commit(rootA, false, nil)
182185

0 commit comments

Comments
 (0)