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, &ethpb.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 := &ethpb.SignedVoluntaryExit{
    65  		Exit: &ethpb.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, &ethpb.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 := &ethpb.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 = &ethpb.SignedVoluntaryExit{
   140  		Exit: &ethpb.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  }