core/state/snapshot: handle deleted accounts in fast iterator

This commit is contained in:
Martin Holst Swende
2020-03-04 13:38:55 +01:00
committed by GitHub
parent 328de180a7
commit eff7cfbb03
2 changed files with 78 additions and 9 deletions

View File

@ -130,9 +130,13 @@ func verifyIterator(t *testing.T, expCount int, it AccountIterator) {
last = common.Hash{}
)
for it.Next() {
if hash := it.Hash(); bytes.Compare(last[:], hash[:]) >= 0 {
hash := it.Hash()
if bytes.Compare(last[:], hash[:]) >= 0 {
t.Errorf("wrong order: %x >= %x", last, hash)
}
if it.Account() == nil {
t.Errorf("iterator returned nil-value for hash %x", hash)
}
count++
}
if count != expCount {
@ -377,6 +381,53 @@ func TestAccountIteratorSeek(t *testing.T) {
verifyIterator(t, 0, it) // expected: nothing
}
// TestIteratorDeletions tests that the iterator behaves correct when there are
// deleted accounts (where the Account() value is nil). The iterator
// should not output any accounts or nil-values for those cases.
func TestIteratorDeletions(t *testing.T) {
// Create an empty base layer and a snapshot tree out of it
base := &diskLayer{
diskdb: rawdb.NewMemoryDatabase(),
root: common.HexToHash("0x01"),
cache: fastcache.New(1024 * 500),
}
snaps := &Tree{
layers: map[common.Hash]snapshot{
base.root: base,
},
}
// Stack three diff layers on top with various overlaps
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"),
randomAccountSet("0x11", "0x22", "0x33"), nil)
set := randomAccountSet("0x11", "0x22", "0x33")
deleted := common.HexToHash("0x22")
set[deleted] = nil
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), set, nil)
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"),
randomAccountSet("0x33", "0x44", "0x55"), nil)
// The output should be 11,33,44,55
it, _ := snaps.AccountIterator(common.HexToHash("0x04"), common.Hash{})
// Do a quick check
verifyIterator(t, 4, it)
it.Release()
// And a more detailed verification that we indeed do not see '0x22'
it, _ = snaps.AccountIterator(common.HexToHash("0x04"), common.Hash{})
defer it.Release()
for it.Next() {
hash := it.Hash()
if it.Account() == nil {
t.Errorf("iterator returned nil-value for hash %x", hash)
}
if hash == deleted {
t.Errorf("expected deleted elem %x to not be returned by iterator", deleted)
}
}
}
// BenchmarkAccountIteratorTraversal is a bit a bit notorious -- all layers contain the
// exact same 200 accounts. That means that we need to process 2000 items, but
// only spit out 200 values eventually.