Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fuzzing core/state package without skip slot cache #4883

Merged
merged 14 commits into from Feb 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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)
}
}
}