github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/rpc/prysm/v1alpha1/validator/exit_test.go (about) 1 package validator 2 3 import ( 4 "context" 5 "testing" 6 "time" 7 8 types "github.com/prysmaticlabs/eth2-types" 9 mockChain "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing" 10 "github.com/prysmaticlabs/prysm/beacon-chain/core/feed" 11 opfeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/operation" 12 "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" 13 "github.com/prysmaticlabs/prysm/beacon-chain/core/state" 14 dbutil "github.com/prysmaticlabs/prysm/beacon-chain/db/testing" 15 "github.com/prysmaticlabs/prysm/beacon-chain/operations/voluntaryexits" 16 mockp2p "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing" 17 mockSync "github.com/prysmaticlabs/prysm/beacon-chain/sync/initial-sync/testing" 18 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 19 "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper" 20 "github.com/prysmaticlabs/prysm/shared/bytesutil" 21 "github.com/prysmaticlabs/prysm/shared/params" 22 "github.com/prysmaticlabs/prysm/shared/testutil" 23 "github.com/prysmaticlabs/prysm/shared/testutil/assert" 24 "github.com/prysmaticlabs/prysm/shared/testutil/require" 25 ) 26 27 func TestProposeExit_Notification(t *testing.T) { 28 db := dbutil.SetupDB(t) 29 ctx := context.Background() 30 31 deposits, keys, err := testutil.DeterministicDepositsAndKeys(params.BeaconConfig().MinGenesisActiveValidatorCount) 32 require.NoError(t, err) 33 beaconState, err := state.GenesisBeaconState(ctx, deposits, 0, ðpb.Eth1Data{BlockHash: make([]byte, 32)}) 34 require.NoError(t, err) 35 epoch := types.Epoch(2048) 36 require.NoError(t, beaconState.SetSlot(params.BeaconConfig().SlotsPerEpoch.Mul(uint64(epoch)))) 37 block := testutil.NewBeaconBlock() 38 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block)), "Could not save genesis block") 39 genesisRoot, err := block.Block.HashTreeRoot() 40 require.NoError(t, err, "Could not get signing root") 41 42 // Set genesis time to be 100 epochs ago. 43 offset := int64(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().SecondsPerSlot)) 44 genesisTime := time.Now().Add(time.Duration(-100*offset) * time.Second) 45 mockChainService := &mockChain.ChainService{State: beaconState, Root: genesisRoot[:], Genesis: genesisTime} 46 server := &Server{ 47 BeaconDB: db, 48 HeadFetcher: mockChainService, 49 SyncChecker: &mockSync.Sync{IsSyncing: false}, 50 TimeFetcher: mockChainService, 51 StateNotifier: mockChainService.StateNotifier(), 52 OperationNotifier: mockChainService.OperationNotifier(), 53 ExitPool: voluntaryexits.NewPool(), 54 P2P: mockp2p.NewTestP2P(t), 55 } 56 57 // Subscribe to operation notifications. 58 opChannel := make(chan *feed.Event, 1024) 59 opSub := server.OperationNotifier.OperationFeed().Subscribe(opChannel) 60 defer opSub.Unsubscribe() 61 62 // Send the request, expect a result on the state feed. 63 validatorIndex := types.ValidatorIndex(0) 64 req := ðpb.SignedVoluntaryExit{ 65 Exit: ðpb.VoluntaryExit{ 66 Epoch: epoch, 67 ValidatorIndex: validatorIndex, 68 }, 69 } 70 req.Signature, err = helpers.ComputeDomainAndSign(beaconState, epoch, req.Exit, params.BeaconConfig().DomainVoluntaryExit, keys[0]) 71 require.NoError(t, err) 72 73 resp, err := server.ProposeExit(context.Background(), req) 74 require.NoError(t, err) 75 expectedRoot, err := req.Exit.HashTreeRoot() 76 require.NoError(t, err) 77 assert.DeepEqual(t, expectedRoot[:], resp.ExitRoot) 78 79 // Ensure the state notification was broadcast. 80 notificationFound := false 81 for !notificationFound { 82 select { 83 case event := <-opChannel: 84 if event.Type == opfeed.ExitReceived { 85 notificationFound = true 86 data, ok := event.Data.(*opfeed.ExitReceivedData) 87 assert.Equal(t, true, ok, "Entity is not of type *opfeed.ExitReceivedData") 88 assert.Equal(t, epoch, data.Exit.Exit.Epoch, "Unexpected state feed epoch") 89 assert.Equal(t, validatorIndex, data.Exit.Exit.ValidatorIndex, "Unexpected state feed validator index") 90 } 91 case <-opSub.Err(): 92 t.Error("Subscription to state notifier failed") 93 return 94 } 95 } 96 } 97 98 func TestProposeExit_NoPanic(t *testing.T) { 99 db := dbutil.SetupDB(t) 100 ctx := context.Background() 101 102 deposits, keys, err := testutil.DeterministicDepositsAndKeys(params.BeaconConfig().MinGenesisActiveValidatorCount) 103 require.NoError(t, err) 104 beaconState, err := state.GenesisBeaconState(ctx, deposits, 0, ðpb.Eth1Data{BlockHash: make([]byte, 32)}) 105 require.NoError(t, err) 106 epoch := types.Epoch(2048) 107 require.NoError(t, beaconState.SetSlot(params.BeaconConfig().SlotsPerEpoch.Mul(uint64(epoch)))) 108 block := testutil.NewBeaconBlock() 109 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block)), "Could not save genesis block") 110 genesisRoot, err := block.Block.HashTreeRoot() 111 require.NoError(t, err, "Could not get signing root") 112 113 // Set genesis time to be 100 epochs ago. 114 offset := int64(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().SecondsPerSlot)) 115 genesisTime := time.Now().Add(time.Duration(-100*offset) * time.Second) 116 mockChainService := &mockChain.ChainService{State: beaconState, Root: genesisRoot[:], Genesis: genesisTime} 117 server := &Server{ 118 BeaconDB: db, 119 HeadFetcher: mockChainService, 120 SyncChecker: &mockSync.Sync{IsSyncing: false}, 121 TimeFetcher: mockChainService, 122 StateNotifier: mockChainService.StateNotifier(), 123 OperationNotifier: mockChainService.OperationNotifier(), 124 ExitPool: voluntaryexits.NewPool(), 125 P2P: mockp2p.NewTestP2P(t), 126 } 127 128 // Subscribe to operation notifications. 129 opChannel := make(chan *feed.Event, 1024) 130 opSub := server.OperationNotifier.OperationFeed().Subscribe(opChannel) 131 defer opSub.Unsubscribe() 132 133 req := ðpb.SignedVoluntaryExit{} 134 _, err = server.ProposeExit(context.Background(), req) 135 require.ErrorContains(t, "voluntary exit does not exist", err, "Expected error for no exit existing") 136 137 // Send the request, expect a result on the state feed. 138 validatorIndex := types.ValidatorIndex(0) 139 req = ðpb.SignedVoluntaryExit{ 140 Exit: ðpb.VoluntaryExit{ 141 Epoch: epoch, 142 ValidatorIndex: validatorIndex, 143 }, 144 } 145 146 _, err = server.ProposeExit(context.Background(), req) 147 require.ErrorContains(t, "invalid signature provided", err, "Expected error for no signature exists") 148 req.Signature = bytesutil.FromBytes48([48]byte{}) 149 150 _, err = server.ProposeExit(context.Background(), req) 151 require.ErrorContains(t, "invalid signature provided", err, "Expected error for invalid signature length") 152 req.Signature, err = helpers.ComputeDomainAndSign(beaconState, epoch, req.Exit, params.BeaconConfig().DomainVoluntaryExit, keys[0]) 153 require.NoError(t, err) 154 resp, err := server.ProposeExit(context.Background(), req) 155 require.NoError(t, err) 156 expectedRoot, err := req.Exit.HashTreeRoot() 157 require.NoError(t, err) 158 assert.DeepEqual(t, expectedRoot[:], resp.ExitRoot) 159 }