github.com/prysmaticlabs/prysm@v1.4.4/validator/client/runner_test.go (about)

     1  package client
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"testing"
     7  	"time"
     8  
     9  	types "github.com/prysmaticlabs/eth2-types"
    10  	"github.com/prysmaticlabs/prysm/shared/event"
    11  	"github.com/prysmaticlabs/prysm/shared/featureconfig"
    12  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    13  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    14  	"github.com/prysmaticlabs/prysm/validator/client/iface"
    15  	"github.com/prysmaticlabs/prysm/validator/client/testutil"
    16  	"github.com/prysmaticlabs/prysm/validator/keymanager/remote"
    17  	logTest "github.com/sirupsen/logrus/hooks/test"
    18  )
    19  
    20  func cancelledContext() context.Context {
    21  	ctx, cancel := context.WithCancel(context.Background())
    22  	cancel()
    23  	return ctx
    24  }
    25  
    26  func TestCancelledContext_CleansUpValidator(t *testing.T) {
    27  	v := &testutil.FakeValidator{Keymanager: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
    28  	run(cancelledContext(), v)
    29  	assert.Equal(t, true, v.DoneCalled, "Expected Done() to be called")
    30  }
    31  
    32  func TestCancelledContext_WaitsForChainStart(t *testing.T) {
    33  	v := &testutil.FakeValidator{Keymanager: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
    34  	run(cancelledContext(), v)
    35  	assert.Equal(t, 1, v.WaitForChainStartCalled, "Expected WaitForChainStart() to be called")
    36  }
    37  
    38  func TestRetry_On_ConnectionError(t *testing.T) {
    39  	retry := 10
    40  	v := &testutil.FakeValidator{
    41  		Keymanager:       &mockKeymanager{accountsChangedFeed: &event.Feed{}},
    42  		RetryTillSuccess: retry,
    43  	}
    44  	backOffPeriod = 10 * time.Millisecond
    45  	ctx, cancel := context.WithCancel(context.Background())
    46  	go run(ctx, v)
    47  	// each step will fail (retry times)=10 this sleep times will wait more then
    48  	// the time it takes for all steps to succeed before main loop.
    49  	time.Sleep(time.Duration(retry*6) * backOffPeriod)
    50  	cancel()
    51  	// every call will fail retry=10 times so first one will be called 4 * retry=10.
    52  	assert.Equal(t, retry*4, v.WaitForChainStartCalled, "Expected WaitForChainStart() to be called")
    53  	assert.Equal(t, retry*3, v.WaitForSyncCalled, "Expected WaitForSync() to be called")
    54  	assert.Equal(t, retry*2, v.WaitForActivationCalled, "Expected WaitForActivation() to be called")
    55  	assert.Equal(t, retry, v.CanonicalHeadSlotCalled, "Expected WaitForActivation() to be called")
    56  	assert.Equal(t, retry, v.ReceiveBlocksCalled, "Expected WaitForActivation() to be called")
    57  }
    58  
    59  func TestCancelledContext_WaitsForActivation(t *testing.T) {
    60  	v := &testutil.FakeValidator{Keymanager: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
    61  	run(cancelledContext(), v)
    62  	assert.Equal(t, 1, v.WaitForActivationCalled, "Expected WaitForActivation() to be called")
    63  }
    64  
    65  func TestCancelledContext_ChecksSlasherReady(t *testing.T) {
    66  	v := &testutil.FakeValidator{Keymanager: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
    67  	cfg := &featureconfig.Flags{
    68  		SlasherProtection: true,
    69  	}
    70  	reset := featureconfig.InitWithReset(cfg)
    71  	defer reset()
    72  	run(cancelledContext(), v)
    73  	assert.Equal(t, true, v.SlasherReadyCalled, "Expected SlasherReady() to be called")
    74  }
    75  
    76  func TestUpdateDuties_NextSlot(t *testing.T) {
    77  	v := &testutil.FakeValidator{Keymanager: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
    78  	ctx, cancel := context.WithCancel(context.Background())
    79  
    80  	slot := types.Slot(55)
    81  	ticker := make(chan types.Slot)
    82  	v.NextSlotRet = ticker
    83  	go func() {
    84  		ticker <- slot
    85  
    86  		cancel()
    87  	}()
    88  
    89  	run(ctx, v)
    90  
    91  	require.Equal(t, true, v.UpdateDutiesCalled, "Expected UpdateAssignments(%d) to be called", slot)
    92  	assert.Equal(t, uint64(slot), v.UpdateDutiesArg1, "UpdateAssignments was called with wrong argument")
    93  }
    94  
    95  func TestUpdateDuties_HandlesError(t *testing.T) {
    96  	hook := logTest.NewGlobal()
    97  	v := &testutil.FakeValidator{Keymanager: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
    98  	ctx, cancel := context.WithCancel(context.Background())
    99  
   100  	slot := types.Slot(55)
   101  	ticker := make(chan types.Slot)
   102  	v.NextSlotRet = ticker
   103  	go func() {
   104  		ticker <- slot
   105  
   106  		cancel()
   107  	}()
   108  	v.UpdateDutiesRet = errors.New("bad")
   109  
   110  	run(ctx, v)
   111  
   112  	require.LogsContain(t, hook, "Failed to update assignments")
   113  }
   114  
   115  func TestRoleAt_NextSlot(t *testing.T) {
   116  	v := &testutil.FakeValidator{Keymanager: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
   117  	ctx, cancel := context.WithCancel(context.Background())
   118  
   119  	slot := types.Slot(55)
   120  	ticker := make(chan types.Slot)
   121  	v.NextSlotRet = ticker
   122  	go func() {
   123  		ticker <- slot
   124  
   125  		cancel()
   126  	}()
   127  
   128  	run(ctx, v)
   129  
   130  	require.Equal(t, true, v.RoleAtCalled, "Expected RoleAt(%d) to be called", slot)
   131  	assert.Equal(t, uint64(slot), v.RoleAtArg1, "RoleAt called with the wrong arg")
   132  }
   133  
   134  func TestAttests_NextSlot(t *testing.T) {
   135  	v := &testutil.FakeValidator{Keymanager: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
   136  	ctx, cancel := context.WithCancel(context.Background())
   137  
   138  	slot := types.Slot(55)
   139  	ticker := make(chan types.Slot)
   140  	v.NextSlotRet = ticker
   141  	v.RolesAtRet = []iface.ValidatorRole{iface.RoleAttester}
   142  	go func() {
   143  		ticker <- slot
   144  
   145  		cancel()
   146  	}()
   147  	timer := time.NewTimer(200 * time.Millisecond)
   148  	run(ctx, v)
   149  	<-timer.C
   150  	require.Equal(t, true, v.AttestToBlockHeadCalled, "SubmitAttestation(%d) was not called", slot)
   151  	assert.Equal(t, uint64(slot), v.AttestToBlockHeadArg1, "SubmitAttestation was called with wrong arg")
   152  }
   153  
   154  func TestProposes_NextSlot(t *testing.T) {
   155  	v := &testutil.FakeValidator{Keymanager: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
   156  	ctx, cancel := context.WithCancel(context.Background())
   157  
   158  	slot := types.Slot(55)
   159  	ticker := make(chan types.Slot)
   160  	v.NextSlotRet = ticker
   161  	v.RolesAtRet = []iface.ValidatorRole{iface.RoleProposer}
   162  	go func() {
   163  		ticker <- slot
   164  
   165  		cancel()
   166  	}()
   167  	timer := time.NewTimer(200 * time.Millisecond)
   168  	run(ctx, v)
   169  	<-timer.C
   170  	require.Equal(t, true, v.ProposeBlockCalled, "ProposeBlock(%d) was not called", slot)
   171  	assert.Equal(t, uint64(slot), v.ProposeBlockArg1, "ProposeBlock was called with wrong arg")
   172  }
   173  
   174  func TestBothProposesAndAttests_NextSlot(t *testing.T) {
   175  	v := &testutil.FakeValidator{Keymanager: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
   176  	ctx, cancel := context.WithCancel(context.Background())
   177  
   178  	slot := types.Slot(55)
   179  	ticker := make(chan types.Slot)
   180  	v.NextSlotRet = ticker
   181  	v.RolesAtRet = []iface.ValidatorRole{iface.RoleAttester, iface.RoleProposer}
   182  	go func() {
   183  		ticker <- slot
   184  
   185  		cancel()
   186  	}()
   187  	timer := time.NewTimer(200 * time.Millisecond)
   188  	run(ctx, v)
   189  	<-timer.C
   190  	require.Equal(t, true, v.AttestToBlockHeadCalled, "SubmitAttestation(%d) was not called", slot)
   191  	assert.Equal(t, uint64(slot), v.AttestToBlockHeadArg1, "SubmitAttestation was called with wrong arg")
   192  	require.Equal(t, true, v.ProposeBlockCalled, "ProposeBlock(%d) was not called", slot)
   193  	assert.Equal(t, uint64(slot), v.ProposeBlockArg1, "ProposeBlock was called with wrong arg")
   194  }
   195  
   196  func TestAllValidatorsAreExited_NextSlot(t *testing.T) {
   197  	v := &testutil.FakeValidator{Keymanager: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
   198  	ctx, cancel := context.WithCancel(context.WithValue(context.Background(), testutil.AllValidatorsAreExitedCtxKey, true))
   199  	hook := logTest.NewGlobal()
   200  
   201  	slot := types.Slot(55)
   202  	ticker := make(chan types.Slot)
   203  	v.NextSlotRet = ticker
   204  	go func() {
   205  		ticker <- slot
   206  
   207  		cancel()
   208  	}()
   209  	run(ctx, v)
   210  	assert.LogsContain(t, hook, "All validators are exited")
   211  }
   212  
   213  func TestKeyReload_ActiveKey(t *testing.T) {
   214  	ctx, cancel := context.WithCancel(context.Background())
   215  	km := &mockKeymanager{}
   216  	v := &testutil.FakeValidator{Keymanager: km}
   217  	go func() {
   218  		km.SimulateAccountChanges([][48]byte{testutil.ActiveKey})
   219  
   220  		cancel()
   221  	}()
   222  	run(ctx, v)
   223  	assert.Equal(t, true, v.HandleKeyReloadCalled)
   224  	// We expect that WaitForActivation will only be called once,
   225  	// at the very beginning, and not after account changes.
   226  	assert.Equal(t, 1, v.WaitForActivationCalled)
   227  }
   228  
   229  func TestKeyReload_NoActiveKey(t *testing.T) {
   230  	ctx, cancel := context.WithCancel(context.Background())
   231  	km := &mockKeymanager{}
   232  	v := &testutil.FakeValidator{Keymanager: km}
   233  	go func() {
   234  		km.SimulateAccountChanges(make([][48]byte, 0))
   235  
   236  		cancel()
   237  	}()
   238  	run(ctx, v)
   239  	assert.Equal(t, true, v.HandleKeyReloadCalled)
   240  	assert.Equal(t, 2, v.WaitForActivationCalled)
   241  }
   242  
   243  func TestKeyReload_RemoteKeymanager(t *testing.T) {
   244  	ctx, cancel := context.WithCancel(context.Background())
   245  	km := remote.NewMock()
   246  	v := &testutil.FakeValidator{Keymanager: &km}
   247  
   248  	ticker := make(chan types.Slot)
   249  	v.NextSlotRet = ticker
   250  	go func() {
   251  		ticker <- types.Slot(55)
   252  
   253  		cancel()
   254  	}()
   255  	run(ctx, v)
   256  	assert.Equal(t, true, km.ReloadPublicKeysCalled)
   257  }