github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/sync/validate_beacon_blocks_test.go (about)

     1  package sync
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"errors"
     7  	"reflect"
     8  	"testing"
     9  	"time"
    10  
    11  	lru "github.com/hashicorp/golang-lru"
    12  	pubsub "github.com/libp2p/go-libp2p-pubsub"
    13  	pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb"
    14  	gcache "github.com/patrickmn/go-cache"
    15  	types "github.com/prysmaticlabs/eth2-types"
    16  	mock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
    17  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
    18  	"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
    19  	dbtest "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
    20  	"github.com/prysmaticlabs/prysm/beacon-chain/operations/attestations"
    21  	"github.com/prysmaticlabs/prysm/beacon-chain/p2p"
    22  	p2ptest "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing"
    23  	"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
    24  	mockSync "github.com/prysmaticlabs/prysm/beacon-chain/sync/initial-sync/testing"
    25  	pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
    26  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    27  	"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
    28  	"github.com/prysmaticlabs/prysm/shared/abool"
    29  	"github.com/prysmaticlabs/prysm/shared/bls"
    30  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    31  	"github.com/prysmaticlabs/prysm/shared/params"
    32  	"github.com/prysmaticlabs/prysm/shared/testutil"
    33  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    34  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    35  	logTest "github.com/sirupsen/logrus/hooks/test"
    36  )
    37  
    38  // General note for writing validation tests: Use a random value for any field
    39  // on the beacon block to avoid hitting shared global cache conditions across
    40  // tests in this package.
    41  
    42  func TestValidateBeaconBlockPubSub_InvalidSignature(t *testing.T) {
    43  	db := dbtest.SetupDB(t)
    44  	p := p2ptest.NewTestP2P(t)
    45  	ctx := context.Background()
    46  	beaconState, _ := testutil.DeterministicGenesisState(t, 100)
    47  	parentBlock := testutil.NewBeaconBlock()
    48  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(parentBlock)))
    49  	bRoot, err := parentBlock.Block.HashTreeRoot()
    50  	require.NoError(t, err)
    51  	require.NoError(t, db.SaveState(ctx, beaconState, bRoot))
    52  	require.NoError(t, db.SaveStateSummary(ctx, &pb.StateSummary{Root: bRoot[:]}))
    53  	copied := beaconState.Copy()
    54  	require.NoError(t, copied.SetSlot(1))
    55  	proposerIdx, err := helpers.BeaconProposerIndex(copied)
    56  	require.NoError(t, err)
    57  	msg := testutil.NewBeaconBlock()
    58  	msg.Block.ParentRoot = bRoot[:]
    59  	msg.Block.Slot = 1
    60  	msg.Block.ProposerIndex = proposerIdx
    61  	msg.Signature = bytesutil.PadTo([]byte("fake"), 96)
    62  
    63  	c, err := lru.New(10)
    64  	require.NoError(t, err)
    65  	c2, err := lru.New(10)
    66  	require.NoError(t, err)
    67  	stateGen := stategen.New(db)
    68  	chainService := &mock.ChainService{Genesis: time.Unix(time.Now().Unix()-int64(params.BeaconConfig().SecondsPerSlot), 0),
    69  		FinalizedCheckPoint: &ethpb.Checkpoint{
    70  			Epoch: 0,
    71  			Root:  make([]byte, 32),
    72  		}}
    73  	r := &Service{
    74  		cfg: &Config{
    75  			DB:            db,
    76  			P2P:           p,
    77  			InitialSync:   &mockSync.Sync{IsSyncing: false},
    78  			Chain:         chainService,
    79  			BlockNotifier: chainService.BlockNotifier(),
    80  			StateGen:      stateGen,
    81  		},
    82  		seenBlockCache: c,
    83  		badBlockCache:  c2,
    84  	}
    85  
    86  	buf := new(bytes.Buffer)
    87  	_, err = p.Encoding().EncodeGossip(buf, msg)
    88  	require.NoError(t, err)
    89  	topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)]
    90  	m := &pubsub.Message{
    91  		Message: &pubsubpb.Message{
    92  			Data:  buf.Bytes(),
    93  			Topic: &topic,
    94  		},
    95  	}
    96  	result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationReject
    97  	assert.Equal(t, true, result)
    98  }
    99  
   100  func TestValidateBeaconBlockPubSub_BlockAlreadyPresentInDB(t *testing.T) {
   101  	db := dbtest.SetupDB(t)
   102  	ctx := context.Background()
   103  
   104  	p := p2ptest.NewTestP2P(t)
   105  	msg := testutil.NewBeaconBlock()
   106  	msg.Block.Slot = 100
   107  	msg.Block.ParentRoot = testutil.Random32Bytes(t)
   108  	require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(msg)))
   109  
   110  	c, err := lru.New(10)
   111  	require.NoError(t, err)
   112  	c2, err := lru.New(10)
   113  	require.NoError(t, err)
   114  	chainService := &mock.ChainService{Genesis: time.Now()}
   115  	r := &Service{
   116  		cfg: &Config{
   117  			DB:            db,
   118  			P2P:           p,
   119  			InitialSync:   &mockSync.Sync{IsSyncing: false},
   120  			Chain:         chainService,
   121  			BlockNotifier: chainService.BlockNotifier(),
   122  		},
   123  		seenBlockCache: c,
   124  		badBlockCache:  c2,
   125  	}
   126  
   127  	buf := new(bytes.Buffer)
   128  	_, err = p.Encoding().EncodeGossip(buf, msg)
   129  	require.NoError(t, err)
   130  
   131  	topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)]
   132  	m := &pubsub.Message{
   133  		Message: &pubsubpb.Message{
   134  			Data:  buf.Bytes(),
   135  			Topic: &topic,
   136  		},
   137  	}
   138  	result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept
   139  	assert.Equal(t, false, result)
   140  }
   141  
   142  func TestValidateBeaconBlockPubSub_CanRecoverStateSummary(t *testing.T) {
   143  	db := dbtest.SetupDB(t)
   144  	p := p2ptest.NewTestP2P(t)
   145  	ctx := context.Background()
   146  	beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
   147  	parentBlock := testutil.NewBeaconBlock()
   148  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(parentBlock)))
   149  	bRoot, err := parentBlock.Block.HashTreeRoot()
   150  	require.NoError(t, err)
   151  	require.NoError(t, db.SaveState(ctx, beaconState, bRoot))
   152  	copied := beaconState.Copy()
   153  	require.NoError(t, copied.SetSlot(1))
   154  	proposerIdx, err := helpers.BeaconProposerIndex(copied)
   155  	require.NoError(t, err)
   156  	msg := testutil.NewBeaconBlock()
   157  	msg.Block.ParentRoot = bRoot[:]
   158  	msg.Block.Slot = 1
   159  	msg.Block.ProposerIndex = proposerIdx
   160  	msg.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, msg.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx])
   161  	require.NoError(t, err)
   162  
   163  	c, err := lru.New(10)
   164  	require.NoError(t, err)
   165  	c2, err := lru.New(10)
   166  	require.NoError(t, err)
   167  	stateGen := stategen.New(db)
   168  	chainService := &mock.ChainService{Genesis: time.Unix(time.Now().Unix()-int64(params.BeaconConfig().SecondsPerSlot), 0),
   169  		State: beaconState,
   170  		FinalizedCheckPoint: &ethpb.Checkpoint{
   171  			Epoch: 0,
   172  			Root:  make([]byte, 32),
   173  		},
   174  	}
   175  	r := &Service{
   176  		cfg: &Config{
   177  			DB:            db,
   178  			P2P:           p,
   179  			InitialSync:   &mockSync.Sync{IsSyncing: false},
   180  			Chain:         chainService,
   181  			BlockNotifier: chainService.BlockNotifier(),
   182  			StateGen:      stateGen,
   183  		},
   184  		seenBlockCache:      c,
   185  		badBlockCache:       c2,
   186  		slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
   187  		seenPendingBlocks:   make(map[[32]byte]bool),
   188  	}
   189  	buf := new(bytes.Buffer)
   190  	_, err = p.Encoding().EncodeGossip(buf, msg)
   191  	require.NoError(t, err)
   192  	topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)]
   193  	m := &pubsub.Message{
   194  		Message: &pubsubpb.Message{
   195  			Data:  buf.Bytes(),
   196  			Topic: &topic,
   197  		},
   198  	}
   199  	result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept
   200  	assert.Equal(t, true, result)
   201  	assert.NotNil(t, m.ValidatorData, "Decoded message was not set on the message validator data")
   202  }
   203  
   204  func TestValidateBeaconBlockPubSub_ValidProposerSignature(t *testing.T) {
   205  	db := dbtest.SetupDB(t)
   206  	p := p2ptest.NewTestP2P(t)
   207  	ctx := context.Background()
   208  	beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
   209  	parentBlock := testutil.NewBeaconBlock()
   210  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(parentBlock)))
   211  	bRoot, err := parentBlock.Block.HashTreeRoot()
   212  	require.NoError(t, err)
   213  	require.NoError(t, db.SaveState(ctx, beaconState, bRoot))
   214  	require.NoError(t, db.SaveStateSummary(ctx, &pb.StateSummary{Root: bRoot[:]}))
   215  	copied := beaconState.Copy()
   216  	require.NoError(t, copied.SetSlot(1))
   217  	proposerIdx, err := helpers.BeaconProposerIndex(copied)
   218  	require.NoError(t, err)
   219  	msg := testutil.NewBeaconBlock()
   220  	msg.Block.ParentRoot = bRoot[:]
   221  	msg.Block.Slot = 1
   222  	msg.Block.ProposerIndex = proposerIdx
   223  	msg.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, msg.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx])
   224  	require.NoError(t, err)
   225  
   226  	c, err := lru.New(10)
   227  	require.NoError(t, err)
   228  	c2, err := lru.New(10)
   229  	require.NoError(t, err)
   230  	stateGen := stategen.New(db)
   231  	chainService := &mock.ChainService{Genesis: time.Unix(time.Now().Unix()-int64(params.BeaconConfig().SecondsPerSlot), 0),
   232  		State: beaconState,
   233  		FinalizedCheckPoint: &ethpb.Checkpoint{
   234  			Epoch: 0,
   235  			Root:  make([]byte, 32),
   236  		},
   237  	}
   238  	r := &Service{
   239  		cfg: &Config{
   240  			DB:            db,
   241  			P2P:           p,
   242  			InitialSync:   &mockSync.Sync{IsSyncing: false},
   243  			Chain:         chainService,
   244  			BlockNotifier: chainService.BlockNotifier(),
   245  			StateGen:      stateGen,
   246  		},
   247  		seenBlockCache:      c,
   248  		badBlockCache:       c2,
   249  		slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
   250  		seenPendingBlocks:   make(map[[32]byte]bool),
   251  	}
   252  	buf := new(bytes.Buffer)
   253  	_, err = p.Encoding().EncodeGossip(buf, msg)
   254  	require.NoError(t, err)
   255  	topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)]
   256  	m := &pubsub.Message{
   257  		Message: &pubsubpb.Message{
   258  			Data:  buf.Bytes(),
   259  			Topic: &topic,
   260  		},
   261  	}
   262  	result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept
   263  	assert.Equal(t, true, result)
   264  	assert.NotNil(t, m.ValidatorData, "Decoded message was not set on the message validator data")
   265  }
   266  
   267  func TestValidateBeaconBlockPubSub_WithLookahead(t *testing.T) {
   268  	db := dbtest.SetupDB(t)
   269  	p := p2ptest.NewTestP2P(t)
   270  	ctx := context.Background()
   271  	beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
   272  	parentBlock := testutil.NewBeaconBlock()
   273  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(parentBlock)))
   274  	bRoot, err := parentBlock.Block.HashTreeRoot()
   275  	require.NoError(t, err)
   276  	require.NoError(t, db.SaveState(ctx, beaconState, bRoot))
   277  	require.NoError(t, db.SaveStateSummary(ctx, &pb.StateSummary{Root: bRoot[:]}))
   278  	copied := beaconState.Copy()
   279  	// The next block is only 1 epoch ahead so as to not induce a new seed.
   280  	blkSlot := params.BeaconConfig().SlotsPerEpoch.Mul(uint64(helpers.NextEpoch(copied)))
   281  	copied, err = state.ProcessSlots(context.Background(), copied, blkSlot)
   282  	require.NoError(t, err)
   283  	proposerIdx, err := helpers.BeaconProposerIndex(copied)
   284  	require.NoError(t, err)
   285  	msg := testutil.NewBeaconBlock()
   286  	msg.Block.ProposerIndex = proposerIdx
   287  	msg.Block.Slot = blkSlot
   288  	msg.Block.ParentRoot = bRoot[:]
   289  	msg.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, msg.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx])
   290  	require.NoError(t, err)
   291  
   292  	c, err := lru.New(10)
   293  	require.NoError(t, err)
   294  	c2, err := lru.New(10)
   295  	require.NoError(t, err)
   296  	stateGen := stategen.New(db)
   297  	offset := int64(blkSlot.Mul(params.BeaconConfig().SecondsPerSlot))
   298  	chainService := &mock.ChainService{Genesis: time.Unix(time.Now().Unix()-offset, 0),
   299  		State: beaconState,
   300  		FinalizedCheckPoint: &ethpb.Checkpoint{
   301  			Epoch: 0,
   302  		}}
   303  	r := &Service{
   304  		cfg: &Config{
   305  			DB:            db,
   306  			P2P:           p,
   307  			InitialSync:   &mockSync.Sync{IsSyncing: false},
   308  			Chain:         chainService,
   309  			BlockNotifier: chainService.BlockNotifier(),
   310  			StateGen:      stateGen,
   311  		},
   312  		seenBlockCache:      c,
   313  		badBlockCache:       c2,
   314  		slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
   315  		seenPendingBlocks:   make(map[[32]byte]bool),
   316  	}
   317  	buf := new(bytes.Buffer)
   318  	_, err = p.Encoding().EncodeGossip(buf, msg)
   319  	require.NoError(t, err)
   320  	topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)]
   321  	m := &pubsub.Message{
   322  		Message: &pubsubpb.Message{
   323  			Data:  buf.Bytes(),
   324  			Topic: &topic,
   325  		},
   326  	}
   327  	result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept
   328  	assert.Equal(t, true, result)
   329  	assert.NotNil(t, m.ValidatorData, "Decoded message was not set on the message validator data")
   330  }
   331  
   332  func TestValidateBeaconBlockPubSub_AdvanceEpochsForState(t *testing.T) {
   333  	db := dbtest.SetupDB(t)
   334  	p := p2ptest.NewTestP2P(t)
   335  	ctx := context.Background()
   336  	beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
   337  	parentBlock := testutil.NewBeaconBlock()
   338  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(parentBlock)))
   339  	bRoot, err := parentBlock.Block.HashTreeRoot()
   340  	require.NoError(t, err)
   341  	require.NoError(t, db.SaveState(ctx, beaconState, bRoot))
   342  	require.NoError(t, db.SaveStateSummary(ctx, &pb.StateSummary{Root: bRoot[:]}))
   343  	copied := beaconState.Copy()
   344  	// The next block is at least 2 epochs ahead to induce shuffling and a new seed.
   345  	blkSlot := params.BeaconConfig().SlotsPerEpoch * 2
   346  	copied, err = state.ProcessSlots(context.Background(), copied, blkSlot)
   347  	require.NoError(t, err)
   348  	proposerIdx, err := helpers.BeaconProposerIndex(copied)
   349  	require.NoError(t, err)
   350  	msg := testutil.NewBeaconBlock()
   351  	msg.Block.ProposerIndex = proposerIdx
   352  	msg.Block.Slot = blkSlot
   353  	msg.Block.ParentRoot = bRoot[:]
   354  	msg.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, msg.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx])
   355  	require.NoError(t, err)
   356  
   357  	c, err := lru.New(10)
   358  	require.NoError(t, err)
   359  	c2, err := lru.New(10)
   360  	require.NoError(t, err)
   361  	stateGen := stategen.New(db)
   362  	offset := int64(blkSlot.Mul(params.BeaconConfig().SecondsPerSlot))
   363  	chainService := &mock.ChainService{Genesis: time.Unix(time.Now().Unix()-offset, 0),
   364  		State: beaconState,
   365  		FinalizedCheckPoint: &ethpb.Checkpoint{
   366  			Epoch: 0,
   367  		}}
   368  	r := &Service{
   369  		cfg: &Config{
   370  			DB:            db,
   371  			P2P:           p,
   372  			InitialSync:   &mockSync.Sync{IsSyncing: false},
   373  			Chain:         chainService,
   374  			BlockNotifier: chainService.BlockNotifier(),
   375  			StateGen:      stateGen,
   376  		},
   377  		seenBlockCache:      c,
   378  		badBlockCache:       c2,
   379  		slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
   380  		seenPendingBlocks:   make(map[[32]byte]bool),
   381  	}
   382  	buf := new(bytes.Buffer)
   383  	_, err = p.Encoding().EncodeGossip(buf, msg)
   384  	require.NoError(t, err)
   385  	topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)]
   386  	m := &pubsub.Message{
   387  		Message: &pubsubpb.Message{
   388  			Data:  buf.Bytes(),
   389  			Topic: &topic,
   390  		},
   391  	}
   392  	result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept
   393  	assert.Equal(t, true, result)
   394  	assert.NotNil(t, m.ValidatorData, "Decoded message was not set on the message validator data")
   395  }
   396  
   397  func TestValidateBeaconBlockPubSub_Syncing(t *testing.T) {
   398  	db := dbtest.SetupDB(t)
   399  	p := p2ptest.NewTestP2P(t)
   400  	ctx := context.Background()
   401  	b := []byte("sk")
   402  	b32 := bytesutil.ToBytes32(b)
   403  	sk, err := bls.SecretKeyFromBytes(b32[:])
   404  	require.NoError(t, err)
   405  	msg := testutil.NewBeaconBlock()
   406  	msg.Block.ParentRoot = testutil.Random32Bytes(t)
   407  	msg.Signature = sk.Sign([]byte("data")).Marshal()
   408  	chainService := &mock.ChainService{
   409  		Genesis: time.Now(),
   410  		FinalizedCheckPoint: &ethpb.Checkpoint{
   411  			Epoch: 0,
   412  		}}
   413  	r := &Service{
   414  		cfg: &Config{
   415  			DB:            db,
   416  			P2P:           p,
   417  			InitialSync:   &mockSync.Sync{IsSyncing: true},
   418  			Chain:         chainService,
   419  			BlockNotifier: chainService.BlockNotifier(),
   420  		},
   421  	}
   422  
   423  	buf := new(bytes.Buffer)
   424  	_, err = p.Encoding().EncodeGossip(buf, msg)
   425  	require.NoError(t, err)
   426  	topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)]
   427  	m := &pubsub.Message{
   428  		Message: &pubsubpb.Message{
   429  			Data:  buf.Bytes(),
   430  			Topic: &topic,
   431  		},
   432  	}
   433  	result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept
   434  	assert.Equal(t, false, result)
   435  }
   436  
   437  func TestValidateBeaconBlockPubSub_AcceptBlocksFromNearFuture(t *testing.T) {
   438  	db := dbtest.SetupDB(t)
   439  	p := p2ptest.NewTestP2P(t)
   440  	ctx := context.Background()
   441  
   442  	beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
   443  	parentBlock := testutil.NewBeaconBlock()
   444  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(parentBlock)))
   445  	bRoot, err := parentBlock.Block.HashTreeRoot()
   446  	require.NoError(t, err)
   447  	require.NoError(t, db.SaveState(ctx, beaconState, bRoot))
   448  	require.NoError(t, db.SaveStateSummary(ctx, &pb.StateSummary{Root: bRoot[:]}))
   449  	copied := beaconState.Copy()
   450  	require.NoError(t, copied.SetSlot(1))
   451  	proposerIdx, err := helpers.BeaconProposerIndex(copied)
   452  	require.NoError(t, err)
   453  
   454  	msg := testutil.NewBeaconBlock()
   455  	msg.Block.Slot = 2 // two slots in future
   456  	msg.Block.ParentRoot = bRoot[:]
   457  	msg.Block.ProposerIndex = proposerIdx
   458  	msg.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, msg.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx])
   459  	require.NoError(t, err)
   460  
   461  	c, err := lru.New(10)
   462  	require.NoError(t, err)
   463  	c2, err := lru.New(10)
   464  	require.NoError(t, err)
   465  	stateGen := stategen.New(db)
   466  	chainService := &mock.ChainService{Genesis: time.Now(),
   467  		FinalizedCheckPoint: &ethpb.Checkpoint{
   468  			Epoch: 0,
   469  			Root:  make([]byte, 32),
   470  		}}
   471  	r := &Service{
   472  		cfg: &Config{
   473  			P2P:           p,
   474  			DB:            db,
   475  			InitialSync:   &mockSync.Sync{IsSyncing: false},
   476  			Chain:         chainService,
   477  			BlockNotifier: chainService.BlockNotifier(),
   478  			StateGen:      stateGen,
   479  		},
   480  		chainStarted:        abool.New(),
   481  		seenBlockCache:      c,
   482  		badBlockCache:       c2,
   483  		slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
   484  		seenPendingBlocks:   make(map[[32]byte]bool),
   485  	}
   486  
   487  	buf := new(bytes.Buffer)
   488  	_, err = p.Encoding().EncodeGossip(buf, msg)
   489  	require.NoError(t, err)
   490  	topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)]
   491  	m := &pubsub.Message{
   492  		Message: &pubsubpb.Message{
   493  			Data:  buf.Bytes(),
   494  			Topic: &topic,
   495  		},
   496  	}
   497  	result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationIgnore
   498  	assert.Equal(t, true, result)
   499  
   500  	// check if the block is inserted in the Queue
   501  	assert.Equal(t, true, len(r.pendingBlocksInCache(msg.Block.Slot)) == 1)
   502  }
   503  
   504  func TestValidateBeaconBlockPubSub_RejectBlocksFromFuture(t *testing.T) {
   505  	db := dbtest.SetupDB(t)
   506  	p := p2ptest.NewTestP2P(t)
   507  	ctx := context.Background()
   508  	b := []byte("sk")
   509  	b32 := bytesutil.ToBytes32(b)
   510  	sk, err := bls.SecretKeyFromBytes(b32[:])
   511  	require.NoError(t, err)
   512  	msg := testutil.NewBeaconBlock()
   513  	msg.Block.Slot = 3
   514  	msg.Block.ParentRoot = testutil.Random32Bytes(t)
   515  	msg.Signature = sk.Sign([]byte("data")).Marshal()
   516  
   517  	c, err := lru.New(10)
   518  	require.NoError(t, err)
   519  	c2, err := lru.New(10)
   520  	require.NoError(t, err)
   521  	chainService := &mock.ChainService{Genesis: time.Now()}
   522  	r := &Service{
   523  		cfg: &Config{
   524  			P2P:           p,
   525  			DB:            db,
   526  			InitialSync:   &mockSync.Sync{IsSyncing: false},
   527  			Chain:         chainService,
   528  			BlockNotifier: chainService.BlockNotifier(),
   529  		},
   530  		chainStarted:        abool.New(),
   531  		seenBlockCache:      c,
   532  		badBlockCache:       c2,
   533  		slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
   534  		seenPendingBlocks:   make(map[[32]byte]bool),
   535  	}
   536  
   537  	buf := new(bytes.Buffer)
   538  	_, err = p.Encoding().EncodeGossip(buf, msg)
   539  	require.NoError(t, err)
   540  	topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)]
   541  	m := &pubsub.Message{
   542  		Message: &pubsubpb.Message{
   543  			Data:  buf.Bytes(),
   544  			Topic: &topic,
   545  		},
   546  	}
   547  	result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept
   548  	assert.Equal(t, false, result)
   549  }
   550  
   551  func TestValidateBeaconBlockPubSub_RejectBlocksFromThePast(t *testing.T) {
   552  	db := dbtest.SetupDB(t)
   553  	b := []byte("sk")
   554  	b32 := bytesutil.ToBytes32(b)
   555  	p := p2ptest.NewTestP2P(t)
   556  	ctx := context.Background()
   557  	sk, err := bls.SecretKeyFromBytes(b32[:])
   558  	require.NoError(t, err)
   559  	msg := testutil.NewBeaconBlock()
   560  	msg.Block.ParentRoot = testutil.Random32Bytes(t)
   561  	msg.Block.Slot = 10
   562  	msg.Signature = sk.Sign([]byte("data")).Marshal()
   563  
   564  	genesisTime := time.Now()
   565  	c, err := lru.New(10)
   566  	require.NoError(t, err)
   567  	c2, err := lru.New(10)
   568  	require.NoError(t, err)
   569  	chainService := &mock.ChainService{
   570  		Genesis: time.Unix(genesisTime.Unix()-1000, 0),
   571  		FinalizedCheckPoint: &ethpb.Checkpoint{
   572  			Epoch: 1,
   573  		},
   574  	}
   575  	r := &Service{
   576  		cfg: &Config{
   577  			DB:            db,
   578  			P2P:           p,
   579  			InitialSync:   &mockSync.Sync{IsSyncing: false},
   580  			Chain:         chainService,
   581  			BlockNotifier: chainService.BlockNotifier(),
   582  		},
   583  		seenBlockCache: c,
   584  		badBlockCache:  c2,
   585  	}
   586  
   587  	buf := new(bytes.Buffer)
   588  	_, err = p.Encoding().EncodeGossip(buf, msg)
   589  	require.NoError(t, err)
   590  	topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)]
   591  	m := &pubsub.Message{
   592  		Message: &pubsubpb.Message{
   593  			Data:  buf.Bytes(),
   594  			Topic: &topic,
   595  		},
   596  	}
   597  	result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept
   598  	assert.Equal(t, false, result)
   599  }
   600  
   601  func TestValidateBeaconBlockPubSub_SeenProposerSlot(t *testing.T) {
   602  	db := dbtest.SetupDB(t)
   603  	p := p2ptest.NewTestP2P(t)
   604  	ctx := context.Background()
   605  	beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
   606  	parentBlock := testutil.NewBeaconBlock()
   607  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(parentBlock)))
   608  	bRoot, err := parentBlock.Block.HashTreeRoot()
   609  	require.NoError(t, err)
   610  	require.NoError(t, db.SaveState(ctx, beaconState, bRoot))
   611  	proposerIdx, err := helpers.BeaconProposerIndex(beaconState)
   612  	require.NoError(t, err)
   613  
   614  	msg := testutil.NewBeaconBlock()
   615  	msg.Block.Slot = 1
   616  	msg.Block.ProposerIndex = proposerIdx
   617  	msg.Block.ParentRoot = bRoot[:]
   618  	msg.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, msg.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx])
   619  	require.NoError(t, err)
   620  
   621  	c, err := lru.New(10)
   622  	require.NoError(t, err)
   623  	c2, err := lru.New(10)
   624  	require.NoError(t, err)
   625  	chainService := &mock.ChainService{Genesis: time.Unix(time.Now().Unix()-int64(params.BeaconConfig().SecondsPerSlot), 0),
   626  		State: beaconState,
   627  		FinalizedCheckPoint: &ethpb.Checkpoint{
   628  			Epoch: 0,
   629  			Root:  make([]byte, 32),
   630  		},
   631  	}
   632  	r := &Service{
   633  		cfg: &Config{
   634  			DB:            db,
   635  			P2P:           p,
   636  			InitialSync:   &mockSync.Sync{IsSyncing: false},
   637  			Chain:         chainService,
   638  			BlockNotifier: chainService.BlockNotifier(),
   639  		},
   640  		seenBlockCache:      c,
   641  		badBlockCache:       c2,
   642  		slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
   643  		seenPendingBlocks:   make(map[[32]byte]bool),
   644  	}
   645  
   646  	buf := new(bytes.Buffer)
   647  	_, err = p.Encoding().EncodeGossip(buf, msg)
   648  	require.NoError(t, err)
   649  	topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)]
   650  	m := &pubsub.Message{
   651  		Message: &pubsubpb.Message{
   652  			Data:  buf.Bytes(),
   653  			Topic: &topic,
   654  		},
   655  	}
   656  	r.setSeenBlockIndexSlot(msg.Block.Slot, msg.Block.ProposerIndex)
   657  	time.Sleep(10 * time.Millisecond) // Wait for cached value to pass through buffers.
   658  	result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept
   659  	assert.Equal(t, false, result)
   660  }
   661  
   662  func TestValidateBeaconBlockPubSub_FilterByFinalizedEpoch(t *testing.T) {
   663  	hook := logTest.NewGlobal()
   664  	db := dbtest.SetupDB(t)
   665  	p := p2ptest.NewTestP2P(t)
   666  
   667  	parent := testutil.NewBeaconBlock()
   668  	require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(parent)))
   669  	parentRoot, err := parent.Block.HashTreeRoot()
   670  	require.NoError(t, err)
   671  	chain := &mock.ChainService{Genesis: time.Unix(time.Now().Unix()-int64(params.BeaconConfig().SecondsPerSlot), 0),
   672  		FinalizedCheckPoint: &ethpb.Checkpoint{
   673  			Epoch: 1,
   674  		}}
   675  	c, err := lru.New(10)
   676  	require.NoError(t, err)
   677  	c2, err := lru.New(10)
   678  	require.NoError(t, err)
   679  	r := &Service{
   680  		cfg: &Config{
   681  			DB:            db,
   682  			P2P:           p,
   683  			Chain:         chain,
   684  			BlockNotifier: chain.BlockNotifier(),
   685  			AttPool:       attestations.NewPool(),
   686  			InitialSync:   &mockSync.Sync{IsSyncing: false},
   687  		},
   688  		seenBlockCache: c,
   689  		badBlockCache:  c2,
   690  	}
   691  
   692  	b := testutil.NewBeaconBlock()
   693  	b.Block.Slot = 1
   694  	b.Block.ParentRoot = parentRoot[:]
   695  	buf := new(bytes.Buffer)
   696  	_, err = p.Encoding().EncodeGossip(buf, b)
   697  	require.NoError(t, err)
   698  	topic := p2p.GossipTypeMapping[reflect.TypeOf(b)]
   699  	m := &pubsub.Message{
   700  		Message: &pubsubpb.Message{
   701  			Data:  buf.Bytes(),
   702  			Topic: &topic,
   703  		},
   704  	}
   705  
   706  	r.validateBeaconBlockPubSub(context.Background(), "", m)
   707  
   708  	hook.Reset()
   709  	b.Block.Slot = params.BeaconConfig().SlotsPerEpoch
   710  	buf = new(bytes.Buffer)
   711  	_, err = p.Encoding().EncodeGossip(buf, b)
   712  	require.NoError(t, err)
   713  	m = &pubsub.Message{
   714  		Message: &pubsubpb.Message{
   715  			Data:  buf.Bytes(),
   716  			Topic: &topic,
   717  		},
   718  	}
   719  
   720  	r.validateBeaconBlockPubSub(context.Background(), "", m)
   721  }
   722  
   723  func TestValidateBeaconBlockPubSub_ParentNotFinalizedDescendant(t *testing.T) {
   724  	hook := logTest.NewGlobal()
   725  	db := dbtest.SetupDB(t)
   726  	p := p2ptest.NewTestP2P(t)
   727  	ctx := context.Background()
   728  	beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
   729  	parentBlock := testutil.NewBeaconBlock()
   730  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(parentBlock)))
   731  	bRoot, err := parentBlock.Block.HashTreeRoot()
   732  	require.NoError(t, err)
   733  	require.NoError(t, db.SaveState(ctx, beaconState, bRoot))
   734  	require.NoError(t, db.SaveStateSummary(ctx, &pb.StateSummary{Root: bRoot[:]}))
   735  	copied := beaconState.Copy()
   736  	require.NoError(t, copied.SetSlot(1))
   737  	proposerIdx, err := helpers.BeaconProposerIndex(copied)
   738  	require.NoError(t, err)
   739  	msg := testutil.NewBeaconBlock()
   740  	msg.Block.Slot = 1
   741  	msg.Block.ProposerIndex = proposerIdx
   742  	msg.Block.ParentRoot = bRoot[:]
   743  	msg.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, msg.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx])
   744  	require.NoError(t, err)
   745  
   746  	c, err := lru.New(10)
   747  	require.NoError(t, err)
   748  	c2, err := lru.New(10)
   749  	require.NoError(t, err)
   750  	stateGen := stategen.New(db)
   751  	chainService := &mock.ChainService{Genesis: time.Unix(time.Now().Unix()-int64(params.BeaconConfig().SecondsPerSlot), 0),
   752  		State: beaconState,
   753  		FinalizedCheckPoint: &ethpb.Checkpoint{
   754  			Epoch: 0,
   755  			Root:  make([]byte, 32),
   756  		},
   757  		VerifyBlkDescendantErr: errors.New("not part of finalized chain"),
   758  	}
   759  	r := &Service{
   760  		cfg: &Config{
   761  			DB:            db,
   762  			P2P:           p,
   763  			InitialSync:   &mockSync.Sync{IsSyncing: false},
   764  			Chain:         chainService,
   765  			BlockNotifier: chainService.BlockNotifier(),
   766  			StateGen:      stateGen,
   767  		},
   768  		seenBlockCache:      c,
   769  		badBlockCache:       c2,
   770  		slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
   771  		seenPendingBlocks:   make(map[[32]byte]bool),
   772  	}
   773  	buf := new(bytes.Buffer)
   774  	_, err = p.Encoding().EncodeGossip(buf, msg)
   775  	require.NoError(t, err)
   776  	topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)]
   777  	m := &pubsub.Message{
   778  		Message: &pubsubpb.Message{
   779  			Data:  buf.Bytes(),
   780  			Topic: &topic,
   781  		},
   782  	}
   783  	assert.Equal(t, pubsub.ValidationReject, r.validateBeaconBlockPubSub(ctx, "", m), "Wrong validation result returned")
   784  	require.LogsContain(t, hook, "not part of finalized chain")
   785  }
   786  
   787  func TestValidateBeaconBlockPubSub_InvalidParentBlock(t *testing.T) {
   788  	db := dbtest.SetupDB(t)
   789  	p := p2ptest.NewTestP2P(t)
   790  	ctx := context.Background()
   791  	beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
   792  	parentBlock := testutil.NewBeaconBlock()
   793  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(parentBlock)))
   794  	bRoot, err := parentBlock.Block.HashTreeRoot()
   795  	require.NoError(t, err)
   796  	require.NoError(t, db.SaveState(ctx, beaconState, bRoot))
   797  	require.NoError(t, db.SaveStateSummary(ctx, &pb.StateSummary{Root: bRoot[:]}))
   798  	copied := beaconState.Copy()
   799  	require.NoError(t, copied.SetSlot(1))
   800  	proposerIdx, err := helpers.BeaconProposerIndex(copied)
   801  	require.NoError(t, err)
   802  	msg := testutil.NewBeaconBlock()
   803  	msg.Block.ProposerIndex = proposerIdx
   804  	msg.Block.Slot = 1
   805  	msg.Block.ParentRoot = bRoot[:]
   806  	msg.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, msg.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx])
   807  	require.NoError(t, err)
   808  
   809  	// Mutate Signature
   810  	copy(msg.Signature[:4], []byte{1, 2, 3, 4})
   811  	currBlockRoot, err := msg.Block.HashTreeRoot()
   812  	require.NoError(t, err)
   813  
   814  	c, err := lru.New(10)
   815  	require.NoError(t, err)
   816  	c2, err := lru.New(10)
   817  	require.NoError(t, err)
   818  	stateGen := stategen.New(db)
   819  	chainService := &mock.ChainService{Genesis: time.Unix(time.Now().Unix()-int64(params.BeaconConfig().SecondsPerSlot), 0),
   820  		State: beaconState,
   821  		FinalizedCheckPoint: &ethpb.Checkpoint{
   822  			Epoch: 0,
   823  		}}
   824  	r := &Service{
   825  		cfg: &Config{
   826  			DB:            db,
   827  			P2P:           p,
   828  			InitialSync:   &mockSync.Sync{IsSyncing: false},
   829  			Chain:         chainService,
   830  			BlockNotifier: chainService.BlockNotifier(),
   831  			StateGen:      stateGen,
   832  		},
   833  		seenBlockCache:      c,
   834  		badBlockCache:       c2,
   835  		slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
   836  		seenPendingBlocks:   make(map[[32]byte]bool),
   837  	}
   838  	buf := new(bytes.Buffer)
   839  	_, err = p.Encoding().EncodeGossip(buf, msg)
   840  	require.NoError(t, err)
   841  	topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)]
   842  	m := &pubsub.Message{
   843  		Message: &pubsubpb.Message{
   844  			Data:  buf.Bytes(),
   845  			Topic: &topic,
   846  		},
   847  	}
   848  	result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept
   849  	assert.Equal(t, false, result)
   850  
   851  	require.NoError(t, copied.SetSlot(2))
   852  	proposerIdx, err = helpers.BeaconProposerIndex(copied)
   853  	require.NoError(t, err)
   854  
   855  	msg = testutil.NewBeaconBlock()
   856  	msg.Block.Slot = 2
   857  	msg.Block.ProposerIndex = proposerIdx
   858  	msg.Block.ParentRoot = currBlockRoot[:]
   859  
   860  	buf = new(bytes.Buffer)
   861  	_, err = p.Encoding().EncodeGossip(buf, msg)
   862  	require.NoError(t, err)
   863  	m = &pubsub.Message{
   864  		Message: &pubsubpb.Message{
   865  			Data:  buf.Bytes(),
   866  			Topic: &topic,
   867  		},
   868  	}
   869  
   870  	// Expect block with bad parent to fail too
   871  	result = r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept
   872  	assert.Equal(t, false, result)
   873  }
   874  
   875  func TestValidateBeaconBlockPubSub_RejectEvilBlocksFromFuture(t *testing.T) {
   876  	db := dbtest.SetupDB(t)
   877  	p := p2ptest.NewTestP2P(t)
   878  	ctx := context.Background()
   879  
   880  	beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
   881  	parentBlock := testutil.NewBeaconBlock()
   882  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(parentBlock)))
   883  	bRoot, err := parentBlock.Block.HashTreeRoot()
   884  	require.NoError(t, err)
   885  	require.NoError(t, db.SaveState(ctx, beaconState, bRoot))
   886  	require.NoError(t, db.SaveStateSummary(ctx, &pb.StateSummary{Root: bRoot[:]}))
   887  
   888  	copied := beaconState.Copy()
   889  	// The next block is at least 2 epochs ahead to induce shuffling and a new seed.
   890  	blkSlot := params.BeaconConfig().SlotsPerEpoch * 2
   891  	copied, err = state.ProcessSlots(context.Background(), copied, blkSlot)
   892  	require.NoError(t, err)
   893  	proposerIdx, err := helpers.BeaconProposerIndex(copied)
   894  	require.NoError(t, err)
   895  
   896  	msg := testutil.NewBeaconBlock()
   897  	msg.Block.ProposerIndex = proposerIdx
   898  	msg.Block.Slot = blkSlot
   899  
   900  	perSlot := params.BeaconConfig().SecondsPerSlot
   901  	// current slot time
   902  	slotsSinceGenesis := types.Slot(1000)
   903  	// max uint, divided by slot time. But avoid losing precision too much.
   904  	overflowBase := (1 << 63) / (perSlot >> 1)
   905  	msg.Block.Slot = slotsSinceGenesis.Add(overflowBase)
   906  
   907  	// valid block
   908  	msg.Block.ParentRoot = bRoot[:]
   909  	msg.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, msg.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx])
   910  	require.NoError(t, err)
   911  
   912  	genesisTime := time.Now()
   913  	c, err := lru.New(10)
   914  	require.NoError(t, err)
   915  	c2, err := lru.New(10)
   916  	require.NoError(t, err)
   917  
   918  	stateGen := stategen.New(db)
   919  	chainService := &mock.ChainService{
   920  		Genesis: time.Unix(genesisTime.Unix()-int64(slotsSinceGenesis.Mul(perSlot)), 0),
   921  		FinalizedCheckPoint: &ethpb.Checkpoint{
   922  			Epoch: 0,
   923  		},
   924  	}
   925  	r := &Service{
   926  		cfg: &Config{
   927  			DB:            db,
   928  			P2P:           p,
   929  			InitialSync:   &mockSync.Sync{IsSyncing: false},
   930  			Chain:         chainService,
   931  			BlockNotifier: chainService.BlockNotifier(),
   932  			StateGen:      stateGen,
   933  		},
   934  		seenBlockCache:      c,
   935  		badBlockCache:       c2,
   936  		slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
   937  		seenPendingBlocks:   make(map[[32]byte]bool),
   938  	}
   939  
   940  	buf := new(bytes.Buffer)
   941  	_, err = p.Encoding().EncodeGossip(buf, msg)
   942  	require.NoError(t, err)
   943  	topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)]
   944  	m := &pubsub.Message{
   945  		Message: &pubsubpb.Message{
   946  			Data:  buf.Bytes(),
   947  			Topic: &topic,
   948  		},
   949  	}
   950  	result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept
   951  	assert.Equal(t, false, result)
   952  }
   953  
   954  func TestService_setBadBlock_DoesntSetWithContextErr(t *testing.T) {
   955  	s := Service{}
   956  	require.NoError(t, s.initCaches())
   957  
   958  	root := [32]byte{'b', 'a', 'd'}
   959  	ctx, cancel := context.WithCancel(context.Background())
   960  	cancel()
   961  	s.setBadBlock(ctx, root)
   962  	if s.hasBadBlock(root) {
   963  		t.Error("Set bad root with cancelled context")
   964  	}
   965  }
   966  
   967  func TestService_isBlockQueueable(t *testing.T) {
   968  	currentTime := time.Now().Round(time.Second)
   969  	genesisTime := uint64(currentTime.Unix() - int64(params.BeaconConfig().SecondsPerSlot))
   970  	blockSlot := types.Slot(1)
   971  
   972  	// slot time within MAXIMUM_GOSSIP_CLOCK_DISPARITY, so dont queue the block.
   973  	receivedTime := currentTime.Add(-400 * time.Millisecond)
   974  	result := isBlockQueueable(genesisTime, blockSlot, receivedTime)
   975  	assert.Equal(t, false, result)
   976  
   977  	// slot time just above MAXIMUM_GOSSIP_CLOCK_DISPARITY, so queue the block.
   978  	receivedTime = currentTime.Add(-600 * time.Millisecond)
   979  	result = isBlockQueueable(genesisTime, blockSlot, receivedTime)
   980  	assert.Equal(t, true, result)
   981  }