diff --git a/beacon-chain/core/epoch/precompute/new.go b/beacon-chain/core/epoch/precompute/new.go index 9671c3ffad80..06d150eb5ddf 100644 --- a/beacon-chain/core/epoch/precompute/new.go +++ b/beacon-chain/core/epoch/precompute/new.go @@ -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{} diff --git a/beacon-chain/core/state/BUILD.bazel b/beacon-chain/core/state/BUILD.bazel index 5df1c2e76513..20825cc075a0 100644 --- a/beacon-chain/core/state/BUILD.bazel +++ b/beacon-chain/core/state/BUILD.bazel @@ -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"], @@ -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", diff --git a/beacon-chain/core/state/state.go b/beacon-chain/core/state/state.go index 4e8a80d1006a..33116c958b36 100644 --- a/beacon-chain/core/state/state.go +++ b/beacon-chain/core/state/state.go @@ -5,6 +5,7 @@ package state import ( "context" + "fmt" "github.com/pkg/errors" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" @@ -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 diff --git a/beacon-chain/core/state/state_fuzz_test.go b/beacon-chain/core/state/state_fuzz_test.go new file mode 100644 index 000000000000..ddd647d34910 --- /dev/null +++ b/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 := ðpb.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 := ðpb.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(¤tTime) + IsValidGenesisState(chainStartDepositCount, currentTime) + } +} diff --git a/beacon-chain/core/state/transition.go b/beacon-chain/core/state/transition.go index 3fa7eb028115..256df5f431b8 100644 --- a/beacon-chain/core/state/transition.go +++ b/beacon-chain/core/state/transition.go @@ -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") } @@ -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 { @@ -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", @@ -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 { diff --git a/beacon-chain/core/state/transition_fuzz_test.go b/beacon-chain/core/state/transition_fuzz_test.go new file mode 100644 index 000000000000..2ba8a942f66a --- /dev/null +++ b/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 := ðpb.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 := ðpb.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 := ðpb.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 := ðpb.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 := ðpb.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 := ðpb.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 := ðpb.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 := ðpb.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 := ðpb.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) + } + } +} diff --git a/beacon-chain/state/getters.go b/beacon-chain/state/getters.go index a501fceacbf7..ba4594df5ceb 100644 --- a/beacon-chain/state/getters.go +++ b/beacon-chain/state/getters.go @@ -107,16 +107,25 @@ func (b *BeaconState) HasInnerState() bool { // GenesisTime of the beacon state as a uint64. func (b *BeaconState) GenesisTime() uint64 { + if !b.HasInnerState() { + return 0 + } return b.state.GenesisTime } // Slot of the current beacon chain state. func (b *BeaconState) Slot() uint64 { + if !b.HasInnerState() { + return 0 + } return b.state.Slot } // Fork version of the beacon chain. func (b *BeaconState) Fork() *pbp2p.Fork { + if !b.HasInnerState() { + return nil + } if b.state.Fork == nil { return nil } @@ -137,6 +146,9 @@ func (b *BeaconState) Fork() *pbp2p.Fork { // LatestBlockHeader stored within the beacon state. func (b *BeaconState) LatestBlockHeader() *ethpb.BeaconBlockHeader { + if !b.HasInnerState() { + return nil + } if b.state.LatestBlockHeader == nil { return nil } @@ -163,6 +175,9 @@ func (b *BeaconState) LatestBlockHeader() *ethpb.BeaconBlockHeader { // BlockRoots kept track of in the beacon state. func (b *BeaconState) BlockRoots() [][]byte { + if !b.HasInnerState() { + return nil + } b.lock.RLock() defer b.lock.RUnlock() @@ -181,6 +196,9 @@ func (b *BeaconState) BlockRoots() [][]byte { // BlockRootAtIndex retrieves a specific block root based on an // input index value. func (b *BeaconState) BlockRootAtIndex(idx uint64) ([]byte, error) { + if !b.HasInnerState() { + return nil, ErrNilInnerState + } if b.state.BlockRoots == nil { return nil, nil } @@ -198,6 +216,9 @@ func (b *BeaconState) BlockRootAtIndex(idx uint64) ([]byte, error) { // StateRoots kept track of in the beacon state. func (b *BeaconState) StateRoots() [][]byte { + if !b.HasInnerState() { + return nil + } if b.state.StateRoots == nil { return nil } @@ -216,6 +237,9 @@ func (b *BeaconState) StateRoots() [][]byte { // HistoricalRoots based on epochs stored in the beacon state. func (b *BeaconState) HistoricalRoots() [][]byte { + if !b.HasInnerState() { + return nil + } if b.state.HistoricalRoots == nil { return nil } @@ -234,6 +258,9 @@ func (b *BeaconState) HistoricalRoots() [][]byte { // Eth1Data corresponding to the proof-of-work chain information stored in the beacon state. func (b *BeaconState) Eth1Data() *ethpb.Eth1Data { + if !b.HasInnerState() { + return nil + } if b.state.Eth1Data == nil { return nil } @@ -243,6 +270,9 @@ func (b *BeaconState) Eth1Data() *ethpb.Eth1Data { // Eth1DataVotes corresponds to votes from eth2 on the canonical proof-of-work chain // data retrieved from eth1. func (b *BeaconState) Eth1DataVotes() []*ethpb.Eth1Data { + if !b.HasInnerState() { + return nil + } if b.state.Eth1DataVotes == nil { return nil } @@ -256,11 +286,17 @@ func (b *BeaconState) Eth1DataVotes() []*ethpb.Eth1Data { // Eth1DepositIndex corresponds to the index of the deposit made to the // validator deposit contract at the time of this state's eth1 data. func (b *BeaconState) Eth1DepositIndex() uint64 { + if !b.HasInnerState() { + return 0 + } return b.state.Eth1DepositIndex } // Validators participating in consensus on the beacon chain. func (b *BeaconState) Validators() []*ethpb.Validator { + if !b.HasInnerState() { + return nil + } if b.state.Validators == nil { return nil } @@ -295,6 +331,9 @@ func (b *BeaconState) Validators() []*ethpb.Validator { // ValidatorsReadOnly returns validators participating in consensus on the beacon chain. This // method doesn't clone the respective validators and returns read only references to the validators. func (b *BeaconState) ValidatorsReadOnly() []*ReadOnlyValidator { + if !b.HasInnerState() { + return nil + } if b.state.Validators == nil { return nil } @@ -312,6 +351,9 @@ func (b *BeaconState) ValidatorsReadOnly() []*ReadOnlyValidator { // ValidatorAtIndex is the validator at the provided index. func (b *BeaconState) ValidatorAtIndex(idx uint64) (*ethpb.Validator, error) { + if !b.HasInnerState() { + return nil, ErrNilInnerState + } if b.state.Validators == nil { return ðpb.Validator{}, nil } @@ -342,6 +384,9 @@ func (b *BeaconState) ValidatorAtIndex(idx uint64) (*ethpb.Validator, error) { // ValidatorAtIndexReadOnly is the validator at the provided index.This method // doesn't clone the validator. func (b *BeaconState) ValidatorAtIndexReadOnly(idx uint64) (*ReadOnlyValidator, error) { + if !b.HasInnerState() { + return nil, ErrNilInnerState + } if b.state.Validators == nil { return &ReadOnlyValidator{}, nil } @@ -378,6 +423,9 @@ func (b *BeaconState) validatorIndexMap() map[[48]byte]uint64 { // PubkeyAtIndex returns the pubkey at the given // validator index. func (b *BeaconState) PubkeyAtIndex(idx uint64) [48]byte { + if !b.HasInnerState() { + return [48]byte{} + } b.lock.RLock() defer b.lock.RUnlock() @@ -386,12 +434,18 @@ func (b *BeaconState) PubkeyAtIndex(idx uint64) [48]byte { // NumValidators returns the size of the validator registry. func (b *BeaconState) NumValidators() int { + if !b.HasInnerState() { + return 0 + } return len(b.state.Validators) } // ReadFromEveryValidator reads values from every validator and applies it to the provided function. // Warning: This method is potentially unsafe, as it exposes the actual validator registry. func (b *BeaconState) ReadFromEveryValidator(f func(idx int, val *ReadOnlyValidator) error) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.RLock() defer b.lock.RUnlock() @@ -406,6 +460,9 @@ func (b *BeaconState) ReadFromEveryValidator(f func(idx int, val *ReadOnlyValida // Balances of validators participating in consensus on the beacon chain. func (b *BeaconState) Balances() []uint64 { + if !b.HasInnerState() { + return nil + } if b.state.Balances == nil { return nil } @@ -419,6 +476,9 @@ func (b *BeaconState) Balances() []uint64 { // BalanceAtIndex of validator with the provided index. func (b *BeaconState) BalanceAtIndex(idx uint64) (uint64, error) { + if !b.HasInnerState() { + return 0, ErrNilInnerState + } if b.state.Balances == nil { return 0, nil } @@ -434,6 +494,9 @@ func (b *BeaconState) BalanceAtIndex(idx uint64) (uint64, error) { // BalancesLength returns the length of the balances slice. func (b *BeaconState) BalancesLength() int { + if !b.HasInnerState() { + return 0 + } if b.state.Balances == nil { return 0 } @@ -446,6 +509,9 @@ func (b *BeaconState) BalancesLength() int { // RandaoMixes of block proposers on the beacon chain. func (b *BeaconState) RandaoMixes() [][]byte { + if !b.HasInnerState() { + return nil + } if b.state.RandaoMixes == nil { return nil } @@ -465,6 +531,9 @@ func (b *BeaconState) RandaoMixes() [][]byte { // RandaoMixAtIndex retrieves a specific block root based on an // input index value. func (b *BeaconState) RandaoMixAtIndex(idx uint64) ([]byte, error) { + if !b.HasInnerState() { + return nil, ErrNilInnerState + } if b.state.RandaoMixes == nil { return nil, nil } @@ -482,6 +551,9 @@ func (b *BeaconState) RandaoMixAtIndex(idx uint64) ([]byte, error) { // RandaoMixesLength returns the length of the randao mixes slice. func (b *BeaconState) RandaoMixesLength() int { + if !b.HasInnerState() { + return 0 + } if b.state.RandaoMixes == nil { return 0 } @@ -494,6 +566,9 @@ func (b *BeaconState) RandaoMixesLength() int { // Slashings of validators on the beacon chain. func (b *BeaconState) Slashings() []uint64 { + if !b.HasInnerState() { + return nil + } if b.state.Slashings == nil { return nil } @@ -508,6 +583,9 @@ func (b *BeaconState) Slashings() []uint64 { // PreviousEpochAttestations corresponding to blocks on the beacon chain. func (b *BeaconState) PreviousEpochAttestations() []*pbp2p.PendingAttestation { + if !b.HasInnerState() { + return nil + } if b.state.PreviousEpochAttestations == nil { return nil } @@ -524,6 +602,9 @@ func (b *BeaconState) PreviousEpochAttestations() []*pbp2p.PendingAttestation { // CurrentEpochAttestations corresponding to blocks on the beacon chain. func (b *BeaconState) CurrentEpochAttestations() []*pbp2p.PendingAttestation { + if !b.HasInnerState() { + return nil + } if b.state.CurrentEpochAttestations == nil { return nil } @@ -540,6 +621,9 @@ func (b *BeaconState) CurrentEpochAttestations() []*pbp2p.PendingAttestation { // JustificationBits marking which epochs have been justified in the beacon chain. func (b *BeaconState) JustificationBits() bitfield.Bitvector4 { + if !b.HasInnerState() { + return nil + } if b.state.JustificationBits == nil { return nil } @@ -554,6 +638,9 @@ func (b *BeaconState) JustificationBits() bitfield.Bitvector4 { // PreviousJustifiedCheckpoint denoting an epoch and block root. func (b *BeaconState) PreviousJustifiedCheckpoint() *ethpb.Checkpoint { + if !b.HasInnerState() { + return nil + } if b.state.PreviousJustifiedCheckpoint == nil { return nil } @@ -566,6 +653,9 @@ func (b *BeaconState) PreviousJustifiedCheckpoint() *ethpb.Checkpoint { // CurrentJustifiedCheckpoint denoting an epoch and block root. func (b *BeaconState) CurrentJustifiedCheckpoint() *ethpb.Checkpoint { + if !b.HasInnerState() { + return nil + } if b.state.CurrentJustifiedCheckpoint == nil { return nil } @@ -578,6 +668,9 @@ func (b *BeaconState) CurrentJustifiedCheckpoint() *ethpb.Checkpoint { // FinalizedCheckpoint denoting an epoch and block root. func (b *BeaconState) FinalizedCheckpoint() *ethpb.Checkpoint { + if !b.HasInnerState() { + return nil + } if b.state.FinalizedCheckpoint == nil { return nil } @@ -590,6 +683,9 @@ func (b *BeaconState) FinalizedCheckpoint() *ethpb.Checkpoint { // FinalizedCheckpointEpoch returns the epoch value of the finalized checkpoint. func (b *BeaconState) FinalizedCheckpointEpoch() uint64 { + if !b.HasInnerState() { + return 0 + } if b.state.FinalizedCheckpoint == nil { return 0 } diff --git a/beacon-chain/state/setters.go b/beacon-chain/state/setters.go index a46f7dea4738..e104d2d99ad5 100644 --- a/beacon-chain/state/setters.go +++ b/beacon-chain/state/setters.go @@ -53,6 +53,9 @@ func (b *BeaconState) SetGenesisTime(val uint64) error { // SetSlot for the beacon state. func (b *BeaconState) SetSlot(val uint64) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.Lock() defer b.lock.Unlock() @@ -63,6 +66,9 @@ func (b *BeaconState) SetSlot(val uint64) error { // SetFork version for the beacon chain. func (b *BeaconState) SetFork(val *pbp2p.Fork) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.Lock() defer b.lock.Unlock() @@ -73,6 +79,9 @@ func (b *BeaconState) SetFork(val *pbp2p.Fork) error { // SetLatestBlockHeader in the beacon state. func (b *BeaconState) SetLatestBlockHeader(val *ethpb.BeaconBlockHeader) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.Lock() defer b.lock.Unlock() @@ -84,6 +93,9 @@ func (b *BeaconState) SetLatestBlockHeader(val *ethpb.BeaconBlockHeader) error { // SetBlockRoots for the beacon state. This PR updates the entire // list to a new value by overwriting the previous one. func (b *BeaconState) SetBlockRoots(val [][]byte) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.Lock() defer b.lock.Unlock() @@ -98,6 +110,9 @@ func (b *BeaconState) SetBlockRoots(val [][]byte) error { // UpdateBlockRootAtIndex for the beacon state. This PR updates the randao mixes // at a specific index to a new value. func (b *BeaconState) UpdateBlockRootAtIndex(idx uint64, blockRoot [32]byte) error { + if !b.HasInnerState() { + return ErrNilInnerState + } if len(b.state.BlockRoots) <= int(idx) { return fmt.Errorf("invalid index provided %d", idx) } @@ -127,6 +142,9 @@ func (b *BeaconState) UpdateBlockRootAtIndex(idx uint64, blockRoot [32]byte) err // SetStateRoots for the beacon state. This PR updates the entire // to a new value by overwriting the previous one. func (b *BeaconState) SetStateRoots(val [][]byte) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.Lock() defer b.lock.Unlock() @@ -141,6 +159,9 @@ func (b *BeaconState) SetStateRoots(val [][]byte) error { // UpdateStateRootAtIndex for the beacon state. This PR updates the randao mixes // at a specific index to a new value. func (b *BeaconState) UpdateStateRootAtIndex(idx uint64, stateRoot [32]byte) error { + if !b.HasInnerState() { + return ErrNilInnerState + } if len(b.state.StateRoots) <= int(idx) { return errors.Errorf("invalid index provided %d", idx) } @@ -171,6 +192,9 @@ func (b *BeaconState) UpdateStateRootAtIndex(idx uint64, stateRoot [32]byte) err // SetHistoricalRoots for the beacon state. This PR updates the entire // list to a new value by overwriting the previous one. func (b *BeaconState) SetHistoricalRoots(val [][]byte) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.Lock() defer b.lock.Unlock() @@ -184,6 +208,9 @@ func (b *BeaconState) SetHistoricalRoots(val [][]byte) error { // SetEth1Data for the beacon state. func (b *BeaconState) SetEth1Data(val *ethpb.Eth1Data) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.Lock() defer b.lock.Unlock() @@ -195,6 +222,9 @@ func (b *BeaconState) SetEth1Data(val *ethpb.Eth1Data) error { // SetEth1DataVotes for the beacon state. This PR updates the entire // list to a new value by overwriting the previous one. func (b *BeaconState) SetEth1DataVotes(val []*ethpb.Eth1Data) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.Lock() defer b.lock.Unlock() @@ -209,6 +239,9 @@ func (b *BeaconState) SetEth1DataVotes(val []*ethpb.Eth1Data) error { // AppendEth1DataVotes for the beacon state. This PR appends the new value // to the the end of list. func (b *BeaconState) AppendEth1DataVotes(val *ethpb.Eth1Data) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.RLock() votes := b.state.Eth1DataVotes if b.sharedFieldReferences[eth1DataVotes].refs > 1 { @@ -228,6 +261,9 @@ func (b *BeaconState) AppendEth1DataVotes(val *ethpb.Eth1Data) error { // SetEth1DepositIndex for the beacon state. func (b *BeaconState) SetEth1DepositIndex(val uint64) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.Lock() defer b.lock.Unlock() @@ -239,6 +275,9 @@ func (b *BeaconState) SetEth1DepositIndex(val uint64) error { // SetValidators for the beacon state. This PR updates the entire // to a new value by overwriting the previous one. func (b *BeaconState) SetValidators(val []*ethpb.Validator) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.Lock() defer b.lock.Unlock() @@ -252,6 +291,9 @@ func (b *BeaconState) SetValidators(val []*ethpb.Validator) error { // ApplyToEveryValidator applies the provided callback function to each validator in the // validator registry. func (b *BeaconState) ApplyToEveryValidator(f func(idx int, val *ethpb.Validator) error) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.RLock() v := b.state.Validators if ref := b.sharedFieldReferences[validators]; ref.refs > 1 { @@ -281,6 +323,9 @@ func (b *BeaconState) ApplyToEveryValidator(f func(idx int, val *ethpb.Validator // UpdateValidatorAtIndex for the beacon state. This PR updates the randao mixes // at a specific index to a new value. func (b *BeaconState) UpdateValidatorAtIndex(idx uint64, val *ethpb.Validator) error { + if !b.HasInnerState() { + return ErrNilInnerState + } if len(b.state.Validators) <= int(idx) { return errors.Errorf("invalid index provided %d", idx) } @@ -321,6 +366,9 @@ func (b *BeaconState) SetValidatorIndexByPubkey(pubKey [48]byte, validatorIdx ui // SetBalances for the beacon state. This PR updates the entire // list to a new value by overwriting the previous one. func (b *BeaconState) SetBalances(val []uint64) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.Lock() defer b.lock.Unlock() @@ -335,6 +383,9 @@ func (b *BeaconState) SetBalances(val []uint64) error { // UpdateBalancesAtIndex for the beacon state. This method updates the balance // at a specific index to a new value. func (b *BeaconState) UpdateBalancesAtIndex(idx uint64, val uint64) error { + if !b.HasInnerState() { + return ErrNilInnerState + } if len(b.state.Balances) <= int(idx) { return errors.Errorf("invalid index provided %d", idx) } @@ -360,6 +411,9 @@ func (b *BeaconState) UpdateBalancesAtIndex(idx uint64, val uint64) error { // SetRandaoMixes for the beacon state. This PR updates the entire // list to a new value by overwriting the previous one. func (b *BeaconState) SetRandaoMixes(val [][]byte) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.Lock() defer b.lock.Unlock() @@ -374,6 +428,9 @@ func (b *BeaconState) SetRandaoMixes(val [][]byte) error { // UpdateRandaoMixesAtIndex for the beacon state. This PR updates the randao mixes // at a specific index to a new value. func (b *BeaconState) UpdateRandaoMixesAtIndex(val []byte, idx uint64) error { + if !b.HasInnerState() { + return ErrNilInnerState + } if len(b.state.RandaoMixes) <= int(idx) { return errors.Errorf("invalid index provided %d", idx) } @@ -399,6 +456,9 @@ func (b *BeaconState) UpdateRandaoMixesAtIndex(val []byte, idx uint64) error { // SetSlashings for the beacon state. This PR updates the entire // list to a new value by overwriting the previous one. func (b *BeaconState) SetSlashings(val []uint64) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.Lock() defer b.lock.Unlock() @@ -413,6 +473,9 @@ func (b *BeaconState) SetSlashings(val []uint64) error { // UpdateSlashingsAtIndex for the beacon state. This PR updates the randao mixes // at a specific index to a new value. func (b *BeaconState) UpdateSlashingsAtIndex(idx uint64, val uint64) error { + if !b.HasInnerState() { + return ErrNilInnerState + } if len(b.state.Slashings) <= int(idx) { return errors.Errorf("invalid index provided %d", idx) } @@ -440,6 +503,9 @@ func (b *BeaconState) UpdateSlashingsAtIndex(idx uint64, val uint64) error { // SetPreviousEpochAttestations for the beacon state. This PR updates the entire // list to a new value by overwriting the previous one. func (b *BeaconState) SetPreviousEpochAttestations(val []*pbp2p.PendingAttestation) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.Lock() defer b.lock.Unlock() @@ -454,6 +520,9 @@ func (b *BeaconState) SetPreviousEpochAttestations(val []*pbp2p.PendingAttestati // SetCurrentEpochAttestations for the beacon state. This PR updates the entire // list to a new value by overwriting the previous one. func (b *BeaconState) SetCurrentEpochAttestations(val []*pbp2p.PendingAttestation) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.Lock() defer b.lock.Unlock() @@ -468,6 +537,9 @@ func (b *BeaconState) SetCurrentEpochAttestations(val []*pbp2p.PendingAttestatio // AppendHistoricalRoots for the beacon state. This PR appends the new value // to the the end of list. func (b *BeaconState) AppendHistoricalRoots(root [32]byte) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.RLock() roots := b.state.HistoricalRoots if b.sharedFieldReferences[historicalRoots].refs > 1 { @@ -488,6 +560,9 @@ func (b *BeaconState) AppendHistoricalRoots(root [32]byte) error { // AppendCurrentEpochAttestations for the beacon state. This PR appends the new value // to the the end of list. func (b *BeaconState) AppendCurrentEpochAttestations(val *pbp2p.PendingAttestation) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.RLock() atts := b.state.CurrentEpochAttestations @@ -509,6 +584,9 @@ func (b *BeaconState) AppendCurrentEpochAttestations(val *pbp2p.PendingAttestati // AppendPreviousEpochAttestations for the beacon state. This PR appends the new value // to the the end of list. func (b *BeaconState) AppendPreviousEpochAttestations(val *pbp2p.PendingAttestation) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.RLock() atts := b.state.PreviousEpochAttestations if b.sharedFieldReferences[previousEpochAttestations].refs > 1 { @@ -529,6 +607,9 @@ func (b *BeaconState) AppendPreviousEpochAttestations(val *pbp2p.PendingAttestat // AppendValidator for the beacon state. This PR appends the new value // to the the end of list. func (b *BeaconState) AppendValidator(val *ethpb.Validator) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.RLock() vals := b.state.Validators if b.sharedFieldReferences[validators].refs > 1 { @@ -549,6 +630,9 @@ func (b *BeaconState) AppendValidator(val *ethpb.Validator) error { // AppendBalance for the beacon state. This PR appends the new value // to the the end of list. func (b *BeaconState) AppendBalance(bal uint64) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.RLock() bals := b.state.Balances @@ -569,6 +653,9 @@ func (b *BeaconState) AppendBalance(bal uint64) error { // SetJustificationBits for the beacon state. func (b *BeaconState) SetJustificationBits(val bitfield.Bitvector4) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.Lock() defer b.lock.Unlock() @@ -579,6 +666,9 @@ func (b *BeaconState) SetJustificationBits(val bitfield.Bitvector4) error { // SetPreviousJustifiedCheckpoint for the beacon state. func (b *BeaconState) SetPreviousJustifiedCheckpoint(val *ethpb.Checkpoint) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.Lock() defer b.lock.Unlock() @@ -589,6 +679,9 @@ func (b *BeaconState) SetPreviousJustifiedCheckpoint(val *ethpb.Checkpoint) erro // SetCurrentJustifiedCheckpoint for the beacon state. func (b *BeaconState) SetCurrentJustifiedCheckpoint(val *ethpb.Checkpoint) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.Lock() defer b.lock.Unlock() @@ -599,6 +692,9 @@ func (b *BeaconState) SetCurrentJustifiedCheckpoint(val *ethpb.Checkpoint) error // SetFinalizedCheckpoint for the beacon state. func (b *BeaconState) SetFinalizedCheckpoint(val *ethpb.Checkpoint) error { + if !b.HasInnerState() { + return ErrNilInnerState + } b.lock.Lock() defer b.lock.Unlock() diff --git a/beacon-chain/state/types.go b/beacon-chain/state/types.go index 35cb9c0e8f45..93c057b832d6 100644 --- a/beacon-chain/state/types.go +++ b/beacon-chain/state/types.go @@ -26,6 +26,10 @@ type reference struct { refs uint } +// ErrNilInnerState returns when the inner state is nil and no copy set or get +// operations can be performed on state. +var ErrNilInnerState = errors.New("nil inner state") + // BeaconState defines a struct containing utilities for the eth2 chain state, defining // getters and setters for its respective values and helpful functions such as HashTreeRoot(). type BeaconState struct { @@ -80,6 +84,9 @@ func InitializeFromProtoUnsafe(st *pbp2p.BeaconState) (*BeaconState, error) { // Copy returns a deep copy of the beacon state. func (b *BeaconState) Copy() *BeaconState { + if !b.HasInnerState() { + return nil + } b.lock.RLock() defer b.lock.RUnlock() diff --git a/shared/mock/beacon_chain_service_mock.go b/shared/mock/beacon_chain_service_mock.go index 9f3dae07fe4e..4c285db8c805 100644 --- a/shared/mock/beacon_chain_service_mock.go +++ b/shared/mock/beacon_chain_service_mock.go @@ -6,12 +6,13 @@ package mock import ( context "context" + reflect "reflect" + empty "github.com/gogo/protobuf/types" gomock "github.com/golang/mock/gomock" v1alpha1 "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" grpc "google.golang.org/grpc" metadata "google.golang.org/grpc/metadata" - reflect "reflect" ) // MockBeaconChainClient is a mock of BeaconChainClient interface