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  }