Skip to content

Commit 5758d1f

Browse files
committed
core/state, trie: fix trie flush order for proper pruning
1 parent 81bd998 commit 5758d1f

File tree

2 files changed

+56
-3
lines changed

2 files changed

+56
-3
lines changed

core/state/statedb_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -914,3 +914,43 @@ func TestStateDBAccessList(t *testing.T) {
914914
t.Fatalf("expected empty, got %d", got)
915915
}
916916
}
917+
918+
// Tests that account and storage tries are flushed in the correct order and that
919+
// no data loss occurs.
920+
func TestFlushOrderDataLoss(t *testing.T) {
921+
// Create a state trie with many accounts and slots
922+
var (
923+
memdb = rawdb.NewMemoryDatabase()
924+
statedb = NewDatabase(memdb)
925+
state, _ = New(common.Hash{}, statedb, nil)
926+
)
927+
for a := byte(0); a < 10; a++ {
928+
state.CreateAccount(common.Address{a})
929+
for s := byte(0); s < 10; s++ {
930+
state.SetState(common.Address{a}, common.Hash{a, s}, common.Hash{a, s})
931+
}
932+
}
933+
root, err := state.Commit(false)
934+
if err != nil {
935+
t.Fatalf("failed to commit state trie: %v", err)
936+
}
937+
statedb.TrieDB().Reference(root, common.Hash{})
938+
if err := statedb.TrieDB().Cap(1024); err != nil {
939+
t.Fatalf("failed to cap trie dirty cache: %v", err)
940+
}
941+
if err := statedb.TrieDB().Commit(root, false, nil); err != nil {
942+
t.Fatalf("failed to commit state trie: %v", err)
943+
}
944+
// Reopen the state trie from flushed disk and verify it
945+
state, err = New(root, NewDatabase(memdb), nil)
946+
if err != nil {
947+
t.Fatalf("failed to reopen state trie: %v", err)
948+
}
949+
for a := byte(0); a < 10; a++ {
950+
for s := byte(0); s < 10; s++ {
951+
if have := state.GetState(common.Address{a}, common.Hash{a, s}); have != (common.Hash{a, s}) {
952+
t.Errorf("account %d: slot %d: state mismatch: have %x, want %x", a, s, have, common.Hash{a, s})
953+
}
954+
}
955+
}
956+
}

trie/database.go

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -776,9 +776,22 @@ func (db *Database) Update(nodes *MergedNodeSet) error {
776776

777777
// Insert dirty nodes into the database. In the same tree, it must be
778778
// ensured that children are inserted first, then parent so that children
779-
// can be linked with their parent correctly. The order of writing between
780-
// different tries(account trie, storage tries) is not required.
781-
for owner, subset := range nodes.sets {
779+
// can be linked with their parent correctly.
780+
//
781+
// Note, the storage tries must be flushed before the account trie to
782+
// retain the invariant that children go into the dirty cache first.
783+
var order []common.Hash
784+
for owner := range nodes.sets {
785+
if owner == (common.Hash{}) {
786+
continue
787+
}
788+
order = append(order, owner)
789+
}
790+
if _, ok := nodes.sets[common.Hash{}]; ok {
791+
order = append(order, common.Hash{})
792+
}
793+
for _, owner := range order {
794+
subset := nodes.sets[owner]
782795
for _, path := range subset.paths {
783796
n, ok := subset.nodes[path]
784797
if !ok {

0 commit comments

Comments
 (0)