mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-02 11:11:16 +00:00
tests/fuzzers: move fuzzers into native packages (#28467)
This commit is contained in:
parent
441f8ed70c
commit
4cc2b2ea5f
8 changed files with 275 additions and 247 deletions
|
|
@ -18,6 +18,7 @@ package bitutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
|
@ -48,19 +49,23 @@ func TestEncodingCycle(t *testing.T) {
|
||||||
"0xdf7070533534333636313639343638373532313536346c1bc333393438373130707063363430353639343638373532313536346c1bc333393438336336346c65fe",
|
"0xdf7070533534333636313639343638373532313536346c1bc333393438373130707063363430353639343638373532313536346c1bc333393438336336346c65fe",
|
||||||
}
|
}
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
data := hexutil.MustDecode(tt)
|
if err := testEncodingCycle(hexutil.MustDecode(tt)); err != nil {
|
||||||
|
t.Errorf("test %d: %v", i, err)
|
||||||
proc, err := bitsetDecodeBytes(bitsetEncodeBytes(data), len(data))
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("test %d: failed to decompress compressed data: %v", i, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !bytes.Equal(data, proc) {
|
|
||||||
t.Errorf("test %d: compress/decompress mismatch: have %x, want %x", i, proc, data)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testEncodingCycle(data []byte) error {
|
||||||
|
proc, err := bitsetDecodeBytes(bitsetEncodeBytes(data), len(data))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to decompress compressed data: %v", err)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(data, proc) {
|
||||||
|
return fmt.Errorf("compress/decompress mismatch: have %x, want %x", proc, data)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Tests that data bitset decoding and rencoding works and is bijective.
|
// Tests that data bitset decoding and rencoding works and is bijective.
|
||||||
func TestDecodingCycle(t *testing.T) {
|
func TestDecodingCycle(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
|
|
@ -179,3 +184,41 @@ func benchmarkEncoding(b *testing.B, bytes int, fill float64) {
|
||||||
bitsetDecodeBytes(bitsetEncodeBytes(data), len(data))
|
bitsetDecodeBytes(bitsetEncodeBytes(data), len(data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FuzzEncoder(f *testing.F) {
|
||||||
|
f.Fuzz(func(t *testing.T, data []byte) {
|
||||||
|
if err := testEncodingCycle(data); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func FuzzDecoder(f *testing.F) {
|
||||||
|
f.Fuzz(func(t *testing.T, data []byte) {
|
||||||
|
fuzzDecode(data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// fuzzDecode implements a go-fuzz fuzzer method to test the bit decoding and
|
||||||
|
// reencoding algorithm.
|
||||||
|
func fuzzDecode(data []byte) {
|
||||||
|
blob, err := DecompressBytes(data, 1024)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// re-compress it (it's OK if the re-compressed differs from the
|
||||||
|
// original - the first input may not have been compressed at all)
|
||||||
|
comp := CompressBytes(blob)
|
||||||
|
if len(comp) > len(blob) {
|
||||||
|
// After compression, it must be smaller or equal
|
||||||
|
panic("bad compression")
|
||||||
|
}
|
||||||
|
// But decompressing it once again should work
|
||||||
|
decomp, err := DecompressBytes(data, 1024)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(decomp, blob) {
|
||||||
|
panic("content mismatch")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
147
core/types/rlp_fuzzer_test.go
Normal file
147
core/types/rlp_fuzzer_test.go
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
// Copyright 2019 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/rlp"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
|
)
|
||||||
|
|
||||||
|
func decodeEncode(input []byte, val interface{}) error {
|
||||||
|
if err := rlp.DecodeBytes(input, val); err != nil {
|
||||||
|
// not valid rlp, nothing to do
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// If it _were_ valid rlp, we can encode it again
|
||||||
|
output, err := rlp.EncodeToBytes(val)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !bytes.Equal(input, output) {
|
||||||
|
return fmt.Errorf("encode-decode is not equal, \ninput : %x\noutput: %x", input, output)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func FuzzRLP(f *testing.F) {
|
||||||
|
f.Fuzz(fuzzRlp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func fuzzRlp(t *testing.T, input []byte) {
|
||||||
|
if len(input) == 0 || len(input) > 500*1024 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rlp.Split(input)
|
||||||
|
if elems, _, err := rlp.SplitList(input); err == nil {
|
||||||
|
rlp.CountValues(elems)
|
||||||
|
}
|
||||||
|
rlp.NewStream(bytes.NewReader(input), 0).Decode(new(interface{}))
|
||||||
|
if err := decodeEncode(input, new(interface{})); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
var v struct {
|
||||||
|
Int uint
|
||||||
|
String string
|
||||||
|
Bytes []byte
|
||||||
|
}
|
||||||
|
if err := decodeEncode(input, &v); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
type Types struct {
|
||||||
|
Bool bool
|
||||||
|
Raw rlp.RawValue
|
||||||
|
Slice []*Types
|
||||||
|
Iface []interface{}
|
||||||
|
}
|
||||||
|
var v Types
|
||||||
|
if err := decodeEncode(input, &v); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
type AllTypes struct {
|
||||||
|
Int uint
|
||||||
|
String string
|
||||||
|
Bytes []byte
|
||||||
|
Bool bool
|
||||||
|
Raw rlp.RawValue
|
||||||
|
Slice []*AllTypes
|
||||||
|
Array [3]*AllTypes
|
||||||
|
Iface []interface{}
|
||||||
|
}
|
||||||
|
var v AllTypes
|
||||||
|
if err := decodeEncode(input, &v); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
if err := decodeEncode(input, [10]byte{}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
var v struct {
|
||||||
|
Byte [10]byte
|
||||||
|
Rool [10]bool
|
||||||
|
}
|
||||||
|
if err := decodeEncode(input, &v); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
var h Header
|
||||||
|
if err := decodeEncode(input, &h); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var b Block
|
||||||
|
if err := decodeEncode(input, &b); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var tx Transaction
|
||||||
|
if err := decodeEncode(input, &tx); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var txs Transactions
|
||||||
|
if err := decodeEncode(input, &txs); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var rs Receipts
|
||||||
|
if err := decodeEncode(input, &rs); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
var v struct {
|
||||||
|
AnIntPtr *big.Int
|
||||||
|
AnInt big.Int
|
||||||
|
AnU256Ptr *uint256.Int
|
||||||
|
AnU256 uint256.Int
|
||||||
|
NotAnU256 [4]uint64
|
||||||
|
}
|
||||||
|
if err := decodeEncode(input, &v); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -14,12 +14,31 @@
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package rlp
|
package vm
|
||||||
|
|
||||||
import "testing"
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
func Fuzz(f *testing.F) {
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
f.Fuzz(func(t *testing.T, data []byte) {
|
)
|
||||||
fuzz(data)
|
|
||||||
|
func FuzzPrecompiledContracts(f *testing.F) {
|
||||||
|
// Create list of addresses
|
||||||
|
var addrs []common.Address
|
||||||
|
for k := range allPrecompiles {
|
||||||
|
addrs = append(addrs, k)
|
||||||
|
}
|
||||||
|
f.Fuzz(func(t *testing.T, addr uint8, input []byte) {
|
||||||
|
a := addrs[int(addr)%len(addrs)]
|
||||||
|
p := allPrecompiles[a]
|
||||||
|
gas := p.RequiredGas(input)
|
||||||
|
if gas > 10_000_000 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
inWant := string(input)
|
||||||
|
RunPrecompiledContract(nil, p, input, gas)
|
||||||
|
if inHave := string(input); inWant != inHave {
|
||||||
|
t.Errorf("Precompiled %v modified input data", a)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -18,13 +18,11 @@ package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/vm/runtime"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Fuzz(f *testing.F) {
|
func FuzzVmRuntime(f *testing.F) {
|
||||||
f.Fuzz(func(t *testing.T, code, input []byte) {
|
f.Fuzz(func(t *testing.T, code, input []byte) {
|
||||||
runtime.Execute(code, input, &runtime.Config{
|
Execute(code, input, &Config{
|
||||||
GasLimit: 12000000,
|
GasLimit: 12000000,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
// Copyright 2023 The go-ethereum Authors
|
|
||||||
// This file is part of the go-ethereum library.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package bitutil
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/common/bitutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
func FuzzEncoder(f *testing.F) {
|
|
||||||
f.Fuzz(func(t *testing.T, data []byte) {
|
|
||||||
fuzzEncode(data)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
func FuzzDecoder(f *testing.F) {
|
|
||||||
f.Fuzz(func(t *testing.T, data []byte) {
|
|
||||||
fuzzDecode(data)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// fuzzEncode implements a go-fuzz fuzzer method to test the bitset encoding and
|
|
||||||
// decoding algorithm.
|
|
||||||
func fuzzEncode(data []byte) {
|
|
||||||
proc, _ := bitutil.DecompressBytes(bitutil.CompressBytes(data), len(data))
|
|
||||||
if !bytes.Equal(data, proc) {
|
|
||||||
panic("content mismatch")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fuzzDecode implements a go-fuzz fuzzer method to test the bit decoding and
|
|
||||||
// reencoding algorithm.
|
|
||||||
func fuzzDecode(data []byte) {
|
|
||||||
blob, err := bitutil.DecompressBytes(data, 1024)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// re-compress it (it's OK if the re-compressed differs from the
|
|
||||||
// original - the first input may not have been compressed at all)
|
|
||||||
comp := bitutil.CompressBytes(blob)
|
|
||||||
if len(comp) > len(blob) {
|
|
||||||
// After compression, it must be smaller or equal
|
|
||||||
panic("bad compression")
|
|
||||||
}
|
|
||||||
// But decompressing it once again should work
|
|
||||||
decomp, err := bitutil.DecompressBytes(data, 1024)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
if !bytes.Equal(decomp, blob) {
|
|
||||||
panic("content mismatch")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,143 +0,0 @@
|
||||||
// Copyright 2019 The go-ethereum Authors
|
|
||||||
// This file is part of the go-ethereum library.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package rlp
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/rlp"
|
|
||||||
"github.com/holiman/uint256"
|
|
||||||
)
|
|
||||||
|
|
||||||
func decodeEncode(input []byte, val interface{}, i int) {
|
|
||||||
if err := rlp.DecodeBytes(input, val); err == nil {
|
|
||||||
output, err := rlp.EncodeToBytes(val)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
if !bytes.Equal(input, output) {
|
|
||||||
panic(fmt.Sprintf("case %d: encode-decode is not equal, \ninput : %x\noutput: %x", i, input, output))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func fuzz(input []byte) int {
|
|
||||||
if len(input) == 0 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
if len(input) > 500*1024 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
var i int
|
|
||||||
{
|
|
||||||
rlp.Split(input)
|
|
||||||
}
|
|
||||||
{
|
|
||||||
if elems, _, err := rlp.SplitList(input); err == nil {
|
|
||||||
rlp.CountValues(elems)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
rlp.NewStream(bytes.NewReader(input), 0).Decode(new(interface{}))
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
decodeEncode(input, new(interface{}), i)
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
{
|
|
||||||
var v struct {
|
|
||||||
Int uint
|
|
||||||
String string
|
|
||||||
Bytes []byte
|
|
||||||
}
|
|
||||||
decodeEncode(input, &v, i)
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
type Types struct {
|
|
||||||
Bool bool
|
|
||||||
Raw rlp.RawValue
|
|
||||||
Slice []*Types
|
|
||||||
Iface []interface{}
|
|
||||||
}
|
|
||||||
var v Types
|
|
||||||
decodeEncode(input, &v, i)
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
{
|
|
||||||
type AllTypes struct {
|
|
||||||
Int uint
|
|
||||||
String string
|
|
||||||
Bytes []byte
|
|
||||||
Bool bool
|
|
||||||
Raw rlp.RawValue
|
|
||||||
Slice []*AllTypes
|
|
||||||
Array [3]*AllTypes
|
|
||||||
Iface []interface{}
|
|
||||||
}
|
|
||||||
var v AllTypes
|
|
||||||
decodeEncode(input, &v, i)
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
{
|
|
||||||
decodeEncode(input, [10]byte{}, i)
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
{
|
|
||||||
var v struct {
|
|
||||||
Byte [10]byte
|
|
||||||
Rool [10]bool
|
|
||||||
}
|
|
||||||
decodeEncode(input, &v, i)
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
{
|
|
||||||
var h types.Header
|
|
||||||
decodeEncode(input, &h, i)
|
|
||||||
i++
|
|
||||||
var b types.Block
|
|
||||||
decodeEncode(input, &b, i)
|
|
||||||
i++
|
|
||||||
var t types.Transaction
|
|
||||||
decodeEncode(input, &t, i)
|
|
||||||
i++
|
|
||||||
var txs types.Transactions
|
|
||||||
decodeEncode(input, &txs, i)
|
|
||||||
i++
|
|
||||||
var rs types.Receipts
|
|
||||||
decodeEncode(input, &rs, i)
|
|
||||||
}
|
|
||||||
{
|
|
||||||
i++
|
|
||||||
var v struct {
|
|
||||||
AnIntPtr *big.Int
|
|
||||||
AnInt big.Int
|
|
||||||
AnU256Ptr *uint256.Int
|
|
||||||
AnU256 uint256.Int
|
|
||||||
NotAnU256 [4]uint64
|
|
||||||
}
|
|
||||||
decodeEncode(input, &v, i)
|
|
||||||
}
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
@ -35,7 +35,7 @@ func Fuzz(f *testing.F) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func fuzz(dataP1, dataP2 []byte) int {
|
func fuzz(dataP1, dataP2 []byte) {
|
||||||
var (
|
var (
|
||||||
curveA = secp256k1.S256()
|
curveA = secp256k1.S256()
|
||||||
curveB = btcec.S256()
|
curveB = btcec.S256()
|
||||||
|
|
@ -50,5 +50,4 @@ func fuzz(dataP1, dataP2 []byte) int {
|
||||||
fmt.Printf("%s %s %s %s\n", x1, y1, x2, y2)
|
fmt.Printf("%s %s %s %s\n", x1, y1, x2, y2)
|
||||||
panic(fmt.Sprintf("Addition failed: geth: %s %s btcd: %s %s", resAX, resAY, resBX, resBY))
|
panic(fmt.Sprintf("Addition failed: geth: %s %s btcd: %s %s", resAX, resAY, resBX, resBY))
|
||||||
}
|
}
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -346,8 +347,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.
|
||||||
|
|
@ -373,36 +375,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)
|
||||||
|
|
@ -432,12 +451,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:
|
||||||
|
|
@ -452,14 +471,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))
|
||||||
}
|
}
|
||||||
|
|
@ -854,3 +873,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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue