mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-02-26 07:37:20 +00:00
trie: do not expect ordering in stacktrie during fuzzing (#31170)
This PR removes the assumption of the stacktrie and trie to have the same ordering. This was hit by the fuzzers on oss-fuzz --------- Co-authored-by: Gary Rong <garyrong0905@gmail.com>
This commit is contained in:
parent
aec1964410
commit
3adfa1fbeb
2 changed files with 40 additions and 24 deletions
|
|
@ -37,16 +37,13 @@ func FuzzStackTrie(f *testing.F) {
|
|||
}
|
||||
|
||||
func fuzz(data []byte, debugging bool) {
|
||||
// This spongeDb is used to check the sequence of disk-db-writes
|
||||
var (
|
||||
input = bytes.NewReader(data)
|
||||
spongeA = &spongeDb{sponge: crypto.NewKeccakState()}
|
||||
dbA = newTestDatabase(rawdb.NewDatabase(spongeA), rawdb.HashScheme)
|
||||
dbA = newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)
|
||||
trieA = NewEmpty(dbA)
|
||||
spongeB = &spongeDb{sponge: crypto.NewKeccakState()}
|
||||
dbB = newTestDatabase(rawdb.NewDatabase(spongeB), rawdb.HashScheme)
|
||||
memDB = rawdb.NewMemoryDatabase()
|
||||
trieB = NewStackTrie(func(path []byte, hash common.Hash, blob []byte) {
|
||||
rawdb.WriteTrieNode(spongeB, common.Hash{}, path, hash, blob, dbB.Scheme())
|
||||
rawdb.WriteTrieNode(memDB, common.Hash{}, path, hash, blob, rawdb.HashScheme)
|
||||
})
|
||||
vals []*kv
|
||||
maxElements = 10000
|
||||
|
|
@ -55,13 +52,17 @@ func fuzz(data []byte, debugging bool) {
|
|||
)
|
||||
// Fill the trie with elements
|
||||
for i := 0; input.Len() > 0 && i < maxElements; i++ {
|
||||
// Build the key
|
||||
k := make([]byte, 32)
|
||||
input.Read(k)
|
||||
|
||||
// Build the val
|
||||
var a uint16
|
||||
binary.Read(input, binary.LittleEndian, &a)
|
||||
a = 1 + a%100
|
||||
v := make([]byte, a)
|
||||
input.Read(v)
|
||||
|
||||
if input.Len() == 0 {
|
||||
// If it was exhausted while reading, the value may be all zeroes,
|
||||
// thus 'deletion' which is not supported on stacktrie
|
||||
|
|
@ -73,6 +74,7 @@ func fuzz(data []byte, debugging bool) {
|
|||
}
|
||||
keys[string(k)] = struct{}{}
|
||||
vals = append(vals, &kv{k: k, v: v})
|
||||
|
||||
trieA.MustUpdate(k, v)
|
||||
}
|
||||
if len(vals) == 0 {
|
||||
|
|
@ -99,11 +101,6 @@ func fuzz(data []byte, debugging bool) {
|
|||
if rootA != rootB {
|
||||
panic(fmt.Sprintf("roots differ: (trie) %x != %x (stacktrie)", rootA, rootB))
|
||||
}
|
||||
sumA := spongeA.sponge.Sum(nil)
|
||||
sumB := spongeB.sponge.Sum(nil)
|
||||
if !bytes.Equal(sumA, sumB) {
|
||||
panic(fmt.Sprintf("sequence differ: (trie) %x != %x (stacktrie)", sumA, sumB))
|
||||
}
|
||||
|
||||
// Ensure all the nodes are persisted correctly
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -779,6 +779,7 @@ func TestCommitAfterHash(t *testing.T) {
|
|||
func makeAccounts(size int) (addresses [][20]byte, accounts [][]byte) {
|
||||
// Make the random benchmark deterministic
|
||||
random := rand.New(rand.NewSource(0))
|
||||
|
||||
// Create a realistic account trie to hash
|
||||
addresses = make([][20]byte, size)
|
||||
for i := 0; i < len(addresses); i++ {
|
||||
|
|
@ -801,7 +802,12 @@ func makeAccounts(size int) (addresses [][20]byte, accounts [][]byte) {
|
|||
balanceBytes := make([]byte, numBytes)
|
||||
random.Read(balanceBytes)
|
||||
balance := new(uint256.Int).SetBytes(balanceBytes)
|
||||
data, _ := rlp.EncodeToBytes(&types.StateAccount{Nonce: nonce, Balance: balance, Root: root, CodeHash: code})
|
||||
data, _ := rlp.EncodeToBytes(&types.StateAccount{
|
||||
Nonce: nonce,
|
||||
Balance: balance,
|
||||
Root: root,
|
||||
CodeHash: code,
|
||||
})
|
||||
accounts[i] = data
|
||||
}
|
||||
return addresses, accounts
|
||||
|
|
@ -856,6 +862,7 @@ func (s *spongeDb) Flush() {
|
|||
s.sponge.Write([]byte(key))
|
||||
s.sponge.Write([]byte(s.values[key]))
|
||||
}
|
||||
fmt.Println(len(s.keys))
|
||||
}
|
||||
|
||||
// spongeBatch is a dummy batch which immediately writes to the underlying spongedb
|
||||
|
|
@ -873,10 +880,12 @@ func (b *spongeBatch) Write() error { return nil }
|
|||
func (b *spongeBatch) Reset() {}
|
||||
func (b *spongeBatch) Replay(w ethdb.KeyValueWriter) error { return nil }
|
||||
|
||||
// TestCommitSequence tests that the trie.Commit operation writes the elements of the trie
|
||||
// in the expected order.
|
||||
// The test data was based on the 'master' code, and is basically random. It can be used
|
||||
// to check whether changes to the trie modifies the write order or data in any way.
|
||||
// TestCommitSequence tests that the trie.Commit operation writes the elements
|
||||
// of the trie in the expected order.
|
||||
//
|
||||
// The test data was based on the 'master' code, and is basically random.
|
||||
// It can be used to check whether changes to the trie modifies the write order
|
||||
// or data in any way.
|
||||
func TestCommitSequence(t *testing.T) {
|
||||
for i, tc := range []struct {
|
||||
count int
|
||||
|
|
@ -887,19 +896,23 @@ func TestCommitSequence(t *testing.T) {
|
|||
{2000, common.FromHex("4574cd8e6b17f3fe8ad89140d1d0bf4f1bd7a87a8ac3fb623b33550544c77635")},
|
||||
} {
|
||||
addresses, accounts := makeAccounts(tc.count)
|
||||
|
||||
// This spongeDb is used to check the sequence of disk-db-writes
|
||||
s := &spongeDb{sponge: crypto.NewKeccakState()}
|
||||
db := newTestDatabase(rawdb.NewDatabase(s), rawdb.HashScheme)
|
||||
trie := NewEmpty(db)
|
||||
|
||||
// Fill the trie with elements
|
||||
trie := NewEmpty(db)
|
||||
for i := 0; i < tc.count; i++ {
|
||||
trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i])
|
||||
}
|
||||
// Flush trie -> database
|
||||
root, nodes := trie.Commit(false)
|
||||
db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
|
||||
|
||||
// Flush memdb -> disk (sponge)
|
||||
db.Commit(root)
|
||||
|
||||
if got, exp := s.sponge.Sum(nil), tc.expWriteSeqHash; !bytes.Equal(got, exp) {
|
||||
t.Errorf("test %d, disk write sequence wrong:\ngot %x exp %x\n", i, got, exp)
|
||||
}
|
||||
|
|
@ -917,12 +930,13 @@ func TestCommitSequenceRandomBlobs(t *testing.T) {
|
|||
{200, common.FromHex("dde92ca9812e068e6982d04b40846dc65a61a9fd4996fc0f55f2fde172a8e13c")},
|
||||
{2000, common.FromHex("ab553a7f9aff82e3929c382908e30ef7dd17a332933e92ba3fe873fc661ef382")},
|
||||
} {
|
||||
prng := rand.New(rand.NewSource(int64(i)))
|
||||
// This spongeDb is used to check the sequence of disk-db-writes
|
||||
prng := rand.New(rand.NewSource(int64(i)))
|
||||
s := &spongeDb{sponge: crypto.NewKeccakState()}
|
||||
db := newTestDatabase(rawdb.NewDatabase(s), rawdb.HashScheme)
|
||||
trie := NewEmpty(db)
|
||||
|
||||
// Fill the trie with elements
|
||||
trie := NewEmpty(db)
|
||||
for i := 0; i < tc.count; i++ {
|
||||
key := make([]byte, 32)
|
||||
var val []byte
|
||||
|
|
@ -939,6 +953,7 @@ func TestCommitSequenceRandomBlobs(t *testing.T) {
|
|||
// Flush trie -> database
|
||||
root, nodes := trie.Commit(false)
|
||||
db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
|
||||
|
||||
// Flush memdb -> disk (sponge)
|
||||
db.Commit(root)
|
||||
if got, exp := s.sponge.Sum(nil), tc.expWriteSeqHash; !bytes.Equal(got, exp) {
|
||||
|
|
@ -974,19 +989,22 @@ func TestCommitSequenceStackTrie(t *testing.T) {
|
|||
// For the stack trie, we need to do inserts in proper order
|
||||
key := make([]byte, 32)
|
||||
binary.BigEndian.PutUint64(key, uint64(i))
|
||||
var val []byte
|
||||
|
||||
// 50% short elements, 50% large elements
|
||||
var val []byte
|
||||
if prng.Intn(2) == 0 {
|
||||
val = make([]byte, 1+prng.Intn(32))
|
||||
} else {
|
||||
val = make([]byte, 1+prng.Intn(1024))
|
||||
}
|
||||
prng.Read(val)
|
||||
|
||||
trie.Update(key, val)
|
||||
stTrie.Update(key, val)
|
||||
}
|
||||
// Flush trie -> database
|
||||
root, nodes := trie.Commit(false)
|
||||
|
||||
// Flush memdb -> disk (sponge)
|
||||
db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
|
||||
db.Commit(root)
|
||||
|
|
@ -1045,6 +1063,7 @@ func TestCommitSequenceSmallRoot(t *testing.T) {
|
|||
|
||||
// Flush trie -> database
|
||||
root, nodes := trie.Commit(false)
|
||||
|
||||
// Flush memdb -> disk (sponge)
|
||||
db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes))
|
||||
db.Commit(root)
|
||||
|
|
|
|||
Loading…
Reference in a new issue