prysm-pulse/beacon-chain/state/stateutil/state_root_cache_fuzz_test.go
Preston Van Loon 973a0a89b5
Update state root cache to fuzz in parallel (#5364)
* Update state root cache to fuzz in parallel

* confirmed arrays passing

Co-authored-by: rauljordan <raul@prysmaticlabs.com>
2020-04-10 13:12:59 -05:00

129 lines
2.9 KiB
Go

package stateutil
import (
"strconv"
"sync"
"testing"
fuzz "github.com/google/gofuzz"
ethereum_beacon_p2p_v1 "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/mputil"
"github.com/prysmaticlabs/prysm/shared/params"
)
func init() {
params.UseMinimalConfig()
}
func TestStateRootCacheFuzz_10(t *testing.T) {
fuzzStateRootCache(t, 0, 10)
}
func TestStateRootCacheFuzz_100(t *testing.T) {
fuzzStateRootCache(t, 1, 100)
}
func TestStateRootCacheFuzz_1000(t *testing.T) {
fuzzStateRootCache(t, 2, 1000)
}
func fuzzStateRootCache(t *testing.T, seed int64, iterations uint64) {
fuzzer := fuzz.NewWithSeed(seed)
hasher := &stateRootHasher{}
hasherWithCache := cachedHasher
mismatch := 0
mismatchedIndices := make([]uint64, 0)
// Use scatter to run tests in parallel.
if _, err := mputil.Scatter(int(iterations), func(start int, length int, _ *sync.RWMutex) (i interface{}, err error) {
state := &ethereum_beacon_p2p_v1.BeaconState{}
for i := start; i < start+length; i++ {
func() {
defer func() {
recover() // Ignore fuzzing panics for out of range values
}()
fuzzer.Fuzz(state)
}()
var a, b [32]byte
func() {
defer func() {
if r := recover(); r != nil {
t.Errorf("Non-cached HTR panicked on iteration %d", i)
panic(r)
}
}()
var err error
a, err = hasher.hashTreeRootState(state)
if err != nil {
t.Fatal(err)
}
}()
func() {
defer func() {
if r := recover(); r != nil {
t.Errorf("Cached HTR panicked on iteration %d", i)
panic(r)
}
}()
var err error
b, err = hasherWithCache.hashTreeRootState(state)
if err != nil {
t.Fatal(err)
}
}()
if a != b {
mismatch++
mismatchedIndices = append(mismatchedIndices, uint64(i))
}
}
return nil, nil
}); err != nil {
t.Error(err)
}
if mismatch > 0 {
t.Errorf("Mismatched indices: %v", mismatchedIndices)
t.Fatalf("%d of %d random states had different roots", mismatch, iterations)
}
}
func TestHashTreeRootState_ElementsChanged_RecomputeBranch(t *testing.T) {
hasher := &stateRootHasher{}
hasherWithCache := cachedHasher
state := &ethereum_beacon_p2p_v1.BeaconState{}
initialRoots := make([][]byte, 5)
for i := 0; i < len(initialRoots); i++ {
var someRt [32]byte
copy(someRt[:], "hello")
initialRoots[i] = someRt[:]
}
state.RandaoMixes = initialRoots
if _, err := hasherWithCache.hashTreeRootState(state); err != nil {
t.Fatal(err)
}
badRoots := make([][]byte, 5)
for i := 0; i < len(badRoots); i++ {
var someRt [32]byte
copy(someRt[:], strconv.Itoa(i))
badRoots[i] = someRt[:]
}
state.RandaoMixes = badRoots
r1, err := hasher.hashTreeRootState(state)
if err != nil {
t.Fatal(err)
}
r2, err := hasherWithCache.hashTreeRootState(state)
if err != nil {
t.Fatal(err)
}
if r1 != r2 {
t.Errorf("Wanted %#x (nocache), received %#x (withcache)", r1, r2)
}
}