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

     1  package sync
     2  
     3  import (
     4  	"context"
     5  	"math"
     6  	"sync"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/ethereum/go-ethereum/p2p/enr"
    11  	"github.com/libp2p/go-libp2p-core/network"
    12  	"github.com/libp2p/go-libp2p-core/protocol"
    13  	gcache "github.com/patrickmn/go-cache"
    14  	types "github.com/prysmaticlabs/eth2-types"
    15  	mock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
    16  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
    17  	dbtest "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
    18  	"github.com/prysmaticlabs/prysm/beacon-chain/p2p/peers"
    19  	p2ptest "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing"
    20  	p2ptypes "github.com/prysmaticlabs/prysm/beacon-chain/p2p/types"
    21  	"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
    22  	pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
    23  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    24  	"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
    25  	"github.com/prysmaticlabs/prysm/shared/copyutil"
    26  	"github.com/prysmaticlabs/prysm/shared/params"
    27  	"github.com/prysmaticlabs/prysm/shared/rand"
    28  	"github.com/prysmaticlabs/prysm/shared/testutil"
    29  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    30  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    31  )
    32  
    33  //    /- b1 - b2
    34  // b0
    35  //    \- b3
    36  // Test b1 was missing then received and we can process b0 -> b1 -> b2
    37  func TestRegularSyncBeaconBlockSubscriber_ProcessPendingBlocks1(t *testing.T) {
    38  	db := dbtest.SetupDB(t)
    39  
    40  	p1 := p2ptest.NewTestP2P(t)
    41  	r := &Service{
    42  		cfg: &Config{
    43  			P2P: p1,
    44  			DB:  db,
    45  			Chain: &mock.ChainService{
    46  				FinalizedCheckPoint: &ethpb.Checkpoint{
    47  					Epoch: 0,
    48  				},
    49  			},
    50  			StateGen: stategen.New(db),
    51  		},
    52  		slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
    53  		seenPendingBlocks:   make(map[[32]byte]bool),
    54  	}
    55  	err := r.initCaches()
    56  	require.NoError(t, err)
    57  
    58  	b0 := testutil.NewBeaconBlock()
    59  	require.NoError(t, r.cfg.DB.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(b0)))
    60  	b0Root, err := b0.Block.HashTreeRoot()
    61  	require.NoError(t, err)
    62  	b3 := testutil.NewBeaconBlock()
    63  	b3.Block.Slot = 3
    64  	b3.Block.ParentRoot = b0Root[:]
    65  	require.NoError(t, r.cfg.DB.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(b3)))
    66  	// Incomplete block link
    67  	b1 := testutil.NewBeaconBlock()
    68  	b1.Block.Slot = 1
    69  	b1.Block.ParentRoot = b0Root[:]
    70  	b1Root, err := b1.Block.HashTreeRoot()
    71  	require.NoError(t, err)
    72  	b2 := testutil.NewBeaconBlock()
    73  	b2.Block.Slot = 2
    74  	b2.Block.ParentRoot = b1Root[:]
    75  	b2Root, err := b1.Block.HashTreeRoot()
    76  	require.NoError(t, err)
    77  
    78  	// Add b2 to the cache
    79  	require.NoError(t, r.insertBlockToPendingQueue(b2.Block.Slot, wrapper.WrappedPhase0SignedBeaconBlock(b2), b2Root))
    80  
    81  	require.NoError(t, r.processPendingBlocks(context.Background()))
    82  	assert.Equal(t, 1, len(r.slotToPendingBlocks.Items()), "Incorrect size for slot to pending blocks cache")
    83  	assert.Equal(t, 1, len(r.seenPendingBlocks), "Incorrect size for seen pending block")
    84  
    85  	// Add b1 to the cache
    86  	require.NoError(t, r.insertBlockToPendingQueue(b1.Block.Slot, wrapper.WrappedPhase0SignedBeaconBlock(b1), b1Root))
    87  	require.NoError(t, r.cfg.DB.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(b1)))
    88  
    89  	// Insert bad b1 in the cache to verify the good one doesn't get replaced.
    90  	require.NoError(t, r.insertBlockToPendingQueue(b1.Block.Slot, wrapper.WrappedPhase0SignedBeaconBlock(testutil.NewBeaconBlock()), [32]byte{}))
    91  
    92  	require.NoError(t, r.processPendingBlocks(context.Background())) // Marks a block as bad
    93  	require.NoError(t, r.processPendingBlocks(context.Background())) // Bad block removed on second run
    94  
    95  	assert.Equal(t, 1, len(r.slotToPendingBlocks.Items()), "Incorrect size for slot to pending blocks cache")
    96  	assert.Equal(t, 2, len(r.seenPendingBlocks), "Incorrect size for seen pending block")
    97  }
    98  
    99  func TestRegularSync_InsertDuplicateBlocks(t *testing.T) {
   100  	db := dbtest.SetupDB(t)
   101  
   102  	p1 := p2ptest.NewTestP2P(t)
   103  	r := &Service{
   104  		cfg: &Config{
   105  			P2P: p1,
   106  			DB:  db,
   107  			Chain: &mock.ChainService{
   108  				FinalizedCheckPoint: &ethpb.Checkpoint{
   109  					Epoch: 0,
   110  					Root:  make([]byte, 32),
   111  				},
   112  			},
   113  		},
   114  		slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
   115  		seenPendingBlocks:   make(map[[32]byte]bool),
   116  	}
   117  	err := r.initCaches()
   118  	require.NoError(t, err)
   119  
   120  	b0 := testutil.NewBeaconBlock()
   121  	b0r := [32]byte{'a'}
   122  	require.NoError(t, r.cfg.DB.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(b0)))
   123  	b0Root, err := b0.Block.HashTreeRoot()
   124  	require.NoError(t, err)
   125  	b1 := testutil.NewBeaconBlock()
   126  	b1.Block.Slot = 1
   127  	b1.Block.ParentRoot = b0Root[:]
   128  	b1r := [32]byte{'b'}
   129  
   130  	require.NoError(t, r.insertBlockToPendingQueue(b0.Block.Slot, wrapper.WrappedPhase0SignedBeaconBlock(b0), b0r))
   131  	require.Equal(t, 1, len(r.pendingBlocksInCache(b0.Block.Slot)), "Block was not added to map")
   132  
   133  	require.NoError(t, r.insertBlockToPendingQueue(b1.Block.Slot, wrapper.WrappedPhase0SignedBeaconBlock(b1), b1r))
   134  	require.Equal(t, 1, len(r.pendingBlocksInCache(b1.Block.Slot)), "Block was not added to map")
   135  
   136  	// Add duplicate block which should not be saved.
   137  	require.NoError(t, r.insertBlockToPendingQueue(b0.Block.Slot, wrapper.WrappedPhase0SignedBeaconBlock(b0), b0r))
   138  	require.Equal(t, 1, len(r.pendingBlocksInCache(b0.Block.Slot)), "Block was added to map")
   139  
   140  	// Add duplicate block which should not be saved.
   141  	require.NoError(t, r.insertBlockToPendingQueue(b1.Block.Slot, wrapper.WrappedPhase0SignedBeaconBlock(b1), b1r))
   142  	require.Equal(t, 1, len(r.pendingBlocksInCache(b1.Block.Slot)), "Block was added to map")
   143  
   144  }
   145  
   146  //    /- b1 - b2 - b5
   147  // b0
   148  //    \- b3 - b4
   149  // Test b2 and b3 were missed, after receiving them we can process 2 chains.
   150  func TestRegularSyncBeaconBlockSubscriber_ProcessPendingBlocks_2Chains(t *testing.T) {
   151  	db := dbtest.SetupDB(t)
   152  	p1 := p2ptest.NewTestP2P(t)
   153  	p2 := p2ptest.NewTestP2P(t)
   154  	p1.Connect(p2)
   155  	assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected")
   156  	pcl := protocol.ID("/eth2/beacon_chain/req/hello/1/ssz_snappy")
   157  	var wg sync.WaitGroup
   158  	wg.Add(1)
   159  	p2.BHost.SetStreamHandler(pcl, func(stream network.Stream) {
   160  		defer wg.Done()
   161  		code, errMsg, err := ReadStatusCode(stream, p1.Encoding())
   162  		assert.NoError(t, err)
   163  		if code == 0 {
   164  			t.Error("Expected a non-zero code")
   165  		}
   166  		if errMsg != p2ptypes.ErrWrongForkDigestVersion.Error() {
   167  			t.Logf("Received error string len %d, wanted error string len %d", len(errMsg), len(p2ptypes.ErrWrongForkDigestVersion.Error()))
   168  			t.Errorf("Received unexpected message response in the stream: %s. Wanted %s.", errMsg, p2ptypes.ErrWrongForkDigestVersion.Error())
   169  		}
   170  	})
   171  
   172  	r := &Service{
   173  		cfg: &Config{
   174  			P2P: p1,
   175  			DB:  db,
   176  			Chain: &mock.ChainService{
   177  				FinalizedCheckPoint: &ethpb.Checkpoint{
   178  					Epoch: 0,
   179  					Root:  make([]byte, 32),
   180  				},
   181  			},
   182  			StateGen: stategen.New(db),
   183  		},
   184  		slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
   185  		seenPendingBlocks:   make(map[[32]byte]bool),
   186  	}
   187  	err := r.initCaches()
   188  	require.NoError(t, err)
   189  	p1.Peers().Add(new(enr.Record), p2.PeerID(), nil, network.DirOutbound)
   190  	p1.Peers().SetConnectionState(p2.PeerID(), peers.PeerConnected)
   191  	p1.Peers().SetChainState(p2.PeerID(), &pb.Status{})
   192  
   193  	b0 := testutil.NewBeaconBlock()
   194  	require.NoError(t, r.cfg.DB.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(b0)))
   195  	b0Root, err := b0.Block.HashTreeRoot()
   196  	require.NoError(t, err)
   197  	b1 := testutil.NewBeaconBlock()
   198  	b1.Block.Slot = 1
   199  	b1.Block.ParentRoot = b0Root[:]
   200  	require.NoError(t, r.cfg.DB.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(b1)))
   201  	b1Root, err := b1.Block.HashTreeRoot()
   202  	require.NoError(t, err)
   203  
   204  	// Incomplete block links
   205  	b2 := testutil.NewBeaconBlock()
   206  	b2.Block.Slot = 2
   207  	b2.Block.ParentRoot = b1Root[:]
   208  	b2Root, err := b2.Block.HashTreeRoot()
   209  	require.NoError(t, err)
   210  	b5 := testutil.NewBeaconBlock()
   211  	b5.Block.Slot = 5
   212  	b5.Block.ParentRoot = b2Root[:]
   213  	b5Root, err := b5.Block.HashTreeRoot()
   214  	require.NoError(t, err)
   215  	b3 := testutil.NewBeaconBlock()
   216  	b3.Block.Slot = 3
   217  	b3.Block.ParentRoot = b0Root[:]
   218  	b3Root, err := b3.Block.HashTreeRoot()
   219  	require.NoError(t, err)
   220  	b4 := testutil.NewBeaconBlock()
   221  	b4.Block.Slot = 4
   222  	b4.Block.ParentRoot = b3Root[:]
   223  	b4Root, err := b4.Block.HashTreeRoot()
   224  	require.NoError(t, err)
   225  
   226  	require.NoError(t, r.insertBlockToPendingQueue(b4.Block.Slot, wrapper.WrappedPhase0SignedBeaconBlock(b4), b4Root))
   227  	require.NoError(t, r.insertBlockToPendingQueue(b5.Block.Slot, wrapper.WrappedPhase0SignedBeaconBlock(b5), b5Root))
   228  
   229  	require.NoError(t, r.processPendingBlocks(context.Background())) // Marks a block as bad
   230  	require.NoError(t, r.processPendingBlocks(context.Background())) // Bad block removed on second run
   231  
   232  	assert.Equal(t, 2, len(r.slotToPendingBlocks.Items()), "Incorrect size for slot to pending blocks cache")
   233  	assert.Equal(t, 2, len(r.seenPendingBlocks), "Incorrect size for seen pending block")
   234  
   235  	// Add b3 to the cache
   236  	require.NoError(t, r.insertBlockToPendingQueue(b3.Block.Slot, wrapper.WrappedPhase0SignedBeaconBlock(b3), b3Root))
   237  	require.NoError(t, r.cfg.DB.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(b3)))
   238  
   239  	require.NoError(t, r.processPendingBlocks(context.Background())) // Marks a block as bad
   240  	require.NoError(t, r.processPendingBlocks(context.Background())) // Bad block removed on second run
   241  
   242  	assert.Equal(t, 1, len(r.slotToPendingBlocks.Items()), "Incorrect size for slot to pending blocks cache")
   243  	assert.Equal(t, 3, len(r.seenPendingBlocks), "Incorrect size for seen pending block")
   244  
   245  	// Add b2 to the cache
   246  	require.NoError(t, r.insertBlockToPendingQueue(b2.Block.Slot, wrapper.WrappedPhase0SignedBeaconBlock(b2), b2Root))
   247  
   248  	require.NoError(t, r.cfg.DB.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(b2)))
   249  
   250  	require.NoError(t, r.processPendingBlocks(context.Background())) // Marks a block as bad
   251  	require.NoError(t, r.processPendingBlocks(context.Background())) // Bad block removed on second run
   252  
   253  	assert.Equal(t, 0, len(r.slotToPendingBlocks.Items()), "Incorrect size for slot to pending blocks cache")
   254  	assert.Equal(t, 4, len(r.seenPendingBlocks), "Incorrect size for seen pending block")
   255  }
   256  
   257  func TestRegularSyncBeaconBlockSubscriber_PruneOldPendingBlocks(t *testing.T) {
   258  	db := dbtest.SetupDB(t)
   259  	p1 := p2ptest.NewTestP2P(t)
   260  	p2 := p2ptest.NewTestP2P(t)
   261  	p1.Connect(p2)
   262  	assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected")
   263  
   264  	r := &Service{
   265  		cfg: &Config{
   266  			P2P: p1,
   267  			DB:  db,
   268  			Chain: &mock.ChainService{
   269  				FinalizedCheckPoint: &ethpb.Checkpoint{
   270  					Epoch: 1,
   271  					Root:  make([]byte, 32),
   272  				},
   273  			},
   274  		},
   275  		slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
   276  		seenPendingBlocks:   make(map[[32]byte]bool),
   277  	}
   278  	err := r.initCaches()
   279  	require.NoError(t, err)
   280  	p1.Peers().Add(new(enr.Record), p1.PeerID(), nil, network.DirOutbound)
   281  	p1.Peers().SetConnectionState(p1.PeerID(), peers.PeerConnected)
   282  	p1.Peers().SetChainState(p1.PeerID(), &pb.Status{})
   283  
   284  	b0 := testutil.NewBeaconBlock()
   285  	require.NoError(t, r.cfg.DB.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(b0)))
   286  	b0Root, err := b0.Block.HashTreeRoot()
   287  	require.NoError(t, err)
   288  	b1 := testutil.NewBeaconBlock()
   289  	b1.Block.Slot = 1
   290  	b1.Block.ParentRoot = b0Root[:]
   291  	require.NoError(t, r.cfg.DB.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(b1)))
   292  	b1Root, err := b1.Block.HashTreeRoot()
   293  	require.NoError(t, err)
   294  
   295  	// Incomplete block links
   296  	b2 := testutil.NewBeaconBlock()
   297  	b2.Block.Slot = 2
   298  	b2.Block.ParentRoot = b1Root[:]
   299  	b2Root, err := b2.Block.HashTreeRoot()
   300  	require.NoError(t, err)
   301  	b5 := testutil.NewBeaconBlock()
   302  	b5.Block.Slot = 5
   303  	b5.Block.ParentRoot = b2Root[:]
   304  	b5Root, err := b5.Block.HashTreeRoot()
   305  	require.NoError(t, err)
   306  	b3 := testutil.NewBeaconBlock()
   307  	b3.Block.Slot = 3
   308  	b3.Block.ParentRoot = b0Root[:]
   309  	b3Root, err := b3.Block.HashTreeRoot()
   310  	require.NoError(t, err)
   311  	b4 := testutil.NewBeaconBlock()
   312  	b4.Block.Slot = 4
   313  	b4.Block.ParentRoot = b3Root[:]
   314  	b4Root, err := b4.Block.HashTreeRoot()
   315  	require.NoError(t, err)
   316  
   317  	require.NoError(t, r.insertBlockToPendingQueue(b2.Block.Slot, wrapper.WrappedPhase0SignedBeaconBlock(b2), b2Root))
   318  	require.NoError(t, r.insertBlockToPendingQueue(b3.Block.Slot, wrapper.WrappedPhase0SignedBeaconBlock(b3), b3Root))
   319  	require.NoError(t, r.insertBlockToPendingQueue(b4.Block.Slot, wrapper.WrappedPhase0SignedBeaconBlock(b4), b4Root))
   320  	require.NoError(t, r.insertBlockToPendingQueue(b5.Block.Slot, wrapper.WrappedPhase0SignedBeaconBlock(b5), b5Root))
   321  
   322  	require.NoError(t, r.processPendingBlocks(context.Background()))
   323  	assert.Equal(t, 0, len(r.slotToPendingBlocks.Items()), "Incorrect size for slot to pending blocks cache")
   324  	assert.Equal(t, 4, len(r.seenPendingBlocks), "Incorrect size for seen pending block")
   325  }
   326  
   327  func TestService_sortedPendingSlots(t *testing.T) {
   328  	r := &Service{
   329  		slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
   330  		seenPendingBlocks:   make(map[[32]byte]bool),
   331  	}
   332  
   333  	var lastSlot types.Slot = math.MaxUint64
   334  	require.NoError(t, r.insertBlockToPendingQueue(lastSlot, wrapper.WrappedPhase0SignedBeaconBlock(testutil.HydrateSignedBeaconBlock(&ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: lastSlot}})), [32]byte{1}))
   335  	require.NoError(t, r.insertBlockToPendingQueue(lastSlot-3, wrapper.WrappedPhase0SignedBeaconBlock(testutil.HydrateSignedBeaconBlock(&ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: lastSlot - 3}})), [32]byte{2}))
   336  	require.NoError(t, r.insertBlockToPendingQueue(lastSlot-5, wrapper.WrappedPhase0SignedBeaconBlock(testutil.HydrateSignedBeaconBlock(&ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: lastSlot - 5}})), [32]byte{3}))
   337  	require.NoError(t, r.insertBlockToPendingQueue(lastSlot-2, wrapper.WrappedPhase0SignedBeaconBlock(testutil.HydrateSignedBeaconBlock(&ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: lastSlot - 2}})), [32]byte{4}))
   338  
   339  	want := []types.Slot{lastSlot - 5, lastSlot - 3, lastSlot - 2, lastSlot}
   340  	assert.DeepEqual(t, want, r.sortedPendingSlots(), "Unexpected pending slots list")
   341  }
   342  
   343  func TestService_BatchRootRequest(t *testing.T) {
   344  	db := dbtest.SetupDB(t)
   345  	p1 := p2ptest.NewTestP2P(t)
   346  	p2 := p2ptest.NewTestP2P(t)
   347  	p1.Connect(p2)
   348  	assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected")
   349  
   350  	r := &Service{
   351  		cfg: &Config{
   352  			P2P: p1,
   353  			DB:  db,
   354  			Chain: &mock.ChainService{
   355  				FinalizedCheckPoint: &ethpb.Checkpoint{
   356  					Epoch: 1,
   357  					Root:  make([]byte, 32),
   358  				},
   359  			},
   360  		},
   361  		slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
   362  		seenPendingBlocks:   make(map[[32]byte]bool),
   363  	}
   364  
   365  	err := r.initCaches()
   366  	require.NoError(t, err)
   367  	p1.Peers().Add(new(enr.Record), p2.PeerID(), nil, network.DirOutbound)
   368  	p1.Peers().SetConnectionState(p2.PeerID(), peers.PeerConnected)
   369  	p1.Peers().SetChainState(p2.PeerID(), &pb.Status{FinalizedEpoch: 2})
   370  
   371  	b0 := testutil.NewBeaconBlock()
   372  	require.NoError(t, r.cfg.DB.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(b0)))
   373  	b0Root, err := b0.Block.HashTreeRoot()
   374  	require.NoError(t, err)
   375  	b1 := testutil.NewBeaconBlock()
   376  	b1.Block.Slot = 1
   377  	b1.Block.ParentRoot = b0Root[:]
   378  	require.NoError(t, r.cfg.DB.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(b1)))
   379  	b1Root, err := b1.Block.HashTreeRoot()
   380  	require.NoError(t, err)
   381  
   382  	b2 := testutil.NewBeaconBlock()
   383  	b2.Block.Slot = 2
   384  	b2.Block.ParentRoot = b1Root[:]
   385  	b2Root, err := b2.Block.HashTreeRoot()
   386  	require.NoError(t, err)
   387  	b5 := testutil.NewBeaconBlock()
   388  	b5.Block.Slot = 5
   389  	b5.Block.ParentRoot = b2Root[:]
   390  	b5Root, err := b5.Block.HashTreeRoot()
   391  	require.NoError(t, err)
   392  	b3 := testutil.NewBeaconBlock()
   393  	b3.Block.Slot = 3
   394  	b3.Block.ParentRoot = b0Root[:]
   395  	b3Root, err := b3.Block.HashTreeRoot()
   396  	require.NoError(t, err)
   397  	b4 := testutil.NewBeaconBlock()
   398  	b4.Block.Slot = 4
   399  	b4.Block.ParentRoot = b3Root[:]
   400  	b4Root, err := b4.Block.HashTreeRoot()
   401  	require.NoError(t, err)
   402  
   403  	// Send in duplicated roots to also test deduplicaton.
   404  	sentRoots := p2ptypes.BeaconBlockByRootsReq{b2Root, b2Root, b3Root, b3Root, b4Root, b5Root}
   405  	expectedRoots := p2ptypes.BeaconBlockByRootsReq{b2Root, b3Root, b4Root, b5Root}
   406  
   407  	pcl := protocol.ID("/eth2/beacon_chain/req/beacon_blocks_by_root/1/ssz_snappy")
   408  	var wg sync.WaitGroup
   409  	wg.Add(1)
   410  	p2.BHost.SetStreamHandler(pcl, func(stream network.Stream) {
   411  		defer wg.Done()
   412  		var out p2ptypes.BeaconBlockByRootsReq
   413  		assert.NoError(t, p2.Encoding().DecodeWithMaxLength(stream, &out))
   414  		assert.DeepEqual(t, expectedRoots, out, "Did not receive expected message")
   415  		response := []*ethpb.SignedBeaconBlock{b2, b3, b4, b5}
   416  		for _, blk := range response {
   417  			_, err := stream.Write([]byte{responseCodeSuccess})
   418  			assert.NoError(t, err, "Could not write to stream")
   419  			_, err = p2.Encoding().EncodeWithMaxLength(stream, blk)
   420  			assert.NoError(t, err, "Could not send response back")
   421  		}
   422  		assert.NoError(t, stream.Close())
   423  	})
   424  
   425  	require.NoError(t, r.sendBatchRootRequest(context.Background(), sentRoots, rand.NewGenerator()))
   426  
   427  	if testutil.WaitTimeout(&wg, 1*time.Second) {
   428  		t.Fatal("Did not receive stream within 1 sec")
   429  	}
   430  	assert.Equal(t, 4, len(r.slotToPendingBlocks.Items()), "Incorrect size for slot to pending blocks cache")
   431  	assert.Equal(t, 4, len(r.seenPendingBlocks), "Incorrect size for seen pending block")
   432  }
   433  
   434  func TestService_AddPeningBlockToQueueOverMax(t *testing.T) {
   435  	r := &Service{
   436  		slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
   437  		seenPendingBlocks:   make(map[[32]byte]bool),
   438  	}
   439  
   440  	b := testutil.NewBeaconBlock()
   441  	b1 := copyutil.CopySignedBeaconBlock(b)
   442  	b1.Block.StateRoot = []byte{'a'}
   443  	b2 := copyutil.CopySignedBeaconBlock(b)
   444  	b2.Block.StateRoot = []byte{'b'}
   445  	require.NoError(t, r.insertBlockToPendingQueue(0, wrapper.WrappedPhase0SignedBeaconBlock(b), [32]byte{}))
   446  	require.NoError(t, r.insertBlockToPendingQueue(0, wrapper.WrappedPhase0SignedBeaconBlock(b1), [32]byte{1}))
   447  	require.NoError(t, r.insertBlockToPendingQueue(0, wrapper.WrappedPhase0SignedBeaconBlock(b2), [32]byte{2}))
   448  
   449  	b3 := copyutil.CopySignedBeaconBlock(b)
   450  	b3.Block.StateRoot = []byte{'c'}
   451  	require.NoError(t, r.insertBlockToPendingQueue(0, wrapper.WrappedPhase0SignedBeaconBlock(b2), [32]byte{3}))
   452  	require.Equal(t, maxBlocksPerSlot, len(r.pendingBlocksInCache(0)))
   453  }
   454  
   455  func TestService_ProcessPendingBlockOnCorrectSlot(t *testing.T) {
   456  	ctx := context.Background()
   457  	db := dbtest.SetupDB(t)
   458  
   459  	p1 := p2ptest.NewTestP2P(t)
   460  	mockChain := mock.ChainService{Genesis: time.Unix(time.Now().Unix()-int64(params.BeaconConfig().SecondsPerSlot), 0),
   461  		FinalizedCheckPoint: &ethpb.Checkpoint{
   462  			Epoch: 0,
   463  		}}
   464  	r := &Service{
   465  		cfg: &Config{
   466  			P2P:      p1,
   467  			DB:       db,
   468  			Chain:    &mockChain,
   469  			StateGen: stategen.New(db),
   470  		},
   471  		slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
   472  		seenPendingBlocks:   make(map[[32]byte]bool),
   473  	}
   474  	err := r.initCaches()
   475  	require.NoError(t, err)
   476  
   477  	beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
   478  	parentBlock := testutil.NewBeaconBlock()
   479  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(parentBlock)))
   480  	bRoot, err := parentBlock.Block.HashTreeRoot()
   481  	require.NoError(t, err)
   482  	require.NoError(t, db.SaveState(ctx, beaconState, bRoot))
   483  	require.NoError(t, db.SaveStateSummary(ctx, &pb.StateSummary{Root: bRoot[:]}))
   484  	copied := beaconState.Copy()
   485  	require.NoError(t, copied.SetSlot(1))
   486  	proposerIdx, err := helpers.BeaconProposerIndex(copied)
   487  	require.NoError(t, err)
   488  
   489  	st, err := testutil.NewBeaconState()
   490  	require.NoError(t, err)
   491  	mockChain.Root = bRoot[:]
   492  	mockChain.State = st
   493  
   494  	b1 := testutil.NewBeaconBlock()
   495  	b1.Block.ParentRoot = bRoot[:]
   496  	b1.Block.Slot = 1
   497  	b1Root, err := b1.Block.HashTreeRoot()
   498  	require.NoError(t, err)
   499  	b1.Block.ProposerIndex = proposerIdx
   500  	b1.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, b1.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx])
   501  	require.NoError(t, err)
   502  
   503  	b2 := testutil.NewBeaconBlock()
   504  	b2.Block.Slot = 2
   505  	b2.Block.ParentRoot = bRoot[:]
   506  	b2Root, err := b2.Block.HashTreeRoot()
   507  	require.NoError(t, err)
   508  
   509  	b3 := testutil.NewBeaconBlock()
   510  	b3.Block.Slot = 3
   511  	b3.Block.ParentRoot = b2Root[:]
   512  	b3Root, err := b3.Block.HashTreeRoot()
   513  	require.NoError(t, err)
   514  
   515  	// Add block1 for slot1
   516  	require.NoError(t, r.insertBlockToPendingQueue(b1.Block.Slot, wrapper.WrappedPhase0SignedBeaconBlock(b1), b1Root))
   517  	// Add block2 for slot2
   518  	require.NoError(t, r.insertBlockToPendingQueue(b2.Block.Slot, wrapper.WrappedPhase0SignedBeaconBlock(b2), b2Root))
   519  	// Add block3 for slot3
   520  	require.NoError(t, r.insertBlockToPendingQueue(b3.Block.Slot, wrapper.WrappedPhase0SignedBeaconBlock(b3), b3Root))
   521  
   522  	// processPendingBlocks should process only blocks of the current slot. i.e. slot 1.
   523  	// Then check if the other two blocks are still in the pendingQueue.
   524  	require.NoError(t, r.processPendingBlocks(context.Background()))
   525  	assert.Equal(t, 2, len(r.slotToPendingBlocks.Items()), "Incorrect size for slot to pending blocks cache")
   526  }
   527  
   528  func TestService_ProcessBadPendingBlocks(t *testing.T) {
   529  	ctx := context.Background()
   530  	db := dbtest.SetupDB(t)
   531  
   532  	p1 := p2ptest.NewTestP2P(t)
   533  	mockChain := mock.ChainService{Genesis: time.Unix(time.Now().Unix()-int64(params.BeaconConfig().SecondsPerSlot), 0),
   534  		FinalizedCheckPoint: &ethpb.Checkpoint{
   535  			Epoch: 0,
   536  		}}
   537  	r := &Service{
   538  		cfg: &Config{
   539  			P2P:      p1,
   540  			DB:       db,
   541  			Chain:    &mockChain,
   542  			StateGen: stategen.New(db),
   543  		},
   544  		slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
   545  		seenPendingBlocks:   make(map[[32]byte]bool),
   546  	}
   547  	err := r.initCaches()
   548  	require.NoError(t, err)
   549  
   550  	beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
   551  	parentBlock := testutil.NewBeaconBlock()
   552  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(parentBlock)))
   553  	bRoot, err := parentBlock.Block.HashTreeRoot()
   554  	require.NoError(t, err)
   555  	require.NoError(t, db.SaveState(ctx, beaconState, bRoot))
   556  	require.NoError(t, db.SaveStateSummary(ctx, &pb.StateSummary{Root: bRoot[:]}))
   557  	copied := beaconState.Copy()
   558  	require.NoError(t, copied.SetSlot(1))
   559  	proposerIdx, err := helpers.BeaconProposerIndex(copied)
   560  	require.NoError(t, err)
   561  
   562  	st, err := testutil.NewBeaconState()
   563  	require.NoError(t, err)
   564  	mockChain.Root = bRoot[:]
   565  	mockChain.State = st
   566  
   567  	b1 := testutil.NewBeaconBlock()
   568  	b1.Block.ParentRoot = bRoot[:]
   569  	b1.Block.Slot = 1
   570  	b1Root, err := b1.Block.HashTreeRoot()
   571  	require.NoError(t, err)
   572  	b1.Block.ProposerIndex = proposerIdx
   573  	b1.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, b1.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx])
   574  	require.NoError(t, err)
   575  
   576  	b := testutil.NewBeaconBlock()
   577  	b.Block.Slot = 55
   578  	b.Block.ParentRoot = []byte{'A', 'B', 'C'}
   579  	bA := wrapper.WrappedPhase0SignedBeaconBlock(b)
   580  	assert.NoError(t, err)
   581  
   582  	// Add block1 for slot 55
   583  	require.NoError(t, r.insertBlockToPendingQueue(b.Block.Slot, bA, b1Root))
   584  	bB := wrapper.WrappedPhase0SignedBeaconBlock(testutil.NewBeaconBlock())
   585  	assert.NoError(t, err)
   586  	// remove with a different block from the same slot.
   587  	require.NoError(t, r.deleteBlockFromPendingQueue(b.Block.Slot, bB, b1Root))
   588  }