diff --git a/beacon-chain/chaintest/README.md b/beacon-chain/chaintest/README.md index 9c9992b1f..29af1011f 100644 --- a/beacon-chain/chaintest/README.md +++ b/beacon-chain/chaintest/README.md @@ -112,6 +112,7 @@ The following configuration options are available for state transition tests: - **deposits**: `[Deposit Config]` trigger a new validator deposit into the beacon state based on configuration options - **proposer_slashings**: `[Proposer Slashing Config]` trigger a proposer slashing at a certain slot for a certain proposer index - **casper_slashings**: `[Casper Slashing Config]` trigger a casper slashing at a certain slot +- **validator_exits**: `[Validator Exit Config]` trigger a voluntary validator exit at a certain slot for a validator index **Deposit Config** - **slot**: `int` a slot in which to trigger a deposit during a state transition test @@ -140,12 +141,17 @@ The following configuration options are available for state transition tests: - **votes_2_custody_0_indices**: `[int]` the custody indices 0 for votes2 - **votes_2_custody_1_indices**: `[int]` the custody indices 1 for votes2 +**Validator Exit Config** +- **slot**: `int` the slot at which a validator wants to voluntarily exit the validator registry +- **validator_index**: `int` the index of the validator in the registry that is exiting + #### Test Results The following are **mandatory** fields as they correspond to checks done at the end of the test run. - **slot**: `int` check the slot of the state resulting from applying N state transitions in the test - **num_validators** `[int]` check the number of validators in the validator registry after applying N state transitions - **penalized_validators** `[int]` the list of validator indices we verify were penalized during the test +- **exited_validators**: `[int]` the list of validator indices we verify voluntarily exited the registry during the test ## Stateless Tests diff --git a/beacon-chain/chaintest/backend/helpers.go b/beacon-chain/chaintest/backend/helpers.go index cbe15a7f1..65a5230d6 100644 --- a/beacon-chain/chaintest/backend/helpers.go +++ b/beacon-chain/chaintest/backend/helpers.go @@ -26,6 +26,7 @@ func generateSimulatedBlock( depositsTrie *trie.DepositTrie, simulatedProposerSlashing *StateTestProposerSlashing, simulatedCasperSlashing *StateTestCasperSlashing, + simulatedExit *StateTestValidatorExit, ) (*pb.BeaconBlock, [32]byte, error) { encodedState, err := proto.Marshal(beaconState) if err != nil { @@ -105,6 +106,12 @@ func generateSimulatedBlock( }, }) } + if simulatedExit != nil { + block.Body.Exits = append(block.Body.Exits, &pb.Exit{ + Slot: simulatedExit.Slot, + ValidatorIndex: simulatedExit.ValidatorIndex, + }) + } encodedBlock, err := proto.Marshal(block) if err != nil { return nil, [32]byte{}, fmt.Errorf("could not marshal new block: %v", err) diff --git a/beacon-chain/chaintest/backend/simulated_backend.go b/beacon-chain/chaintest/backend/simulated_backend.go index cea5df99f..074987e6e 100644 --- a/beacon-chain/chaintest/backend/simulated_backend.go +++ b/beacon-chain/chaintest/backend/simulated_backend.go @@ -200,6 +200,13 @@ func (sb *SimulatedBackend) RunStateTransitionTest(testCase *StateTestCase) erro break } } + var simulatedValidatorExit *StateTestValidatorExit + for _, exit := range testCase.Config.ValidatorExits { + if exit.Slot == i { + simulatedValidatorExit = exit + break + } + } layersPeeled := layersPeeledForProposer[proposerIndex] blockRandaoReveal := determineSimulatedBlockRandaoReveal(layersPeeled, hashOnions) @@ -214,6 +221,7 @@ func (sb *SimulatedBackend) RunStateTransitionTest(testCase *StateTestCase) erro depositsTrie, simulatedProposerSlashing, simulatedCasperSlashing, + simulatedValidatorExit, ) if err != nil { return fmt.Errorf("could not generate simulated beacon block %v", err) @@ -266,6 +274,14 @@ func (sb *SimulatedBackend) RunStateTransitionTest(testCase *StateTestCase) erro ) } } + for _, exited := range testCase.Results.ExitedValidators { + if beaconState.ValidatorRegistry[exited].StatusFlags != pb.ValidatorRecord_INITIATED_EXIT { + return fmt.Errorf( + "expected validator at index %d to have exited", + exited, + ) + } + } return nil } diff --git a/beacon-chain/chaintest/backend/state_test_format.go b/beacon-chain/chaintest/backend/state_test_format.go index 01d303682..459d544e6 100644 --- a/beacon-chain/chaintest/backend/state_test_format.go +++ b/beacon-chain/chaintest/backend/state_test_format.go @@ -23,6 +23,7 @@ type StateTestConfig struct { Deposits []*StateTestDeposit `yaml:"deposits"` ProposerSlashings []*StateTestProposerSlashing `yaml:"proposer_slashings"` CasperSlashings []*StateTestCasperSlashing `yaml:"casper_slashings"` + ValidatorExits []*StateTestValidatorExit `yaml:"validator_exits"` EpochLength uint64 `yaml:"epoch_length"` ShardCount uint64 `yaml:"shard_count"` DepositsForChainStart uint64 `yaml:"deposits_for_chain_start"` @@ -62,9 +63,16 @@ type StateTestCasperSlashing struct { Votes2CustodyBit1Indices []uint32 `yaml:"votes_2_custody_1_indices"` } +// StateTestValidatorExit -- +type StateTestValidatorExit struct { + Slot uint64 `yaml:"slot"` + ValidatorIndex uint32 `yaml:"validator_index"` +} + // StateTestResults -- type StateTestResults struct { Slot uint64 NumValidators int `yaml:"num_validators"` PenalizedValidators []uint32 `yaml:"penalized_validators"` + ExitedValidators []uint32 `yaml:"exited_validators"` } diff --git a/beacon-chain/chaintest/tests/state-tests/block-processing.yaml b/beacon-chain/chaintest/tests/state-tests/block-processing.yaml index 41e9a74b9..9769cbfeb 100644 --- a/beacon-chain/chaintest/tests/state-tests/block-processing.yaml +++ b/beacon-chain/chaintest/tests/state-tests/block-processing.yaml @@ -52,10 +52,14 @@ test_cases: votes_1_custody_1_indices: [] votes_2_custody_0_indices: [] votes_2_custody_1_indices: [16386] + validator_exits: + - slot: 60 + validator_index: 100 # At slot 60, validator at index 100 triggers a voluntary exit results: slot: 64 num_validators: 16387 penalized_validators: [16385, 16386] # We test that the validators at indices 16385, 16386 were indeed penalized + exited_validators: [100] # We confirm the indices of validators that willingly exited the registry - config: skip_slots: [10, 20] epoch_length: 64 diff --git a/beacon-chain/rpc/service_test.go b/beacon-chain/rpc/service_test.go index be946e831..f0972b40e 100644 --- a/beacon-chain/rpc/service_test.go +++ b/beacon-chain/rpc/service_test.go @@ -658,7 +658,7 @@ func TestValidatorAssignments(t *testing.T) { } func TestAssignmentsForPublicKeys_emptyPubKey(t *testing.T) { - pks := []*pb.PublicKey{&pb.PublicKey{}} + pks := []*pb.PublicKey{{}} a, err := assignmentsForPublicKeys(pks, nil) if err != nil {