package blocks_test import ( "context" "testing" types "github.com/prysmaticlabs/eth2-types" "github.com/prysmaticlabs/prysm/beacon-chain/core" "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks" "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1" "github.com/prysmaticlabs/prysm/crypto/bls" ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1" "github.com/prysmaticlabs/prysm/shared/params" "github.com/prysmaticlabs/prysm/shared/testutil" "github.com/prysmaticlabs/prysm/shared/testutil/assert" "github.com/prysmaticlabs/prysm/shared/testutil/require" ) func TestProcessVoluntaryExits_NotActiveLongEnoughToExit(t *testing.T) { exits := []*ethpb.SignedVoluntaryExit{ { Exit: ðpb.VoluntaryExit{ ValidatorIndex: 0, Epoch: 0, }, }, } registry := []*ethpb.Validator{ { ExitEpoch: params.BeaconConfig().FarFutureEpoch, }, } state, err := v1.InitializeFromProto(ðpb.BeaconState{ Validators: registry, Slot: 10, }) require.NoError(t, err) b := testutil.NewBeaconBlock() b.Block = ðpb.BeaconBlock{ Body: ðpb.BeaconBlockBody{ VoluntaryExits: exits, }, } want := "validator has not been active long enough to exit" _, err = blocks.ProcessVoluntaryExits(context.Background(), state, b.Block.Body.VoluntaryExits) assert.ErrorContains(t, want, err) } func TestProcessVoluntaryExits_ExitAlreadySubmitted(t *testing.T) { exits := []*ethpb.SignedVoluntaryExit{ { Exit: ðpb.VoluntaryExit{ Epoch: 10, }, }, } registry := []*ethpb.Validator{ { ExitEpoch: 10, }, } state, err := v1.InitializeFromProto(ðpb.BeaconState{ Validators: registry, Slot: 0, }) require.NoError(t, err) b := testutil.NewBeaconBlock() b.Block = ðpb.BeaconBlock{ Body: ðpb.BeaconBlockBody{ VoluntaryExits: exits, }, } want := "validator with index 0 has already submitted an exit, which will take place at epoch: 10" _, err = blocks.ProcessVoluntaryExits(context.Background(), state, b.Block.Body.VoluntaryExits) assert.ErrorContains(t, want, err) } func TestProcessVoluntaryExits_AppliesCorrectStatus(t *testing.T) { exits := []*ethpb.SignedVoluntaryExit{ { Exit: ðpb.VoluntaryExit{ ValidatorIndex: 0, Epoch: 0, }, }, } registry := []*ethpb.Validator{ { ExitEpoch: params.BeaconConfig().FarFutureEpoch, ActivationEpoch: 0, }, } state, err := v1.InitializeFromProto(ðpb.BeaconState{ Validators: registry, Fork: ðpb.Fork{ CurrentVersion: params.BeaconConfig().GenesisForkVersion, PreviousVersion: params.BeaconConfig().GenesisForkVersion, }, Slot: params.BeaconConfig().SlotsPerEpoch * 5, }) require.NoError(t, err) err = state.SetSlot(state.Slot() + params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().ShardCommitteePeriod))) require.NoError(t, err) priv, err := bls.RandKey() require.NoError(t, err) val, err := state.ValidatorAtIndex(0) require.NoError(t, err) val.PublicKey = priv.PublicKey().Marshal() require.NoError(t, state.UpdateValidatorAtIndex(0, val)) exits[0].Signature, err = helpers.ComputeDomainAndSign(state, core.CurrentEpoch(state), exits[0].Exit, params.BeaconConfig().DomainVoluntaryExit, priv) require.NoError(t, err) b := testutil.NewBeaconBlock() b.Block = ðpb.BeaconBlock{ Body: ðpb.BeaconBlockBody{ VoluntaryExits: exits, }, } newState, err := blocks.ProcessVoluntaryExits(context.Background(), state, b.Block.Body.VoluntaryExits) require.NoError(t, err, "Could not process exits") newRegistry := newState.Validators() if newRegistry[0].ExitEpoch != helpers.ActivationExitEpoch(types.Epoch(state.Slot()/params.BeaconConfig().SlotsPerEpoch)) { t.Errorf("Expected validator exit epoch to be %d, got %d", helpers.ActivationExitEpoch(types.Epoch(state.Slot()/params.BeaconConfig().SlotsPerEpoch)), newRegistry[0].ExitEpoch) } }