Skip to content

Commit

Permalink
fuzzing core/state package without skip slot cache (prysmaticlabs#4883)
Browse files Browse the repository at this point in the history
* fuzzing core/state package

* named error msg

* err comment

* terence feedback

* preston feedback

* preston feedback

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored and cryptomental committed Feb 24, 2020
1 parent 8f03a76 commit df2e59e
Show file tree
Hide file tree
Showing 10 changed files with 488 additions and 6 deletions.
1 change: 0 additions & 1 deletion beacon-chain/core/epoch/precompute/new.go
Expand Up @@ -15,7 +15,6 @@ import (
func New(ctx context.Context, state *stateTrie.BeaconState) ([]*Validator, *Balance) {
ctx, span := trace.StartSpan(ctx, "precomputeEpoch.New")
defer span.End()

vp := make([]*Validator, state.NumValidators())
bp := &Balance{}

Expand Down
3 changes: 3 additions & 0 deletions beacon-chain/core/state/BUILD.bazel
Expand Up @@ -44,7 +44,9 @@ go_test(
srcs = [
"benchmarks_test.go",
"skip_slot_cache_test.go",
"state_fuzz_test.go",
"state_test.go",
"transition_fuzz_test.go",
"transition_test.go",
],
data = ["//shared/benchutil/benchmark_files:benchmark_data"],
Expand All @@ -63,6 +65,7 @@ go_test(
"//shared/testutil:go_default_library",
"//shared/trieutil:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@com_github_google_gofuzz//:go_default_library",
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
Expand Down
4 changes: 4 additions & 0 deletions beacon-chain/core/state/state.go
Expand Up @@ -5,6 +5,7 @@ package state

import (
"context"
"fmt"

"github.com/pkg/errors"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
Expand Down Expand Up @@ -65,6 +66,9 @@ func GenesisBeaconState(deposits []*ethpb.Deposit, genesisTime uint64, eth1Data
// Process initial deposits.
leaves := [][]byte{}
for _, deposit := range deposits {
if deposit == nil || deposit.Data == nil {
return nil, fmt.Errorf("nil deposit or deposit with nil data cannot be processed: %v", deposit)
}
hash, err := ssz.HashTreeRoot(deposit.Data)
if err != nil {
return nil, err
Expand Down
60 changes: 60 additions & 0 deletions beacon-chain/core/state/state_fuzz_test.go
@@ -0,0 +1,60 @@
package state

import (
"testing"

fuzz "github.com/google/gofuzz"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
)

func TestGenesisBeaconState_1000(t *testing.T) {
fuzzer := fuzz.NewWithSeed(0)
fuzzer.NilChance(0.1)
deposits := make([]*ethpb.Deposit, 300000)
var genesisTime uint64
eth1Data := &ethpb.Eth1Data{}
for i := 0; i < 1000; i++ {
fuzzer.Fuzz(&deposits)
fuzzer.Fuzz(&genesisTime)
fuzzer.Fuzz(eth1Data)
gs, err := GenesisBeaconState(deposits, genesisTime, eth1Data)
if err != nil {
if gs != nil {
t.Fatalf("Genesis state should be nil on err. found: %v on error: %v for inputs deposit: %v "+
"genesis time: %v eth1data: %v", gs, err, deposits, genesisTime, eth1Data)
}
}
}
}

func TestOptimizedGenesisBeaconState_1000(t *testing.T) {
fuzzer := fuzz.NewWithSeed(0)
fuzzer.NilChance(0.1)
var genesisTime uint64
preState := &stateTrie.BeaconState{}
eth1Data := &ethpb.Eth1Data{}
for i := 0; i < 1000; i++ {
fuzzer.Fuzz(&genesisTime)
fuzzer.Fuzz(eth1Data)
fuzzer.Fuzz(preState)
gs, err := OptimizedGenesisBeaconState(genesisTime, preState, eth1Data)
if err != nil {
if gs != nil {
t.Fatalf("Genesis state should be nil on err. found: %v on error: %v for inputs genesis time: %v "+
"pre state: %v eth1data: %v", gs, err, genesisTime, preState, eth1Data)
}
}
}
}

func TestIsValidGenesisState_100000(t *testing.T) {
fuzzer := fuzz.NewWithSeed(0)
fuzzer.NilChance(0.1)
var chainStartDepositCount, currentTime uint64
for i := 0; i < 100000; i++ {
fuzzer.Fuzz(&chainStartDepositCount)
fuzzer.Fuzz(&currentTime)
IsValidGenesisState(chainStartDepositCount, currentTime)
}
}
20 changes: 16 additions & 4 deletions beacon-chain/core/state/transition.go
Expand Up @@ -157,6 +157,9 @@ func CalculateStateRoot(
traceutil.AnnotateError(span, ctx.Err())
return [32]byte{}, ctx.Err()
}
if state == nil {
return [32]byte{}, errors.New("nil state")
}
if signed == nil || signed.Block == nil {
return [32]byte{}, errors.New("nil block")
}
Expand Down Expand Up @@ -252,6 +255,9 @@ func ProcessSlot(ctx context.Context, state *stateTrie.BeaconState) (*stateTrie.
func ProcessSlots(ctx context.Context, state *stateTrie.BeaconState, slot uint64) (*stateTrie.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "beacon-chain.ChainService.ProcessSlots")
defer span.End()
if state == nil {
return nil, errors.New("nil state")
}
span.AddAttributes(trace.Int64Attribute("slots", int64(slot)-int64(state.Slot())))

if state.Slot() > slot {
Expand Down Expand Up @@ -563,11 +569,14 @@ func verifyOperationLengths(state *stateTrie.BeaconState, body *ethpb.BeaconBloc
params.BeaconConfig().MaxVoluntaryExits,
)
}

if state.Eth1DepositIndex() > state.Eth1Data().DepositCount {
return fmt.Errorf("expected state.deposit_index %d <= eth1data.deposit_count %d", state.Eth1DepositIndex(), state.Eth1Data().DepositCount)
eth1Data := state.Eth1Data()
if eth1Data == nil {
return errors.New("nil eth1data in state")
}
maxDeposits := mathutil.Min(params.BeaconConfig().MaxDeposits, state.Eth1Data().DepositCount-state.Eth1DepositIndex())
if state.Eth1DepositIndex() > eth1Data.DepositCount {
return fmt.Errorf("expected state.deposit_index %d <= eth1data.deposit_count %d", state.Eth1DepositIndex(), eth1Data.DepositCount)
}
maxDeposits := mathutil.Min(params.BeaconConfig().MaxDeposits, eth1Data.DepositCount-state.Eth1DepositIndex())
// Verify outstanding deposits are processed up to max number of deposits
if len(body.Deposits) != int(maxDeposits) {
return fmt.Errorf("incorrect outstanding deposits in block body, wanted: %d, got: %d",
Expand All @@ -593,6 +602,9 @@ func ProcessEpochPrecompute(ctx context.Context, state *stateTrie.BeaconState) (
defer span.End()
span.AddAttributes(trace.Int64Attribute("epoch", int64(helpers.CurrentEpoch(state))))

if state == nil {
return nil, errors.New("nil state")
}
vp, bp := precompute.New(ctx, state)
vp, bp, err := precompute.ProcessAttestations(ctx, state, vp, bp)
if err != nil {
Expand Down
204 changes: 204 additions & 0 deletions beacon-chain/core/state/transition_fuzz_test.go
@@ -0,0 +1,204 @@
package state

import (
"context"
"testing"

fuzz "github.com/google/gofuzz"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
)

func TestFuzzExecuteStateTransition_1000(t *testing.T) {
ctx := context.Background()
state := &stateTrie.BeaconState{}
sb := &ethpb.SignedBeaconBlock{}
fuzzer := fuzz.NewWithSeed(0)
fuzzer.NilChance(0.1)
for i := 0; i < 1000; i++ {
fuzzer.Fuzz(state)
fuzzer.Fuzz(sb)
s, err := ExecuteStateTransition(ctx, state, sb)
if err != nil && s != nil {
t.Fatalf("state should be nil on err. found: %v on error: %v for state: %v and signed block: %v", s, err, state, sb)
}
}
}

func TestFuzzExecuteStateTransitionNoVerifyAttSigs_1000(t *testing.T) {
ctx := context.Background()
state := &stateTrie.BeaconState{}
sb := &ethpb.SignedBeaconBlock{}
fuzzer := fuzz.NewWithSeed(0)
fuzzer.NilChance(0.1)
for i := 0; i < 1000; i++ {
fuzzer.Fuzz(state)
fuzzer.Fuzz(sb)
s, err := ExecuteStateTransitionNoVerifyAttSigs(ctx, state, sb)
if err != nil && s != nil {
t.Fatalf("state should be nil on err. found: %v on error: %v for state: %v and signed block: %v", s, err, state, sb)
}
}
}

func TestFuzzCalculateStateRoot_1000(t *testing.T) {
ctx := context.Background()
state := &stateTrie.BeaconState{}
sb := &ethpb.SignedBeaconBlock{}
fuzzer := fuzz.NewWithSeed(0)
fuzzer.NilChance(0.1)
for i := 0; i < 1000; i++ {
fuzzer.Fuzz(state)
fuzzer.Fuzz(sb)
stateRoot, err := CalculateStateRoot(ctx, state, sb)
if err != nil && stateRoot != [32]byte{} {
t.Fatalf("state root should be empty on err. found: %v on error: %v for signed block: %v", stateRoot, err, sb)
}
}
}

func TestFuzzProcessSlot_1000(t *testing.T) {
ctx := context.Background()
state := &stateTrie.BeaconState{}
fuzzer := fuzz.NewWithSeed(0)
fuzzer.NilChance(0.1)
for i := 0; i < 1000; i++ {
fuzzer.Fuzz(state)
s, err := ProcessSlot(ctx, state)
if err != nil && s != nil {
t.Fatalf("state should be nil on err. found: %v on error: %v for state: %v", s, err, state)
}
}
}

func TestFuzzProcessSlots_1000(t *testing.T) {
ctx := context.Background()
state := &stateTrie.BeaconState{}
slot := uint64(0)
fuzzer := fuzz.NewWithSeed(0)
fuzzer.NilChance(0.1)
for i := 0; i < 1000; i++ {
fuzzer.Fuzz(state)
fuzzer.Fuzz(&slot)
s, err := ProcessSlots(ctx, state, slot)
if err != nil && s != nil {
t.Fatalf("state should be nil on err. found: %v on error: %v for state: %v", s, err, state)
}
}
}

func TestFuzzProcessBlock_1000(t *testing.T) {
ctx := context.Background()
state := &stateTrie.BeaconState{}
sb := &ethpb.SignedBeaconBlock{}
fuzzer := fuzz.NewWithSeed(0)
fuzzer.NilChance(0.1)
for i := 0; i < 1000; i++ {
fuzzer.Fuzz(state)
fuzzer.Fuzz(sb)
s, err := ProcessBlock(ctx, state, sb)
if err != nil && s != nil {
t.Fatalf("state should be nil on err. found: %v on error: %v for signed block: %v", s, err, sb)
}
}
}

func TestFuzzProcessBlockNoVerifyAttSigs_1000(t *testing.T) {
ctx := context.Background()
state := &stateTrie.BeaconState{}
sb := &ethpb.SignedBeaconBlock{}
fuzzer := fuzz.NewWithSeed(0)
fuzzer.NilChance(0.1)
for i := 0; i < 1000; i++ {
fuzzer.Fuzz(state)
fuzzer.Fuzz(sb)
s, err := ProcessBlockNoVerifyAttSigs(ctx, state, sb)
if err != nil && s != nil {
t.Fatalf("state should be nil on err. found: %v on error: %v for signed block: %v", s, err, sb)
}
}
}

func TestFuzzProcessOperations_1000(t *testing.T) {
ctx := context.Background()
state := &stateTrie.BeaconState{}
bb := &ethpb.BeaconBlockBody{}
fuzzer := fuzz.NewWithSeed(0)
fuzzer.NilChance(0.1)
for i := 0; i < 1000; i++ {
fuzzer.Fuzz(state)
fuzzer.Fuzz(bb)
s, err := ProcessOperations(ctx, state, bb)
if err != nil && s != nil {
t.Fatalf("state should be nil on err. found: %v on error: %v for block body: %v", s, err, bb)
}
}
}

func TestFuzzprocessOperationsNoVerify_1000(t *testing.T) {
ctx := context.Background()
state := &stateTrie.BeaconState{}
bb := &ethpb.BeaconBlockBody{}
fuzzer := fuzz.NewWithSeed(0)
fuzzer.NilChance(0.1)
for i := 0; i < 1000; i++ {
fuzzer.Fuzz(state)
fuzzer.Fuzz(bb)
s, err := processOperationsNoVerify(ctx, state, bb)
if err != nil && s != nil {
t.Fatalf("state should be nil on err. found: %v on error: %v for block body: %v", s, err, bb)
}
}
}

func TestFuzzverifyOperationLengths_10000(t *testing.T) {
state := &stateTrie.BeaconState{}
bb := &ethpb.BeaconBlockBody{}
fuzzer := fuzz.NewWithSeed(0)
fuzzer.NilChance(0.1)
for i := 0; i < 10000; i++ {
fuzzer.Fuzz(state)
fuzzer.Fuzz(bb)
verifyOperationLengths(state, bb)
}
}

func TestFuzzCanProcessEpoch_10000(t *testing.T) {
state := &stateTrie.BeaconState{}
fuzzer := fuzz.NewWithSeed(0)
fuzzer.NilChance(0.1)
for i := 0; i < 10000; i++ {
fuzzer.Fuzz(state)
CanProcessEpoch(state)
}
}

func TestFuzzProcessEpochPrecompute_1000(t *testing.T) {
ctx := context.Background()
state := &stateTrie.BeaconState{}
fuzzer := fuzz.NewWithSeed(0)
fuzzer.NilChance(0.1)
for i := 0; i < 1000; i++ {
fuzzer.Fuzz(state)
s, err := ProcessEpochPrecompute(ctx, state)
if err != nil && s != nil {
t.Fatalf("state should be nil on err. found: %v on error: %v for state: %v", s, err, state)
}
}
}

func TestFuzzcomputeStateRoot_1000(t *testing.T) {
ctx := context.Background()
state := &stateTrie.BeaconState{}
sb := &ethpb.SignedBeaconBlock{}
fuzzer := fuzz.NewWithSeed(0)
fuzzer.NilChance(0.1)
for i := 0; i < 1000; i++ {
fuzzer.Fuzz(state)
fuzzer.Fuzz(sb)
s, err := computeStateRoot(ctx, state, sb)
if err != nil && s != nil {
t.Fatalf("state should be nil on err. found: %v on error: %v for signed block: %v", s, err, sb)
}
}
}

0 comments on commit df2e59e

Please sign in to comment.