core/state: extend snapshotter to handle account resurrections
This commit is contained in:
@ -28,18 +28,23 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
)
|
||||
|
||||
// TestIteratorBasics tests some simple single-layer iteration
|
||||
func TestIteratorBasics(t *testing.T) {
|
||||
// TestAccountIteratorBasics tests some simple single-layer iteration
|
||||
func TestAccountIteratorBasics(t *testing.T) {
|
||||
var (
|
||||
accounts = make(map[common.Hash][]byte)
|
||||
storage = make(map[common.Hash]map[common.Hash][]byte)
|
||||
destructs = make(map[common.Hash]struct{})
|
||||
accounts = make(map[common.Hash][]byte)
|
||||
storage = make(map[common.Hash]map[common.Hash][]byte)
|
||||
)
|
||||
// Fill up a parent
|
||||
for i := 0; i < 100; i++ {
|
||||
h := randomHash()
|
||||
data := randomAccount()
|
||||
|
||||
accounts[h] = data
|
||||
if rand.Intn(20) < 10 {
|
||||
if rand.Intn(4) == 0 {
|
||||
destructs[h] = struct{}{}
|
||||
}
|
||||
if rand.Intn(2) == 0 {
|
||||
accStorage := make(map[common.Hash][]byte)
|
||||
value := make([]byte, 32)
|
||||
rand.Read(value)
|
||||
@ -48,7 +53,7 @@ func TestIteratorBasics(t *testing.T) {
|
||||
}
|
||||
}
|
||||
// Add some (identical) layers on top
|
||||
parent := newDiffLayer(emptyLayer(), common.Hash{}, accounts, storage)
|
||||
parent := newDiffLayer(emptyLayer(), common.Hash{}, destructs, accounts, storage)
|
||||
it := parent.AccountIterator(common.Hash{})
|
||||
verifyIterator(t, 100, it)
|
||||
}
|
||||
@ -138,8 +143,8 @@ func verifyIterator(t *testing.T, expCount int, it AccountIterator) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestIteratorTraversal tests some simple multi-layer iteration.
|
||||
func TestIteratorTraversal(t *testing.T) {
|
||||
// TestAccountIteratorTraversal tests some simple multi-layer iteration.
|
||||
func TestAccountIteratorTraversal(t *testing.T) {
|
||||
// Create an empty base layer and a snapshot tree out of it
|
||||
base := &diskLayer{
|
||||
diskdb: rawdb.NewMemoryDatabase(),
|
||||
@ -152,13 +157,13 @@ func TestIteratorTraversal(t *testing.T) {
|
||||
},
|
||||
}
|
||||
// Stack three diff layers on top with various overlaps
|
||||
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"),
|
||||
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil,
|
||||
randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil)
|
||||
|
||||
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"),
|
||||
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil,
|
||||
randomAccountSet("0xbb", "0xdd", "0xf0"), nil)
|
||||
|
||||
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"),
|
||||
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil,
|
||||
randomAccountSet("0xcc", "0xf0", "0xff"), nil)
|
||||
|
||||
// Verify the single and multi-layer iterators
|
||||
@ -173,9 +178,9 @@ func TestIteratorTraversal(t *testing.T) {
|
||||
verifyIterator(t, 7, it)
|
||||
}
|
||||
|
||||
// TestIteratorTraversalValues tests some multi-layer iteration, where we
|
||||
// TestAccountIteratorTraversalValues tests some multi-layer iteration, where we
|
||||
// also expect the correct values to show up.
|
||||
func TestIteratorTraversalValues(t *testing.T) {
|
||||
func TestAccountIteratorTraversalValues(t *testing.T) {
|
||||
// Create an empty base layer and a snapshot tree out of it
|
||||
base := &diskLayer{
|
||||
diskdb: rawdb.NewMemoryDatabase(),
|
||||
@ -223,14 +228,14 @@ func TestIteratorTraversalValues(t *testing.T) {
|
||||
}
|
||||
}
|
||||
// Assemble a stack of snapshots from the account layers
|
||||
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), a, nil)
|
||||
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), b, nil)
|
||||
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), c, nil)
|
||||
snaps.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), d, nil)
|
||||
snaps.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), e, nil)
|
||||
snaps.Update(common.HexToHash("0x07"), common.HexToHash("0x06"), f, nil)
|
||||
snaps.Update(common.HexToHash("0x08"), common.HexToHash("0x07"), g, nil)
|
||||
snaps.Update(common.HexToHash("0x09"), common.HexToHash("0x08"), h, nil)
|
||||
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, a, nil)
|
||||
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, b, nil)
|
||||
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, c, nil)
|
||||
snaps.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), nil, d, nil)
|
||||
snaps.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), nil, e, nil)
|
||||
snaps.Update(common.HexToHash("0x07"), common.HexToHash("0x06"), nil, f, nil)
|
||||
snaps.Update(common.HexToHash("0x08"), common.HexToHash("0x07"), nil, g, nil)
|
||||
snaps.Update(common.HexToHash("0x09"), common.HexToHash("0x08"), nil, h, nil)
|
||||
|
||||
it, _ := snaps.AccountIterator(common.HexToHash("0x09"), common.Hash{})
|
||||
defer it.Release()
|
||||
@ -249,7 +254,7 @@ func TestIteratorTraversalValues(t *testing.T) {
|
||||
}
|
||||
|
||||
// This testcase is notorious, all layers contain the exact same 200 accounts.
|
||||
func TestIteratorLargeTraversal(t *testing.T) {
|
||||
func TestAccountIteratorLargeTraversal(t *testing.T) {
|
||||
// Create a custom account factory to recreate the same addresses
|
||||
makeAccounts := func(num int) map[common.Hash][]byte {
|
||||
accounts := make(map[common.Hash][]byte)
|
||||
@ -272,7 +277,7 @@ func TestIteratorLargeTraversal(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for i := 1; i < 128; i++ {
|
||||
snaps.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), makeAccounts(200), nil)
|
||||
snaps.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(200), nil)
|
||||
}
|
||||
// Iterate the entire stack and ensure everything is hit only once
|
||||
head := snaps.Snapshot(common.HexToHash("0x80"))
|
||||
@ -285,11 +290,11 @@ func TestIteratorLargeTraversal(t *testing.T) {
|
||||
verifyIterator(t, 200, it)
|
||||
}
|
||||
|
||||
// TestIteratorFlattening tests what happens when we
|
||||
// TestAccountIteratorFlattening tests what happens when we
|
||||
// - have a live iterator on child C (parent C1 -> C2 .. CN)
|
||||
// - flattens C2 all the way into CN
|
||||
// - continues iterating
|
||||
func TestIteratorFlattening(t *testing.T) {
|
||||
func TestAccountIteratorFlattening(t *testing.T) {
|
||||
// Create an empty base layer and a snapshot tree out of it
|
||||
base := &diskLayer{
|
||||
diskdb: rawdb.NewMemoryDatabase(),
|
||||
@ -302,13 +307,13 @@ func TestIteratorFlattening(t *testing.T) {
|
||||
},
|
||||
}
|
||||
// Create a stack of diffs on top
|
||||
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"),
|
||||
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil,
|
||||
randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil)
|
||||
|
||||
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"),
|
||||
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil,
|
||||
randomAccountSet("0xbb", "0xdd", "0xf0"), nil)
|
||||
|
||||
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"),
|
||||
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil,
|
||||
randomAccountSet("0xcc", "0xf0", "0xff"), nil)
|
||||
|
||||
// Create an iterator and flatten the data from underneath it
|
||||
@ -321,7 +326,7 @@ func TestIteratorFlattening(t *testing.T) {
|
||||
//verifyIterator(t, 7, it)
|
||||
}
|
||||
|
||||
func TestIteratorSeek(t *testing.T) {
|
||||
func TestAccountIteratorSeek(t *testing.T) {
|
||||
// Create a snapshot stack with some initial data
|
||||
base := &diskLayer{
|
||||
diskdb: rawdb.NewMemoryDatabase(),
|
||||
@ -333,13 +338,13 @@ func TestIteratorSeek(t *testing.T) {
|
||||
base.root: base,
|
||||
},
|
||||
}
|
||||
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"),
|
||||
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil,
|
||||
randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil)
|
||||
|
||||
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"),
|
||||
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil,
|
||||
randomAccountSet("0xbb", "0xdd", "0xf0"), nil)
|
||||
|
||||
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"),
|
||||
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil,
|
||||
randomAccountSet("0xcc", "0xf0", "0xff"), nil)
|
||||
|
||||
// Construct various iterators and ensure their tranversal is correct
|
||||
@ -372,18 +377,18 @@ func TestIteratorSeek(t *testing.T) {
|
||||
verifyIterator(t, 0, it) // expected: nothing
|
||||
}
|
||||
|
||||
// BenchmarkIteratorTraversal is a bit a bit notorious -- all layers contain the
|
||||
// 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.
|
||||
//
|
||||
// The value-fetching benchmark is easy on the binary iterator, since it never has to reach
|
||||
// down at any depth for retrieving the values -- all are on the toppmost layer
|
||||
//
|
||||
// BenchmarkIteratorTraversal/binary_iterator_keys-6 2239 483674 ns/op
|
||||
// BenchmarkIteratorTraversal/binary_iterator_values-6 2403 501810 ns/op
|
||||
// BenchmarkIteratorTraversal/fast_iterator_keys-6 1923 677966 ns/op
|
||||
// BenchmarkIteratorTraversal/fast_iterator_values-6 1741 649967 ns/op
|
||||
func BenchmarkIteratorTraversal(b *testing.B) {
|
||||
// BenchmarkAccountIteratorTraversal/binary_iterator_keys-6 2239 483674 ns/op
|
||||
// BenchmarkAccountIteratorTraversal/binary_iterator_values-6 2403 501810 ns/op
|
||||
// BenchmarkAccountIteratorTraversal/fast_iterator_keys-6 1923 677966 ns/op
|
||||
// BenchmarkAccountIteratorTraversal/fast_iterator_values-6 1741 649967 ns/op
|
||||
func BenchmarkAccountIteratorTraversal(b *testing.B) {
|
||||
// Create a custom account factory to recreate the same addresses
|
||||
makeAccounts := func(num int) map[common.Hash][]byte {
|
||||
accounts := make(map[common.Hash][]byte)
|
||||
@ -406,7 +411,7 @@ func BenchmarkIteratorTraversal(b *testing.B) {
|
||||
},
|
||||
}
|
||||
for i := 1; i <= 100; i++ {
|
||||
snaps.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), makeAccounts(200), nil)
|
||||
snaps.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(200), nil)
|
||||
}
|
||||
// We call this once before the benchmark, so the creation of
|
||||
// sorted accountlists are not included in the results.
|
||||
@ -469,17 +474,17 @@ func BenchmarkIteratorTraversal(b *testing.B) {
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkIteratorLargeBaselayer is a pretty realistic benchmark, where
|
||||
// BenchmarkAccountIteratorLargeBaselayer is a pretty realistic benchmark, where
|
||||
// the baselayer is a lot larger than the upper layer.
|
||||
//
|
||||
// This is heavy on the binary iterator, which in most cases will have to
|
||||
// call recursively 100 times for the majority of the values
|
||||
//
|
||||
// BenchmarkIteratorLargeBaselayer/binary_iterator_(keys)-6 514 1971999 ns/op
|
||||
// BenchmarkIteratorLargeBaselayer/binary_iterator_(values)-6 61 18997492 ns/op
|
||||
// BenchmarkIteratorLargeBaselayer/fast_iterator_(keys)-6 10000 114385 ns/op
|
||||
// BenchmarkIteratorLargeBaselayer/fast_iterator_(values)-6 4047 296823 ns/op
|
||||
func BenchmarkIteratorLargeBaselayer(b *testing.B) {
|
||||
// BenchmarkAccountIteratorLargeBaselayer/binary_iterator_(keys)-6 514 1971999 ns/op
|
||||
// BenchmarkAccountIteratorLargeBaselayer/binary_iterator_(values)-6 61 18997492 ns/op
|
||||
// BenchmarkAccountIteratorLargeBaselayer/fast_iterator_(keys)-6 10000 114385 ns/op
|
||||
// BenchmarkAccountIteratorLargeBaselayer/fast_iterator_(values)-6 4047 296823 ns/op
|
||||
func BenchmarkAccountIteratorLargeBaselayer(b *testing.B) {
|
||||
// Create a custom account factory to recreate the same addresses
|
||||
makeAccounts := func(num int) map[common.Hash][]byte {
|
||||
accounts := make(map[common.Hash][]byte)
|
||||
@ -501,9 +506,9 @@ func BenchmarkIteratorLargeBaselayer(b *testing.B) {
|
||||
base.root: base,
|
||||
},
|
||||
}
|
||||
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), makeAccounts(2000), nil)
|
||||
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, makeAccounts(2000), nil)
|
||||
for i := 2; i <= 100; i++ {
|
||||
snaps.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), makeAccounts(20), nil)
|
||||
snaps.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(20), nil)
|
||||
}
|
||||
// We call this once before the benchmark, so the creation of
|
||||
// sorted accountlists are not included in the results.
|
||||
@ -590,7 +595,7 @@ func benchmarkAccountIteration(b *testing.B, iterator func(snap snapshot) Accoun
|
||||
}
|
||||
stack := snapshot(emptyLayer())
|
||||
for _, layer := range layers {
|
||||
stack = stack.Update(common.Hash{}, layer, nil)
|
||||
stack = stack.Update(common.Hash{}, layer, nil, nil)
|
||||
}
|
||||
// Reset the timers and report all the stats
|
||||
it := iterator(stack)
|
||||
|
Reference in New Issue
Block a user