trie: move fuzzers into native packages #28467 (#1239)

This commit is contained in:
Daniel Liu 2025-07-17 17:55:19 +08:00 committed by GitHub
parent 4b4980d949
commit a9d4fffc97
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -23,6 +23,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"hash" "hash"
"io"
"math/big" "math/big"
"math/rand" "math/rand"
"reflect" "reflect"
@ -292,8 +293,9 @@ func TestRandomCases(t *testing.T) {
{op: 1, key: common.Hex2Bytes("980c393656413a15c8da01978ed9f89feb80b502f58f2d640e3a2f5f7a99a7018f1b573befd92053ac6f78fca4a87268"), value: common.Hex2Bytes("")}, // step 24 {op: 1, key: common.Hex2Bytes("980c393656413a15c8da01978ed9f89feb80b502f58f2d640e3a2f5f7a99a7018f1b573befd92053ac6f78fca4a87268"), value: common.Hex2Bytes("")}, // step 24
{op: 1, key: common.Hex2Bytes("fd"), value: common.Hex2Bytes("")}, // step 25 {op: 1, key: common.Hex2Bytes("fd"), value: common.Hex2Bytes("")}, // step 25
} }
runRandTest(rt) if err := runRandTest(rt); err != nil {
t.Fatal(err)
}
} }
// randTest performs random trie operations. // randTest performs random trie operations.
@ -319,36 +321,53 @@ const (
) )
func (randTest) Generate(r *rand.Rand, size int) reflect.Value { func (randTest) Generate(r *rand.Rand, size int) reflect.Value {
var finishedFn = func() bool {
size--
return size > 0
}
return reflect.ValueOf(generateSteps(finishedFn, r))
}
func generateSteps(finished func() bool, r io.Reader) randTest {
var allKeys [][]byte var allKeys [][]byte
var one = []byte{0}
genKey := func() []byte { genKey := func() []byte {
if len(allKeys) < 2 || r.Intn(100) < 10 { r.Read(one)
if len(allKeys) < 2 || one[0]%100 > 90 {
// new key // new key
key := make([]byte, r.Intn(50)) size := one[0] % 50
key := make([]byte, size)
r.Read(key) r.Read(key)
allKeys = append(allKeys, key) allKeys = append(allKeys, key)
return key return key
} }
// use existing key // use existing key
return allKeys[r.Intn(len(allKeys))] idx := int(one[0]) % len(allKeys)
return allKeys[idx]
} }
var steps randTest var steps randTest
for i := 0; i < size; i++ { for !finished() {
step := randTestStep{op: r.Intn(opMax)} r.Read(one)
step := randTestStep{op: int(one[0]) % opMax}
switch step.op { switch step.op {
case opUpdate: case opUpdate:
step.key = genKey() step.key = genKey()
step.value = make([]byte, 8) step.value = make([]byte, 8)
binary.BigEndian.PutUint64(step.value, uint64(i)) binary.BigEndian.PutUint64(step.value, uint64(len(steps)))
case opGet, opDelete: case opGet, opDelete:
step.key = genKey() step.key = genKey()
} }
steps = append(steps, step) steps = append(steps, step)
} }
return reflect.ValueOf(steps) return steps
} }
func runRandTest(rt randTest) bool { // runRandTestBool coerces error to boolean, for use in quick.Check
func runRandTestBool(rt randTest) bool {
return runRandTest(rt) == nil
}
func runRandTest(rt randTest) error {
triedb := NewDatabase(memorydb.New()) triedb := NewDatabase(memorydb.New())
tr, _ := New(common.Hash{}, triedb) tr, _ := New(common.Hash{}, triedb)
@ -378,12 +397,12 @@ func runRandTest(rt randTest) bool {
hash, err := tr.Commit(nil) hash, err := tr.Commit(nil)
if err != nil { if err != nil {
rt[i].err = err rt[i].err = err
return false return err
} }
newtr, err := New(hash, triedb) newtr, err := New(hash, triedb)
if err != nil { if err != nil {
rt[i].err = err rt[i].err = err
return false return err
} }
tr = newtr tr = newtr
case opItercheckhash: case opItercheckhash:
@ -398,14 +417,14 @@ func runRandTest(rt randTest) bool {
} }
// Abort the test on error. // Abort the test on error.
if rt[i].err != nil { if rt[i].err != nil {
return false return rt[i].err
} }
} }
return true return nil
} }
func TestRandom(t *testing.T) { func TestRandom(t *testing.T) {
if err := quick.Check(runRandTest, nil); err != nil { if err := quick.Check(runRandTestBool, nil); err != nil {
if cerr, ok := err.(*quick.CheckError); ok { if cerr, ok := err.(*quick.CheckError); ok {
t.Fatalf("random test iteration %d failed: %s", cerr.Count, spew.Sdump(cerr.In)) t.Fatalf("random test iteration %d failed: %s", cerr.Count, spew.Sdump(cerr.In))
} }
@ -841,3 +860,17 @@ func TestDecodeNode(t *testing.T) {
decodeNode(hash, elems) decodeNode(hash, elems)
} }
} }
func FuzzTrie(f *testing.F) {
f.Fuzz(func(t *testing.T, data []byte) {
var steps = 500
var input = bytes.NewReader(data)
var finishedFn = func() bool {
steps--
return steps < 0 || input.Len() == 0
}
if err := runRandTest(generateSteps(finishedFn, input)); err != nil {
t.Fatal(err)
}
})
}