github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/blockchain/testing/mock.go (about) 1 // Package testing includes useful mocks for writing unit 2 // tests which depend on logic from the blockchain package. 3 package testing 4 5 import ( 6 "bytes" 7 "context" 8 "sync" 9 "time" 10 11 "github.com/pkg/errors" 12 types "github.com/prysmaticlabs/eth2-types" 13 "github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute" 14 "github.com/prysmaticlabs/prysm/beacon-chain/core/feed" 15 blockfeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/block" 16 opfeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/operation" 17 statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state" 18 "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" 19 "github.com/prysmaticlabs/prysm/beacon-chain/db" 20 "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray" 21 iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface" 22 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1" 23 pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" 24 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 25 "github.com/prysmaticlabs/prysm/proto/interfaces" 26 "github.com/prysmaticlabs/prysm/shared/bytesutil" 27 "github.com/prysmaticlabs/prysm/shared/event" 28 "github.com/prysmaticlabs/prysm/shared/params" 29 "github.com/sirupsen/logrus" 30 ) 31 32 // ChainService defines the mock interface for testing 33 type ChainService struct { 34 State iface.BeaconState 35 Root []byte 36 Block interfaces.SignedBeaconBlock 37 FinalizedCheckPoint *ethpb.Checkpoint 38 CurrentJustifiedCheckPoint *ethpb.Checkpoint 39 PreviousJustifiedCheckPoint *ethpb.Checkpoint 40 BlocksReceived []interfaces.SignedBeaconBlock 41 Balance *precompute.Balance 42 Genesis time.Time 43 ValidatorsRoot [32]byte 44 CanonicalRoots map[[32]byte]bool 45 Fork *pb.Fork 46 ETH1Data *ethpb.Eth1Data 47 DB db.Database 48 stateNotifier statefeed.Notifier 49 blockNotifier blockfeed.Notifier 50 opNotifier opfeed.Notifier 51 ValidAttestation bool 52 ForkChoiceStore *protoarray.Store 53 VerifyBlkDescendantErr error 54 Slot *types.Slot // Pointer because 0 is a useful value, so checking against it can be incorrect. 55 } 56 57 // StateNotifier mocks the same method in the chain service. 58 func (s *ChainService) StateNotifier() statefeed.Notifier { 59 if s.stateNotifier == nil { 60 s.stateNotifier = &MockStateNotifier{} 61 } 62 return s.stateNotifier 63 } 64 65 // BlockNotifier mocks the same method in the chain service. 66 func (s *ChainService) BlockNotifier() blockfeed.Notifier { 67 if s.blockNotifier == nil { 68 s.blockNotifier = &MockBlockNotifier{} 69 } 70 return s.blockNotifier 71 } 72 73 // MockBlockNotifier mocks the block notifier. 74 type MockBlockNotifier struct { 75 feed *event.Feed 76 } 77 78 // BlockFeed returns a block feed. 79 func (mbn *MockBlockNotifier) BlockFeed() *event.Feed { 80 if mbn.feed == nil { 81 mbn.feed = new(event.Feed) 82 } 83 return mbn.feed 84 } 85 86 // MockStateNotifier mocks the state notifier. 87 type MockStateNotifier struct { 88 feed *event.Feed 89 feedLock sync.Mutex 90 91 recv []*feed.Event 92 recvLock sync.Mutex 93 recvCh chan *feed.Event 94 95 RecordEvents bool 96 } 97 98 // ReceivedEvents returns the events received by the state feed in this mock. 99 func (msn *MockStateNotifier) ReceivedEvents() []*feed.Event { 100 msn.recvLock.Lock() 101 defer msn.recvLock.Unlock() 102 return msn.recv 103 } 104 105 // StateFeed returns a state feed. 106 func (msn *MockStateNotifier) StateFeed() *event.Feed { 107 msn.feedLock.Lock() 108 defer msn.feedLock.Unlock() 109 110 if msn.feed == nil && msn.recvCh == nil { 111 msn.feed = new(event.Feed) 112 if msn.RecordEvents { 113 msn.recvCh = make(chan *feed.Event) 114 sub := msn.feed.Subscribe(msn.recvCh) 115 116 go func() { 117 select { 118 case evt := <-msn.recvCh: 119 msn.recvLock.Lock() 120 msn.recv = append(msn.recv, evt) 121 msn.recvLock.Unlock() 122 case <-sub.Err(): 123 sub.Unsubscribe() 124 } 125 }() 126 } 127 } 128 return msn.feed 129 } 130 131 // OperationNotifier mocks the same method in the chain service. 132 func (s *ChainService) OperationNotifier() opfeed.Notifier { 133 if s.opNotifier == nil { 134 s.opNotifier = &MockOperationNotifier{} 135 } 136 return s.opNotifier 137 } 138 139 // MockOperationNotifier mocks the operation notifier. 140 type MockOperationNotifier struct { 141 feed *event.Feed 142 } 143 144 // OperationFeed returns an operation feed. 145 func (mon *MockOperationNotifier) OperationFeed() *event.Feed { 146 if mon.feed == nil { 147 mon.feed = new(event.Feed) 148 } 149 return mon.feed 150 } 151 152 // ReceiveBlockInitialSync mocks ReceiveBlockInitialSync method in chain service. 153 func (s *ChainService) ReceiveBlockInitialSync(ctx context.Context, block interfaces.SignedBeaconBlock, _ [32]byte) error { 154 if s.State == nil { 155 s.State = &v1.BeaconState{} 156 } 157 if !bytes.Equal(s.Root, block.Block().ParentRoot()) { 158 return errors.Errorf("wanted %#x but got %#x", s.Root, block.Block().ParentRoot()) 159 } 160 if err := s.State.SetSlot(block.Block().Slot()); err != nil { 161 return err 162 } 163 s.BlocksReceived = append(s.BlocksReceived, block) 164 signingRoot, err := block.Block().HashTreeRoot() 165 if err != nil { 166 return err 167 } 168 if s.DB != nil { 169 if err := s.DB.SaveBlock(ctx, block); err != nil { 170 return err 171 } 172 logrus.Infof("Saved block with root: %#x at slot %d", signingRoot, block.Block().Slot()) 173 } 174 s.Root = signingRoot[:] 175 s.Block = block 176 return nil 177 } 178 179 // ReceiveBlockBatch processes blocks in batches from initial-sync. 180 func (s *ChainService) ReceiveBlockBatch(ctx context.Context, blks []interfaces.SignedBeaconBlock, _ [][32]byte) error { 181 if s.State == nil { 182 s.State = &v1.BeaconState{} 183 } 184 for _, block := range blks { 185 if !bytes.Equal(s.Root, block.Block().ParentRoot()) { 186 return errors.Errorf("wanted %#x but got %#x", s.Root, block.Block().ParentRoot()) 187 } 188 if err := s.State.SetSlot(block.Block().Slot()); err != nil { 189 return err 190 } 191 s.BlocksReceived = append(s.BlocksReceived, block) 192 signingRoot, err := block.Block().HashTreeRoot() 193 if err != nil { 194 return err 195 } 196 if s.DB != nil { 197 if err := s.DB.SaveBlock(ctx, block); err != nil { 198 return err 199 } 200 logrus.Infof("Saved block with root: %#x at slot %d", signingRoot, block.Block().Slot()) 201 } 202 s.Root = signingRoot[:] 203 s.Block = block 204 } 205 return nil 206 } 207 208 // ReceiveBlock mocks ReceiveBlock method in chain service. 209 func (s *ChainService) ReceiveBlock(ctx context.Context, block interfaces.SignedBeaconBlock, _ [32]byte) error { 210 if s.State == nil { 211 s.State = &v1.BeaconState{} 212 } 213 if !bytes.Equal(s.Root, block.Block().ParentRoot()) { 214 return errors.Errorf("wanted %#x but got %#x", s.Root, block.Block().ParentRoot()) 215 } 216 if err := s.State.SetSlot(block.Block().Slot()); err != nil { 217 return err 218 } 219 s.BlocksReceived = append(s.BlocksReceived, block) 220 signingRoot, err := block.Block().HashTreeRoot() 221 if err != nil { 222 return err 223 } 224 if s.DB != nil { 225 if err := s.DB.SaveBlock(ctx, block); err != nil { 226 return err 227 } 228 logrus.Infof("Saved block with root: %#x at slot %d", signingRoot, block.Block().Slot()) 229 } 230 s.Root = signingRoot[:] 231 s.Block = block 232 return nil 233 } 234 235 // HeadSlot mocks HeadSlot method in chain service. 236 func (s *ChainService) HeadSlot() types.Slot { 237 if s.State == nil { 238 return 0 239 } 240 return s.State.Slot() 241 } 242 243 // HeadRoot mocks HeadRoot method in chain service. 244 func (s *ChainService) HeadRoot(_ context.Context) ([]byte, error) { 245 if len(s.Root) > 0 { 246 return s.Root, nil 247 } 248 return make([]byte, 32), nil 249 } 250 251 // HeadBlock mocks HeadBlock method in chain service. 252 func (s *ChainService) HeadBlock(context.Context) (interfaces.SignedBeaconBlock, error) { 253 return s.Block, nil 254 } 255 256 // HeadState mocks HeadState method in chain service. 257 func (s *ChainService) HeadState(context.Context) (iface.BeaconState, error) { 258 return s.State, nil 259 } 260 261 // CurrentFork mocks HeadState method in chain service. 262 func (s *ChainService) CurrentFork() *pb.Fork { 263 return s.Fork 264 } 265 266 // FinalizedCheckpt mocks FinalizedCheckpt method in chain service. 267 func (s *ChainService) FinalizedCheckpt() *ethpb.Checkpoint { 268 return s.FinalizedCheckPoint 269 } 270 271 // CurrentJustifiedCheckpt mocks CurrentJustifiedCheckpt method in chain service. 272 func (s *ChainService) CurrentJustifiedCheckpt() *ethpb.Checkpoint { 273 return s.CurrentJustifiedCheckPoint 274 } 275 276 // PreviousJustifiedCheckpt mocks PreviousJustifiedCheckpt method in chain service. 277 func (s *ChainService) PreviousJustifiedCheckpt() *ethpb.Checkpoint { 278 return s.PreviousJustifiedCheckPoint 279 } 280 281 // ReceiveAttestation mocks ReceiveAttestation method in chain service. 282 func (s *ChainService) ReceiveAttestation(_ context.Context, _ *ethpb.Attestation) error { 283 return nil 284 } 285 286 // ReceiveAttestationNoPubsub mocks ReceiveAttestationNoPubsub method in chain service. 287 func (s *ChainService) ReceiveAttestationNoPubsub(context.Context, *ethpb.Attestation) error { 288 return nil 289 } 290 291 // AttestationPreState mocks AttestationPreState method in chain service. 292 func (s *ChainService) AttestationPreState(_ context.Context, _ *ethpb.Attestation) (iface.BeaconState, error) { 293 return s.State, nil 294 } 295 296 // HeadValidatorsIndices mocks the same method in the chain service. 297 func (s *ChainService) HeadValidatorsIndices(_ context.Context, epoch types.Epoch) ([]types.ValidatorIndex, error) { 298 if s.State == nil { 299 return []types.ValidatorIndex{}, nil 300 } 301 return helpers.ActiveValidatorIndices(s.State, epoch) 302 } 303 304 // HeadSeed mocks the same method in the chain service. 305 func (s *ChainService) HeadSeed(_ context.Context, epoch types.Epoch) ([32]byte, error) { 306 return helpers.Seed(s.State, epoch, params.BeaconConfig().DomainBeaconAttester) 307 } 308 309 // HeadETH1Data provides the current ETH1Data of the head state. 310 func (s *ChainService) HeadETH1Data() *ethpb.Eth1Data { 311 return s.ETH1Data 312 } 313 314 // ProtoArrayStore mocks the same method in the chain service. 315 func (s *ChainService) ProtoArrayStore() *protoarray.Store { 316 return s.ForkChoiceStore 317 } 318 319 // GenesisTime mocks the same method in the chain service. 320 func (s *ChainService) GenesisTime() time.Time { 321 return s.Genesis 322 } 323 324 // GenesisValidatorRoot mocks the same method in the chain service. 325 func (s *ChainService) GenesisValidatorRoot() [32]byte { 326 return s.ValidatorsRoot 327 } 328 329 // CurrentSlot mocks the same method in the chain service. 330 func (s *ChainService) CurrentSlot() types.Slot { 331 if s.Slot != nil { 332 return *s.Slot 333 } 334 return types.Slot(uint64(time.Now().Unix()-s.Genesis.Unix()) / params.BeaconConfig().SecondsPerSlot) 335 } 336 337 // Participation mocks the same method in the chain service. 338 func (s *ChainService) Participation(_ uint64) *precompute.Balance { 339 return s.Balance 340 } 341 342 // IsValidAttestation always returns true. 343 func (s *ChainService) IsValidAttestation(_ context.Context, _ *ethpb.Attestation) bool { 344 return s.ValidAttestation 345 } 346 347 // IsCanonical returns and determines whether a block with the provided root is part of 348 // the canonical chain. 349 func (s *ChainService) IsCanonical(_ context.Context, r [32]byte) (bool, error) { 350 if s.CanonicalRoots != nil { 351 _, ok := s.CanonicalRoots[r] 352 return ok, nil 353 } 354 return true, nil 355 } 356 357 // HasInitSyncBlock mocks the same method in the chain service. 358 func (s *ChainService) HasInitSyncBlock(_ [32]byte) bool { 359 return false 360 } 361 362 // HeadGenesisValidatorRoot mocks HeadGenesisValidatorRoot method in chain service. 363 func (s *ChainService) HeadGenesisValidatorRoot() [32]byte { 364 return [32]byte{} 365 } 366 367 // VerifyBlkDescendant mocks VerifyBlkDescendant and always returns nil. 368 func (s *ChainService) VerifyBlkDescendant(_ context.Context, _ [32]byte) error { 369 return s.VerifyBlkDescendantErr 370 } 371 372 // VerifyLmdFfgConsistency mocks VerifyLmdFfgConsistency and always returns nil. 373 func (s *ChainService) VerifyLmdFfgConsistency(_ context.Context, a *ethpb.Attestation) error { 374 if !bytes.Equal(a.Data.BeaconBlockRoot, a.Data.Target.Root) { 375 return errors.New("LMD and FFG miss matched") 376 } 377 return nil 378 } 379 380 // VerifyFinalizedConsistency mocks VerifyFinalizedConsistency and always returns nil. 381 func (s *ChainService) VerifyFinalizedConsistency(_ context.Context, r []byte) error { 382 if !bytes.Equal(r, s.FinalizedCheckPoint.Root) { 383 return errors.New("Root and finalized store are not consistent") 384 } 385 return nil 386 } 387 388 // ChainHeads mocks ChainHeads and always return nil. 389 func (s *ChainService) ChainHeads() ([][32]byte, []types.Slot) { 390 return [][32]byte{ 391 bytesutil.ToBytes32(bytesutil.PadTo([]byte("foo"), 32)), 392 bytesutil.ToBytes32(bytesutil.PadTo([]byte("bar"), 32)), 393 }, 394 []types.Slot{0, 1} 395 }