core/state: tests on the binary iterator (#30754)

Fixes an error in the binary iterator, adds additional testcases

---------

Co-authored-by: Gary Rong <garyrong0905@gmail.com>
This commit is contained in:
Martin HS 2024-11-15 07:59:06 +01:00 committed by GitHub
parent df182a742c
commit ec280e030f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 172 additions and 74 deletions

View File

@ -39,12 +39,12 @@ type binaryIterator struct {
// initBinaryAccountIterator creates a simplistic iterator to step over all the // initBinaryAccountIterator creates a simplistic iterator to step over all the
// accounts in a slow, but easily verifiable way. Note this function is used for // accounts in a slow, but easily verifiable way. Note this function is used for
// initialization, use `newBinaryAccountIterator` as the API. // initialization, use `newBinaryAccountIterator` as the API.
func (dl *diffLayer) initBinaryAccountIterator() Iterator { func (dl *diffLayer) initBinaryAccountIterator(seek common.Hash) Iterator {
parent, ok := dl.parent.(*diffLayer) parent, ok := dl.parent.(*diffLayer)
if !ok { if !ok {
l := &binaryIterator{ l := &binaryIterator{
a: dl.AccountIterator(common.Hash{}), a: dl.AccountIterator(seek),
b: dl.Parent().AccountIterator(common.Hash{}), b: dl.Parent().AccountIterator(seek),
accountIterator: true, accountIterator: true,
} }
l.aDone = !l.a.Next() l.aDone = !l.a.Next()
@ -52,8 +52,8 @@ func (dl *diffLayer) initBinaryAccountIterator() Iterator {
return l return l
} }
l := &binaryIterator{ l := &binaryIterator{
a: dl.AccountIterator(common.Hash{}), a: dl.AccountIterator(seek),
b: parent.initBinaryAccountIterator(), b: parent.initBinaryAccountIterator(seek),
accountIterator: true, accountIterator: true,
} }
l.aDone = !l.a.Next() l.aDone = !l.a.Next()
@ -64,12 +64,12 @@ func (dl *diffLayer) initBinaryAccountIterator() Iterator {
// initBinaryStorageIterator creates a simplistic iterator to step over all the // initBinaryStorageIterator creates a simplistic iterator to step over all the
// storage slots in a slow, but easily verifiable way. Note this function is used // storage slots in a slow, but easily verifiable way. Note this function is used
// for initialization, use `newBinaryStorageIterator` as the API. // for initialization, use `newBinaryStorageIterator` as the API.
func (dl *diffLayer) initBinaryStorageIterator(account common.Hash) Iterator { func (dl *diffLayer) initBinaryStorageIterator(account, seek common.Hash) Iterator {
parent, ok := dl.parent.(*diffLayer) parent, ok := dl.parent.(*diffLayer)
if !ok { if !ok {
// If the storage in this layer is already destructed, discard all // If the storage in this layer is already destructed, discard all
// deeper layers but still return a valid single-branch iterator. // deeper layers but still return a valid single-branch iterator.
a, destructed := dl.StorageIterator(account, common.Hash{}) a, destructed := dl.StorageIterator(account, seek)
if destructed { if destructed {
l := &binaryIterator{ l := &binaryIterator{
a: a, a: a,
@ -81,7 +81,7 @@ func (dl *diffLayer) initBinaryStorageIterator(account common.Hash) Iterator {
} }
// The parent is disk layer, don't need to take care "destructed" // The parent is disk layer, don't need to take care "destructed"
// anymore. // anymore.
b, _ := dl.Parent().StorageIterator(account, common.Hash{}) b, _ := dl.Parent().StorageIterator(account, seek)
l := &binaryIterator{ l := &binaryIterator{
a: a, a: a,
b: b, b: b,
@ -93,7 +93,7 @@ func (dl *diffLayer) initBinaryStorageIterator(account common.Hash) Iterator {
} }
// If the storage in this layer is already destructed, discard all // If the storage in this layer is already destructed, discard all
// deeper layers but still return a valid single-branch iterator. // deeper layers but still return a valid single-branch iterator.
a, destructed := dl.StorageIterator(account, common.Hash{}) a, destructed := dl.StorageIterator(account, seek)
if destructed { if destructed {
l := &binaryIterator{ l := &binaryIterator{
a: a, a: a,
@ -105,7 +105,7 @@ func (dl *diffLayer) initBinaryStorageIterator(account common.Hash) Iterator {
} }
l := &binaryIterator{ l := &binaryIterator{
a: a, a: a,
b: parent.initBinaryStorageIterator(account), b: parent.initBinaryStorageIterator(account, seek),
account: account, account: account,
} }
l.aDone = !l.a.Next() l.aDone = !l.a.Next()
@ -117,33 +117,50 @@ func (dl *diffLayer) initBinaryStorageIterator(account common.Hash) Iterator {
// or an error if iteration failed for some reason (e.g. root being iterated // or an error if iteration failed for some reason (e.g. root being iterated
// becomes stale and garbage collected). // becomes stale and garbage collected).
func (it *binaryIterator) Next() bool { func (it *binaryIterator) Next() bool {
for {
if !it.next() {
return false
}
if len(it.Account()) != 0 || len(it.Slot()) != 0 {
return true
}
// it.fail might be set if error occurs by calling
// it.Account() or it.Slot(), stop iteration if so.
if it.fail != nil {
return false
}
}
}
func (it *binaryIterator) next() bool {
if it.aDone && it.bDone { if it.aDone && it.bDone {
return false return false
} }
first: for {
if it.aDone { if it.aDone {
it.k = it.b.Hash() it.k = it.b.Hash()
it.bDone = !it.b.Next()
return true
}
if it.bDone {
it.k = it.a.Hash()
it.aDone = !it.a.Next()
return true
}
nextA, nextB := it.a.Hash(), it.b.Hash()
if diff := bytes.Compare(nextA[:], nextB[:]); diff < 0 {
it.aDone = !it.a.Next()
it.k = nextA
return true
} else if diff == 0 {
// Now we need to advance one of them
it.aDone = !it.a.Next()
continue
}
it.bDone = !it.b.Next() it.bDone = !it.b.Next()
it.k = nextB
return true return true
} }
if it.bDone {
it.k = it.a.Hash()
it.aDone = !it.a.Next()
return true
}
nextA, nextB := it.a.Hash(), it.b.Hash()
if diff := bytes.Compare(nextA[:], nextB[:]); diff < 0 {
it.aDone = !it.a.Next()
it.k = nextA
return true
} else if diff == 0 {
// Now we need to advance one of them
it.aDone = !it.a.Next()
goto first
}
it.bDone = !it.b.Next()
it.k = nextB
return true
} }
// Error returns any failure that occurred during iteration, which might have // Error returns any failure that occurred during iteration, which might have
@ -195,19 +212,21 @@ func (it *binaryIterator) Slot() []byte {
// Release recursively releases all the iterators in the stack. // Release recursively releases all the iterators in the stack.
func (it *binaryIterator) Release() { func (it *binaryIterator) Release() {
it.a.Release() it.a.Release()
it.b.Release() if it.b != nil {
it.b.Release()
}
} }
// newBinaryAccountIterator creates a simplistic account iterator to step over // newBinaryAccountIterator creates a simplistic account iterator to step over
// all the accounts in a slow, but easily verifiable way. // all the accounts in a slow, but easily verifiable way.
func (dl *diffLayer) newBinaryAccountIterator() AccountIterator { func (dl *diffLayer) newBinaryAccountIterator(seek common.Hash) AccountIterator {
iter := dl.initBinaryAccountIterator() iter := dl.initBinaryAccountIterator(seek)
return iter.(AccountIterator) return iter.(AccountIterator)
} }
// newBinaryStorageIterator creates a simplistic account iterator to step over // newBinaryStorageIterator creates a simplistic account iterator to step over
// all the storage slots in a slow, but easily verifiable way. // all the storage slots in a slow, but easily verifiable way.
func (dl *diffLayer) newBinaryStorageIterator(account common.Hash) StorageIterator { func (dl *diffLayer) newBinaryStorageIterator(account, seek common.Hash) StorageIterator {
iter := dl.initBinaryStorageIterator(account) iter := dl.initBinaryStorageIterator(account, seek)
return iter.(StorageIterator) return iter.(StorageIterator)
} }

View File

@ -58,6 +58,9 @@ func TestAccountIteratorBasics(t *testing.T) {
it := diffLayer.AccountIterator(common.Hash{}) it := diffLayer.AccountIterator(common.Hash{})
verifyIterator(t, 100, it, verifyNothing) // Nil is allowed for single layer iterator verifyIterator(t, 100, it, verifyNothing) // Nil is allowed for single layer iterator
it = diffLayer.newBinaryAccountIterator(common.Hash{})
verifyIterator(t, 100, it, verifyNothing) // Nil is allowed for single layer iterator
diskLayer := diffToDisk(diffLayer) diskLayer := diffToDisk(diffLayer)
it = diskLayer.AccountIterator(common.Hash{}) it = diskLayer.AccountIterator(common.Hash{})
verifyIterator(t, 100, it, verifyNothing) // Nil is allowed for single layer iterator verifyIterator(t, 100, it, verifyNothing) // Nil is allowed for single layer iterator
@ -235,7 +238,7 @@ func TestAccountIteratorTraversal(t *testing.T) {
head := snaps.Snapshot(common.HexToHash("0x04")) head := snaps.Snapshot(common.HexToHash("0x04"))
verifyIterator(t, 3, head.(snapshot).AccountIterator(common.Hash{}), verifyNothing) verifyIterator(t, 3, head.(snapshot).AccountIterator(common.Hash{}), verifyNothing)
verifyIterator(t, 7, head.(*diffLayer).newBinaryAccountIterator(), verifyAccount) verifyIterator(t, 7, head.(*diffLayer).newBinaryAccountIterator(common.Hash{}), verifyAccount)
it, _ := snaps.AccountIterator(common.HexToHash("0x04"), common.Hash{}) it, _ := snaps.AccountIterator(common.HexToHash("0x04"), common.Hash{})
verifyIterator(t, 7, it, verifyAccount) verifyIterator(t, 7, it, verifyAccount)
@ -249,7 +252,7 @@ func TestAccountIteratorTraversal(t *testing.T) {
}() }()
aggregatorMemoryLimit = 0 // Force pushing the bottom-most layer into disk aggregatorMemoryLimit = 0 // Force pushing the bottom-most layer into disk
snaps.Cap(common.HexToHash("0x04"), 2) snaps.Cap(common.HexToHash("0x04"), 2)
verifyIterator(t, 7, head.(*diffLayer).newBinaryAccountIterator(), verifyAccount) verifyIterator(t, 7, head.(*diffLayer).newBinaryAccountIterator(common.Hash{}), verifyAccount)
it, _ = snaps.AccountIterator(common.HexToHash("0x04"), common.Hash{}) it, _ = snaps.AccountIterator(common.HexToHash("0x04"), common.Hash{})
verifyIterator(t, 7, it, verifyAccount) verifyIterator(t, 7, it, verifyAccount)
@ -283,7 +286,7 @@ func TestStorageIteratorTraversal(t *testing.T) {
diffIter, _ := head.(snapshot).StorageIterator(common.HexToHash("0xaa"), common.Hash{}) diffIter, _ := head.(snapshot).StorageIterator(common.HexToHash("0xaa"), common.Hash{})
verifyIterator(t, 3, diffIter, verifyNothing) verifyIterator(t, 3, diffIter, verifyNothing)
verifyIterator(t, 6, head.(*diffLayer).newBinaryStorageIterator(common.HexToHash("0xaa")), verifyStorage) verifyIterator(t, 6, head.(*diffLayer).newBinaryStorageIterator(common.HexToHash("0xaa"), common.Hash{}), verifyStorage)
it, _ := snaps.StorageIterator(common.HexToHash("0x04"), common.HexToHash("0xaa"), common.Hash{}) it, _ := snaps.StorageIterator(common.HexToHash("0x04"), common.HexToHash("0xaa"), common.Hash{})
verifyIterator(t, 6, it, verifyStorage) verifyIterator(t, 6, it, verifyStorage)
@ -297,7 +300,7 @@ func TestStorageIteratorTraversal(t *testing.T) {
}() }()
aggregatorMemoryLimit = 0 // Force pushing the bottom-most layer into disk aggregatorMemoryLimit = 0 // Force pushing the bottom-most layer into disk
snaps.Cap(common.HexToHash("0x04"), 2) snaps.Cap(common.HexToHash("0x04"), 2)
verifyIterator(t, 6, head.(*diffLayer).newBinaryStorageIterator(common.HexToHash("0xaa")), verifyStorage) verifyIterator(t, 6, head.(*diffLayer).newBinaryStorageIterator(common.HexToHash("0xaa"), common.Hash{}), verifyStorage)
it, _ = snaps.StorageIterator(common.HexToHash("0x04"), common.HexToHash("0xaa"), common.Hash{}) it, _ = snaps.StorageIterator(common.HexToHash("0x04"), common.HexToHash("0xaa"), common.Hash{})
verifyIterator(t, 6, it, verifyStorage) verifyIterator(t, 6, it, verifyStorage)
@ -528,7 +531,7 @@ func TestAccountIteratorLargeTraversal(t *testing.T) {
// Iterate the entire stack and ensure everything is hit only once // Iterate the entire stack and ensure everything is hit only once
head := snaps.Snapshot(common.HexToHash("0x80")) head := snaps.Snapshot(common.HexToHash("0x80"))
verifyIterator(t, 200, head.(snapshot).AccountIterator(common.Hash{}), verifyNothing) verifyIterator(t, 200, head.(snapshot).AccountIterator(common.Hash{}), verifyNothing)
verifyIterator(t, 200, head.(*diffLayer).newBinaryAccountIterator(), verifyAccount) verifyIterator(t, 200, head.(*diffLayer).newBinaryAccountIterator(common.Hash{}), verifyAccount)
it, _ := snaps.AccountIterator(common.HexToHash("0x80"), common.Hash{}) it, _ := snaps.AccountIterator(common.HexToHash("0x80"), common.Hash{})
verifyIterator(t, 200, it, verifyAccount) verifyIterator(t, 200, it, verifyAccount)
@ -543,7 +546,7 @@ func TestAccountIteratorLargeTraversal(t *testing.T) {
aggregatorMemoryLimit = 0 // Force pushing the bottom-most layer into disk aggregatorMemoryLimit = 0 // Force pushing the bottom-most layer into disk
snaps.Cap(common.HexToHash("0x80"), 2) snaps.Cap(common.HexToHash("0x80"), 2)
verifyIterator(t, 200, head.(*diffLayer).newBinaryAccountIterator(), verifyAccount) verifyIterator(t, 200, head.(*diffLayer).newBinaryAccountIterator(common.Hash{}), verifyAccount)
it, _ = snaps.AccountIterator(common.HexToHash("0x80"), common.Hash{}) it, _ = snaps.AccountIterator(common.HexToHash("0x80"), common.Hash{})
verifyIterator(t, 200, it, verifyAccount) verifyIterator(t, 200, it, verifyAccount)
@ -555,6 +558,20 @@ func TestAccountIteratorLargeTraversal(t *testing.T) {
// - flattens C2 all the way into CN // - flattens C2 all the way into CN
// - continues iterating // - continues iterating
func TestAccountIteratorFlattening(t *testing.T) { func TestAccountIteratorFlattening(t *testing.T) {
t.Run("fast", func(t *testing.T) {
testAccountIteratorFlattening(t, func(snaps *Tree, root, seek common.Hash) AccountIterator {
it, _ := snaps.AccountIterator(root, seek)
return it
})
})
t.Run("binary", func(t *testing.T) {
testAccountIteratorFlattening(t, func(snaps *Tree, root, seek common.Hash) AccountIterator {
return snaps.layers[root].(*diffLayer).newBinaryAccountIterator(seek)
})
})
}
func testAccountIteratorFlattening(t *testing.T, newIterator func(snaps *Tree, root, seek common.Hash) AccountIterator) {
// Create an empty base layer and a snapshot tree out of it // Create an empty base layer and a snapshot tree out of it
base := &diskLayer{ base := &diskLayer{
diskdb: rawdb.NewMemoryDatabase(), diskdb: rawdb.NewMemoryDatabase(),
@ -577,7 +594,7 @@ func TestAccountIteratorFlattening(t *testing.T) {
randomAccountSet("0xcc", "0xf0", "0xff"), nil) randomAccountSet("0xcc", "0xf0", "0xff"), nil)
// Create an iterator and flatten the data from underneath it // Create an iterator and flatten the data from underneath it
it, _ := snaps.AccountIterator(common.HexToHash("0x04"), common.Hash{}) it := newIterator(snaps, common.HexToHash("0x04"), common.Hash{})
defer it.Release() defer it.Release()
if err := snaps.Cap(common.HexToHash("0x04"), 1); err != nil { if err := snaps.Cap(common.HexToHash("0x04"), 1); err != nil {
@ -587,6 +604,21 @@ func TestAccountIteratorFlattening(t *testing.T) {
} }
func TestAccountIteratorSeek(t *testing.T) { func TestAccountIteratorSeek(t *testing.T) {
t.Run("fast", func(t *testing.T) {
testAccountIteratorSeek(t, func(snaps *Tree, root, seek common.Hash) AccountIterator {
it, _ := snaps.AccountIterator(root, seek)
return it
})
})
t.Run("binary", func(t *testing.T) {
testAccountIteratorSeek(t, func(snaps *Tree, root, seek common.Hash) AccountIterator {
it := snaps.layers[root].(*diffLayer).newBinaryAccountIterator(seek)
return it
})
})
}
func testAccountIteratorSeek(t *testing.T, newIterator func(snaps *Tree, root, seek common.Hash) AccountIterator) {
// Create a snapshot stack with some initial data // Create a snapshot stack with some initial data
base := &diskLayer{ base := &diskLayer{
diskdb: rawdb.NewMemoryDatabase(), diskdb: rawdb.NewMemoryDatabase(),
@ -612,44 +644,58 @@ func TestAccountIteratorSeek(t *testing.T) {
// 03: aa, bb, dd, ee, f0 (, f0), ff // 03: aa, bb, dd, ee, f0 (, f0), ff
// 04: aa, bb, cc, dd, ee, f0 (, f0), ff (, ff) // 04: aa, bb, cc, dd, ee, f0 (, f0), ff (, ff)
// Construct various iterators and ensure their traversal is correct // Construct various iterators and ensure their traversal is correct
it, _ := snaps.AccountIterator(common.HexToHash("0x02"), common.HexToHash("0xdd")) it := newIterator(snaps, common.HexToHash("0x02"), common.HexToHash("0xdd"))
defer it.Release() defer it.Release()
verifyIterator(t, 3, it, verifyAccount) // expected: ee, f0, ff verifyIterator(t, 3, it, verifyAccount) // expected: ee, f0, ff
it, _ = snaps.AccountIterator(common.HexToHash("0x02"), common.HexToHash("0xaa")) it = newIterator(snaps, common.HexToHash("0x02"), common.HexToHash("0xaa"))
defer it.Release() defer it.Release()
verifyIterator(t, 4, it, verifyAccount) // expected: aa, ee, f0, ff verifyIterator(t, 4, it, verifyAccount) // expected: aa, ee, f0, ff
it, _ = snaps.AccountIterator(common.HexToHash("0x02"), common.HexToHash("0xff")) it = newIterator(snaps, common.HexToHash("0x02"), common.HexToHash("0xff"))
defer it.Release() defer it.Release()
verifyIterator(t, 1, it, verifyAccount) // expected: ff verifyIterator(t, 1, it, verifyAccount) // expected: ff
it, _ = snaps.AccountIterator(common.HexToHash("0x02"), common.HexToHash("0xff1")) it = newIterator(snaps, common.HexToHash("0x02"), common.HexToHash("0xff1"))
defer it.Release() defer it.Release()
verifyIterator(t, 0, it, verifyAccount) // expected: nothing verifyIterator(t, 0, it, verifyAccount) // expected: nothing
it, _ = snaps.AccountIterator(common.HexToHash("0x04"), common.HexToHash("0xbb")) it = newIterator(snaps, common.HexToHash("0x04"), common.HexToHash("0xbb"))
defer it.Release() defer it.Release()
verifyIterator(t, 6, it, verifyAccount) // expected: bb, cc, dd, ee, f0, ff verifyIterator(t, 6, it, verifyAccount) // expected: bb, cc, dd, ee, f0, ff
it, _ = snaps.AccountIterator(common.HexToHash("0x04"), common.HexToHash("0xef")) it = newIterator(snaps, common.HexToHash("0x04"), common.HexToHash("0xef"))
defer it.Release() defer it.Release()
verifyIterator(t, 2, it, verifyAccount) // expected: f0, ff verifyIterator(t, 2, it, verifyAccount) // expected: f0, ff
it, _ = snaps.AccountIterator(common.HexToHash("0x04"), common.HexToHash("0xf0")) it = newIterator(snaps, common.HexToHash("0x04"), common.HexToHash("0xf0"))
defer it.Release() defer it.Release()
verifyIterator(t, 2, it, verifyAccount) // expected: f0, ff verifyIterator(t, 2, it, verifyAccount) // expected: f0, ff
it, _ = snaps.AccountIterator(common.HexToHash("0x04"), common.HexToHash("0xff")) it = newIterator(snaps, common.HexToHash("0x04"), common.HexToHash("0xff"))
defer it.Release() defer it.Release()
verifyIterator(t, 1, it, verifyAccount) // expected: ff verifyIterator(t, 1, it, verifyAccount) // expected: ff
it, _ = snaps.AccountIterator(common.HexToHash("0x04"), common.HexToHash("0xff1")) it = newIterator(snaps, common.HexToHash("0x04"), common.HexToHash("0xff1"))
defer it.Release() defer it.Release()
verifyIterator(t, 0, it, verifyAccount) // expected: nothing verifyIterator(t, 0, it, verifyAccount) // expected: nothing
} }
func TestStorageIteratorSeek(t *testing.T) { func TestStorageIteratorSeek(t *testing.T) {
t.Run("fast", func(t *testing.T) {
testStorageIteratorSeek(t, func(snaps *Tree, root, account, seek common.Hash) StorageIterator {
it, _ := snaps.StorageIterator(root, account, seek)
return it
})
})
t.Run("binary", func(t *testing.T) {
testStorageIteratorSeek(t, func(snaps *Tree, root, account, seek common.Hash) StorageIterator {
return snaps.layers[root].(*diffLayer).newBinaryStorageIterator(account, seek)
})
})
}
func testStorageIteratorSeek(t *testing.T, newIterator func(snaps *Tree, root, account, seek common.Hash) StorageIterator) {
// Create a snapshot stack with some initial data // Create a snapshot stack with some initial data
base := &diskLayer{ base := &diskLayer{
diskdb: rawdb.NewMemoryDatabase(), diskdb: rawdb.NewMemoryDatabase(),
@ -676,35 +722,35 @@ func TestStorageIteratorSeek(t *testing.T) {
// 03: 01, 02, 03, 05 (, 05), 06 // 03: 01, 02, 03, 05 (, 05), 06
// 04: 01(, 01), 02, 03, 05(, 05, 05), 06, 08 // 04: 01(, 01), 02, 03, 05(, 05, 05), 06, 08
// Construct various iterators and ensure their traversal is correct // Construct various iterators and ensure their traversal is correct
it, _ := snaps.StorageIterator(common.HexToHash("0x02"), common.HexToHash("0xaa"), common.HexToHash("0x01")) it := newIterator(snaps, common.HexToHash("0x02"), common.HexToHash("0xaa"), common.HexToHash("0x01"))
defer it.Release() defer it.Release()
verifyIterator(t, 3, it, verifyStorage) // expected: 01, 03, 05 verifyIterator(t, 3, it, verifyStorage) // expected: 01, 03, 05
it, _ = snaps.StorageIterator(common.HexToHash("0x02"), common.HexToHash("0xaa"), common.HexToHash("0x02")) it = newIterator(snaps, common.HexToHash("0x02"), common.HexToHash("0xaa"), common.HexToHash("0x02"))
defer it.Release() defer it.Release()
verifyIterator(t, 2, it, verifyStorage) // expected: 03, 05 verifyIterator(t, 2, it, verifyStorage) // expected: 03, 05
it, _ = snaps.StorageIterator(common.HexToHash("0x02"), common.HexToHash("0xaa"), common.HexToHash("0x5")) it = newIterator(snaps, common.HexToHash("0x02"), common.HexToHash("0xaa"), common.HexToHash("0x5"))
defer it.Release() defer it.Release()
verifyIterator(t, 1, it, verifyStorage) // expected: 05 verifyIterator(t, 1, it, verifyStorage) // expected: 05
it, _ = snaps.StorageIterator(common.HexToHash("0x02"), common.HexToHash("0xaa"), common.HexToHash("0x6")) it = newIterator(snaps, common.HexToHash("0x02"), common.HexToHash("0xaa"), common.HexToHash("0x6"))
defer it.Release() defer it.Release()
verifyIterator(t, 0, it, verifyStorage) // expected: nothing verifyIterator(t, 0, it, verifyStorage) // expected: nothing
it, _ = snaps.StorageIterator(common.HexToHash("0x04"), common.HexToHash("0xaa"), common.HexToHash("0x01")) it = newIterator(snaps, common.HexToHash("0x04"), common.HexToHash("0xaa"), common.HexToHash("0x01"))
defer it.Release() defer it.Release()
verifyIterator(t, 6, it, verifyStorage) // expected: 01, 02, 03, 05, 06, 08 verifyIterator(t, 6, it, verifyStorage) // expected: 01, 02, 03, 05, 06, 08
it, _ = snaps.StorageIterator(common.HexToHash("0x04"), common.HexToHash("0xaa"), common.HexToHash("0x05")) it = newIterator(snaps, common.HexToHash("0x04"), common.HexToHash("0xaa"), common.HexToHash("0x05"))
defer it.Release() defer it.Release()
verifyIterator(t, 3, it, verifyStorage) // expected: 05, 06, 08 verifyIterator(t, 3, it, verifyStorage) // expected: 05, 06, 08
it, _ = snaps.StorageIterator(common.HexToHash("0x04"), common.HexToHash("0xaa"), common.HexToHash("0x08")) it = newIterator(snaps, common.HexToHash("0x04"), common.HexToHash("0xaa"), common.HexToHash("0x08"))
defer it.Release() defer it.Release()
verifyIterator(t, 1, it, verifyStorage) // expected: 08 verifyIterator(t, 1, it, verifyStorage) // expected: 08
it, _ = snaps.StorageIterator(common.HexToHash("0x04"), common.HexToHash("0xaa"), common.HexToHash("0x09")) it = newIterator(snaps, common.HexToHash("0x04"), common.HexToHash("0xaa"), common.HexToHash("0x09"))
defer it.Release() defer it.Release()
verifyIterator(t, 0, it, verifyStorage) // expected: nothing verifyIterator(t, 0, it, verifyStorage) // expected: nothing
} }
@ -713,6 +759,20 @@ func TestStorageIteratorSeek(t *testing.T) {
// deleted accounts (where the Account() value is nil). The iterator // deleted accounts (where the Account() value is nil). The iterator
// should not output any accounts or nil-values for those cases. // should not output any accounts or nil-values for those cases.
func TestAccountIteratorDeletions(t *testing.T) { func TestAccountIteratorDeletions(t *testing.T) {
t.Run("fast", func(t *testing.T) {
testAccountIteratorDeletions(t, func(snaps *Tree, root, seek common.Hash) AccountIterator {
it, _ := snaps.AccountIterator(root, seek)
return it
})
})
t.Run("binary", func(t *testing.T) {
testAccountIteratorDeletions(t, func(snaps *Tree, root, seek common.Hash) AccountIterator {
return snaps.layers[root].(*diffLayer).newBinaryAccountIterator(seek)
})
})
}
func testAccountIteratorDeletions(t *testing.T, newIterator func(snaps *Tree, root, seek common.Hash) AccountIterator) {
// Create an empty base layer and a snapshot tree out of it // Create an empty base layer and a snapshot tree out of it
base := &diskLayer{ base := &diskLayer{
diskdb: rawdb.NewMemoryDatabase(), diskdb: rawdb.NewMemoryDatabase(),
@ -739,7 +799,8 @@ func TestAccountIteratorDeletions(t *testing.T) {
nil, randomAccountSet("0x33", "0x44", "0x55"), nil) nil, randomAccountSet("0x33", "0x44", "0x55"), nil)
// The output should be 11,33,44,55 // The output should be 11,33,44,55
it, _ := snaps.AccountIterator(common.HexToHash("0x04"), common.Hash{}) it := newIterator(snaps, common.HexToHash("0x04"), (common.Hash{}))
// Do a quick check // Do a quick check
verifyIterator(t, 4, it, verifyAccount) verifyIterator(t, 4, it, verifyAccount)
it.Release() it.Release()
@ -759,6 +820,20 @@ func TestAccountIteratorDeletions(t *testing.T) {
} }
func TestStorageIteratorDeletions(t *testing.T) { func TestStorageIteratorDeletions(t *testing.T) {
t.Run("fast", func(t *testing.T) {
testStorageIteratorDeletions(t, func(snaps *Tree, root, account, seek common.Hash) StorageIterator {
it, _ := snaps.StorageIterator(root, account, seek)
return it
})
})
t.Run("binary", func(t *testing.T) {
testStorageIteratorDeletions(t, func(snaps *Tree, root, account, seek common.Hash) StorageIterator {
return snaps.layers[root].(*diffLayer).newBinaryStorageIterator(account, seek)
})
})
}
func testStorageIteratorDeletions(t *testing.T, newIterator func(snaps *Tree, root, account, seek common.Hash) StorageIterator) {
// Create an empty base layer and a snapshot tree out of it // Create an empty base layer and a snapshot tree out of it
base := &diskLayer{ base := &diskLayer{
diskdb: rawdb.NewMemoryDatabase(), diskdb: rawdb.NewMemoryDatabase(),
@ -778,12 +853,12 @@ func TestStorageIteratorDeletions(t *testing.T) {
randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02", "0x04", "0x06"}}, [][]string{{"0x01", "0x03"}})) randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02", "0x04", "0x06"}}, [][]string{{"0x01", "0x03"}}))
// The output should be 02,04,05,06 // The output should be 02,04,05,06
it, _ := snaps.StorageIterator(common.HexToHash("0x03"), common.HexToHash("0xaa"), common.Hash{}) it := newIterator(snaps, common.HexToHash("0x03"), common.HexToHash("0xaa"), common.Hash{})
verifyIterator(t, 4, it, verifyStorage) verifyIterator(t, 4, it, verifyStorage)
it.Release() it.Release()
// The output should be 04,05,06 // The output should be 04,05,06
it, _ = snaps.StorageIterator(common.HexToHash("0x03"), common.HexToHash("0xaa"), common.HexToHash("0x03")) it = newIterator(snaps, common.HexToHash("0x03"), common.HexToHash("0xaa"), common.HexToHash("0x03"))
verifyIterator(t, 3, it, verifyStorage) verifyIterator(t, 3, it, verifyStorage)
it.Release() it.Release()
@ -793,7 +868,7 @@ func TestStorageIteratorDeletions(t *testing.T) {
} }
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), destructed, nil, nil) snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), destructed, nil, nil)
it, _ = snaps.StorageIterator(common.HexToHash("0x04"), common.HexToHash("0xaa"), common.Hash{}) it = newIterator(snaps, common.HexToHash("0x04"), common.HexToHash("0xaa"), common.Hash{})
verifyIterator(t, 0, it, verifyStorage) verifyIterator(t, 0, it, verifyStorage)
it.Release() it.Release()
@ -802,17 +877,21 @@ func TestStorageIteratorDeletions(t *testing.T) {
randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x07", "0x08", "0x09"}}, nil)) randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x07", "0x08", "0x09"}}, nil))
// The output should be 07,08,09 // The output should be 07,08,09
it, _ = snaps.StorageIterator(common.HexToHash("0x05"), common.HexToHash("0xaa"), common.Hash{})
it = newIterator(snaps, common.HexToHash("0x05"), common.HexToHash("0xaa"), common.Hash{})
verifyIterator(t, 3, it, verifyStorage) verifyIterator(t, 3, it, verifyStorage)
it.Release() it.Release()
// Destruct the whole storage but re-create the account in the same layer // Destruct the whole storage but re-create the account in the same layer
snaps.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), destructed, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x11", "0x12"}}, nil)) snaps.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), destructed, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x11", "0x12"}}, nil))
it, _ = snaps.StorageIterator(common.HexToHash("0x06"), common.HexToHash("0xaa"), common.Hash{}) it = newIterator(snaps, common.HexToHash("0x06"), common.HexToHash("0xaa"), common.Hash{})
verifyIterator(t, 2, it, verifyStorage) // The output should be 11,12 verifyIterator(t, 2, it, verifyStorage) // The output should be 11,12
it.Release() it.Release()
verifyIterator(t, 2, snaps.Snapshot(common.HexToHash("0x06")).(*diffLayer).newBinaryStorageIterator(common.HexToHash("0xaa")), verifyStorage) verifyIterator(t, 2, snaps.Snapshot(
common.HexToHash("0x06")).(*diffLayer).
newBinaryStorageIterator(common.HexToHash("0xaa"), common.Hash{}),
verifyStorage)
} }
// BenchmarkAccountIteratorTraversal is a bit notorious -- all layers contain the // BenchmarkAccountIteratorTraversal is a bit notorious -- all layers contain the
@ -854,12 +933,12 @@ func BenchmarkAccountIteratorTraversal(b *testing.B) {
// We call this once before the benchmark, so the creation of // We call this once before the benchmark, so the creation of
// sorted accountlists are not included in the results. // sorted accountlists are not included in the results.
head := snaps.Snapshot(common.HexToHash("0x65")) head := snaps.Snapshot(common.HexToHash("0x65"))
head.(*diffLayer).newBinaryAccountIterator() head.(*diffLayer).newBinaryAccountIterator(common.Hash{})
b.Run("binary iterator keys", func(b *testing.B) { b.Run("binary iterator keys", func(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
got := 0 got := 0
it := head.(*diffLayer).newBinaryAccountIterator() it := head.(*diffLayer).newBinaryAccountIterator(common.Hash{})
for it.Next() { for it.Next() {
got++ got++
} }
@ -871,7 +950,7 @@ func BenchmarkAccountIteratorTraversal(b *testing.B) {
b.Run("binary iterator values", func(b *testing.B) { b.Run("binary iterator values", func(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
got := 0 got := 0
it := head.(*diffLayer).newBinaryAccountIterator() it := head.(*diffLayer).newBinaryAccountIterator(common.Hash{})
for it.Next() { for it.Next() {
got++ got++
head.(*diffLayer).accountRLP(it.Hash(), 0) head.(*diffLayer).accountRLP(it.Hash(), 0)
@ -951,12 +1030,12 @@ func BenchmarkAccountIteratorLargeBaselayer(b *testing.B) {
// We call this once before the benchmark, so the creation of // We call this once before the benchmark, so the creation of
// sorted accountlists are not included in the results. // sorted accountlists are not included in the results.
head := snaps.Snapshot(common.HexToHash("0x65")) head := snaps.Snapshot(common.HexToHash("0x65"))
head.(*diffLayer).newBinaryAccountIterator() head.(*diffLayer).newBinaryAccountIterator(common.Hash{})
b.Run("binary iterator (keys)", func(b *testing.B) { b.Run("binary iterator (keys)", func(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
got := 0 got := 0
it := head.(*diffLayer).newBinaryAccountIterator() it := head.(*diffLayer).newBinaryAccountIterator(common.Hash{})
for it.Next() { for it.Next() {
got++ got++
} }
@ -968,7 +1047,7 @@ func BenchmarkAccountIteratorLargeBaselayer(b *testing.B) {
b.Run("binary iterator (values)", func(b *testing.B) { b.Run("binary iterator (values)", func(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
got := 0 got := 0
it := head.(*diffLayer).newBinaryAccountIterator() it := head.(*diffLayer).newBinaryAccountIterator(common.Hash{})
for it.Next() { for it.Next() {
got++ got++
v := it.Hash() v := it.Hash()
@ -1013,7 +1092,7 @@ func BenchmarkAccountIteratorLargeBaselayer(b *testing.B) {
/* /*
func BenchmarkBinaryAccountIteration(b *testing.B) { func BenchmarkBinaryAccountIteration(b *testing.B) {
benchmarkAccountIteration(b, func(snap snapshot) AccountIterator { benchmarkAccountIteration(b, func(snap snapshot) AccountIterator {
return snap.(*diffLayer).newBinaryAccountIterator() return snap.(*diffLayer).newBinaryAccountIterator(common.Hash{})
}) })
} }