Skip to content

Commit f2701c8

Browse files
committed
core/state/snapshot: properly clean up storage of deleted accounts
1 parent 7e04d4e commit f2701c8

File tree

2 files changed

+72
-3
lines changed

2 files changed

+72
-3
lines changed

core/state/snapshot/generate.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ func (dl *diskLayer) proveRange(root common.Hash, prefix []byte, kind string, or
240240
for iter.Next() {
241241
key := iter.Key()
242242
if len(key) != len(prefix)+common.HashLength {
243+
// TODO! Why is this check neeed?
243244
panic("remove this panic later on")
244245
}
245246
if len(keys) == max {
@@ -384,7 +385,7 @@ func (dl *diskLayer) genRange(root common.Hash, prefix []byte, kind string, orig
384385
for len(kvkeys) > 0 {
385386
if cmp := bytes.Compare(kvkeys[0], iter.Key); cmp < 0 {
386387
// delete the key
387-
if err := onState(kvkeys[0], kvvals[0], false, true); err != nil {
388+
if err := onState(kvkeys[0], nil, false, true); err != nil {
388389
return false, nil, err
389390
}
390391
kvkeys = kvkeys[1:]
@@ -411,8 +412,8 @@ func (dl *diskLayer) genRange(root common.Hash, prefix []byte, kind string, orig
411412
return false, nil, iter.Err
412413
}
413414
// Delete all stale snapshot states remaining
414-
for i := 0; i < len(kvkeys); i++ {
415-
if err := onState(kvkeys[i], kvvals[i], false, true); err != nil {
415+
for _, key := range kvkeys {
416+
if err := onState(key, nil, false, true); err != nil {
416417
return false, nil, err
417418
}
418419
deleted += 1
@@ -480,6 +481,12 @@ func (dl *diskLayer) generate(stats *generatorStats) {
480481
accountHash := common.BytesToHash(key)
481482
if delete {
482483
rawdb.DeleteAccountSnapshot(batch, accountHash)
484+
// We also need to ensure that any previous snapshot
485+
prefix := append(rawdb.SnapshotStoragePrefix, accountHash.Bytes()...)
486+
keyLen := len(rawdb.SnapshotStoragePrefix) + 2*common.HashLength
487+
if err := wipeKeyRange(dl.diskdb, "storage", prefix, nil, nil, keyLen, snapWipedStorageMeter, false); err != nil {
488+
return err
489+
}
483490
return nil
484491
}
485492
// Retrieve the current account and flatten it into the internal format

core/state/snapshot/generate_test.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package snapshot
1818

1919
import (
20+
"fmt"
2021
"github.com/ethereum/go-ethereum/log"
2122
"math/big"
2223
"os"
@@ -426,3 +427,64 @@ func TestGenerateCorruptStorageTrie(t *testing.T) {
426427
snap.genAbort <- stop
427428
<-stop
428429
}
430+
431+
func getStorageTrie(n int, triedb *trie.Database) *trie.SecureTrie {
432+
stTrie, _ := trie.NewSecure(common.Hash{}, triedb)
433+
for i := 0; i < n; i++ {
434+
k := fmt.Sprintf("key-%d", i)
435+
v := fmt.Sprintf("val-%d", i)
436+
stTrie.Update([]byte(k), []byte(v))
437+
}
438+
stTrie.Commit(nil)
439+
return stTrie
440+
}
441+
442+
// Tests that snapshot generation when an extra account with storage exists in the snap state.
443+
func TestGenerateWithExtraAccounts(t *testing.T) {
444+
445+
var (
446+
diskdb = memorydb.New()
447+
triedb = trie.NewDatabase(diskdb)
448+
stTrie = getStorageTrie(5, triedb)
449+
)
450+
accTrie, _ := trie.NewSecure(common.Hash{}, triedb)
451+
{ // Account one in the trie
452+
acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()}
453+
val, _ := rlp.EncodeToBytes(acc)
454+
accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
455+
// Identical in the snap
456+
rawdb.WriteAccountSnapshot(diskdb, hashData([]byte("acc-1")), val)
457+
rawdb.WriteStorageSnapshot(diskdb, hashData([]byte("acc-1")), hashData([]byte("key-1")), []byte("val-1"))
458+
rawdb.WriteStorageSnapshot(diskdb, hashData([]byte("acc-1")), hashData([]byte("key-2")), []byte("val-2"))
459+
rawdb.WriteStorageSnapshot(diskdb, hashData([]byte("acc-1")), hashData([]byte("key-3")), []byte("val-3"))
460+
}
461+
{ // Account two exists only in the snapshot
462+
acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()}
463+
val, _ := rlp.EncodeToBytes(acc)
464+
rawdb.WriteAccountSnapshot(diskdb, hashData([]byte("acc-2")), val)
465+
rawdb.WriteStorageSnapshot(diskdb, hashData([]byte("acc-2")), hashData([]byte("b-key-1")), []byte("b-val-1"))
466+
rawdb.WriteStorageSnapshot(diskdb, hashData([]byte("acc-2")), hashData([]byte("b-key-2")), []byte("b-val-2"))
467+
rawdb.WriteStorageSnapshot(diskdb, hashData([]byte("acc-2")), hashData([]byte("b-key-3")), []byte("b-val-3"))
468+
}
469+
root, _ := accTrie.Commit(nil)
470+
t.Logf("root: %x", root)
471+
triedb.Commit(root, false, nil)
472+
473+
snap := generateSnapshot(diskdb, triedb, 16, root)
474+
select {
475+
case <-snap.genPending:
476+
// Snapshot generation succeeded
477+
478+
case <-time.After(250 * time.Millisecond):
479+
t.Errorf("Snapshot generation failed")
480+
}
481+
checkSnapRoot(t, snap, root)
482+
// Signal abortion to the generator and wait for it to tear down
483+
stop := make(chan *generatorStats)
484+
snap.genAbort <- stop
485+
<-stop
486+
// If we now inspect the snap db, there should exist no extraneous storage items
487+
if data := rawdb.ReadStorageSnapshot(diskdb, hashData([]byte("acc-2")), hashData([]byte("b-key-1"))); data != nil {
488+
t.Fatalf("expected slot to be removed, got %v", string(data))
489+
}
490+
}

0 commit comments

Comments
 (0)