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"
"fmt"
"hash"
"io"
"math/big"
"math/rand"
"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("fd"), value: common.Hex2Bytes("")}, // step 25
}
runRandTest(rt)
if err := runRandTest(rt); err != nil {
t.Fatal(err)
}
}
// randTest performs random trie operations.
@ -319,36 +321,53 @@ const (
)
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 one = []byte{0}
genKey := func() []byte {
if len(allKeys) < 2 || r.Intn(100) < 10 {
r.Read(one)
if len(allKeys) < 2 || one[0]%100 > 90 {
// new key
key := make([]byte, r.Intn(50))
size := one[0] % 50
key := make([]byte, size)
r.Read(key)
allKeys = append(allKeys, key)
return key
}
// use existing key
return allKeys[r.Intn(len(allKeys))]
idx := int(one[0]) % len(allKeys)
return allKeys[idx]
}
var steps randTest
for i := 0; i < size; i++ {
step := randTestStep{op: r.Intn(opMax)}
for !finished() {
r.Read(one)
step := randTestStep{op: int(one[0]) % opMax}
switch step.op {
case opUpdate:
step.key = genKey()
step.value = make([]byte, 8)
binary.BigEndian.PutUint64(step.value, uint64(i))
binary.BigEndian.PutUint64(step.value, uint64(len(steps)))
case opGet, opDelete:
step.key = genKey()
}
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())
tr, _ := New(common.Hash{}, triedb)
@ -378,12 +397,12 @@ func runRandTest(rt randTest) bool {
hash, err := tr.Commit(nil)
if err != nil {
rt[i].err = err
return false
return err
}
newtr, err := New(hash, triedb)
if err != nil {
rt[i].err = err
return false
return err
}
tr = newtr
case opItercheckhash:
@ -398,14 +417,14 @@ func runRandTest(rt randTest) bool {
}
// Abort the test on error.
if rt[i].err != nil {
return false
return rt[i].err
}
}
return true
return nil
}
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 {
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)
}
}
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)
}
})
}