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 }