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

     1  package sync
     2  
     3  import (
     4  	"context"
     5  	"sync"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/kevinms/leakybucket-go"
    10  	"github.com/libp2p/go-libp2p-core/network"
    11  	"github.com/libp2p/go-libp2p-core/protocol"
    12  	gcache "github.com/patrickmn/go-cache"
    13  	types "github.com/prysmaticlabs/eth2-types"
    14  	mock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
    15  	"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
    16  	db "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
    17  	"github.com/prysmaticlabs/prysm/beacon-chain/p2p"
    18  	p2ptest "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing"
    19  	p2pTypes "github.com/prysmaticlabs/prysm/beacon-chain/p2p/types"
    20  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    21  	"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
    22  	"github.com/prysmaticlabs/prysm/shared/params"
    23  	"github.com/prysmaticlabs/prysm/shared/testutil"
    24  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    25  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    26  )
    27  
    28  func TestRecentBeaconBlocksRPCHandler_ReturnsBlocks(t *testing.T) {
    29  	p1 := p2ptest.NewTestP2P(t)
    30  	p2 := p2ptest.NewTestP2P(t)
    31  	p1.Connect(p2)
    32  	assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected")
    33  	d := db.SetupDB(t)
    34  
    35  	var blkRoots p2pTypes.BeaconBlockByRootsReq
    36  	// Populate the database with blocks that would match the request.
    37  	for i := types.Slot(1); i < 11; i++ {
    38  		blk := testutil.NewBeaconBlock()
    39  		blk.Block.Slot = i
    40  		root, err := blk.Block.HashTreeRoot()
    41  		require.NoError(t, err)
    42  		require.NoError(t, d.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(blk)))
    43  		blkRoots = append(blkRoots, root)
    44  	}
    45  
    46  	r := &Service{cfg: &Config{P2P: p1, DB: d}, rateLimiter: newRateLimiter(p1)}
    47  	pcl := protocol.ID(p2p.RPCBlocksByRootTopicV1)
    48  	topic := string(pcl)
    49  	r.rateLimiter.limiterMap[topic] = leakybucket.NewCollector(10000, 10000, false)
    50  
    51  	var wg sync.WaitGroup
    52  	wg.Add(1)
    53  	p2.BHost.SetStreamHandler(pcl, func(stream network.Stream) {
    54  		defer wg.Done()
    55  		for i := range blkRoots {
    56  			expectSuccess(t, stream)
    57  			res := testutil.NewBeaconBlock()
    58  			assert.NoError(t, r.cfg.P2P.Encoding().DecodeWithMaxLength(stream, res))
    59  			if uint64(res.Block.Slot) != uint64(i+1) {
    60  				t.Errorf("Received unexpected block slot %d but wanted %d", res.Block.Slot, i+1)
    61  			}
    62  		}
    63  	})
    64  
    65  	stream1, err := p1.BHost.NewStream(context.Background(), p2.BHost.ID(), pcl)
    66  	require.NoError(t, err)
    67  	err = r.beaconBlocksRootRPCHandler(context.Background(), &blkRoots, stream1)
    68  	assert.NoError(t, err)
    69  
    70  	if testutil.WaitTimeout(&wg, 1*time.Second) {
    71  		t.Fatal("Did not receive stream within 1 sec")
    72  	}
    73  }
    74  
    75  func TestRecentBeaconBlocks_RPCRequestSent(t *testing.T) {
    76  	p1 := p2ptest.NewTestP2P(t)
    77  	p2 := p2ptest.NewTestP2P(t)
    78  	p1.DelaySend = true
    79  
    80  	blockA := testutil.NewBeaconBlock()
    81  	blockA.Block.Slot = 111
    82  	blockB := testutil.NewBeaconBlock()
    83  	blockB.Block.Slot = 40
    84  	// Set up a head state with data we expect.
    85  	blockARoot, err := blockA.Block.HashTreeRoot()
    86  	require.NoError(t, err)
    87  	blockBRoot, err := blockB.Block.HashTreeRoot()
    88  	require.NoError(t, err)
    89  	genesisState, err := state.GenesisBeaconState(context.Background(), nil, 0, &ethpb.Eth1Data{})
    90  	require.NoError(t, err)
    91  	require.NoError(t, genesisState.SetSlot(111))
    92  	require.NoError(t, genesisState.UpdateBlockRootAtIndex(111%uint64(params.BeaconConfig().SlotsPerHistoricalRoot), blockARoot))
    93  	finalizedCheckpt := &ethpb.Checkpoint{
    94  		Epoch: 5,
    95  		Root:  blockBRoot[:],
    96  	}
    97  
    98  	expectedRoots := p2pTypes.BeaconBlockByRootsReq{blockBRoot, blockARoot}
    99  
   100  	r := &Service{
   101  		cfg: &Config{
   102  			P2P: p1,
   103  			Chain: &mock.ChainService{
   104  				State:               genesisState,
   105  				FinalizedCheckPoint: finalizedCheckpt,
   106  				Root:                blockARoot[:],
   107  			},
   108  		},
   109  		slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
   110  		seenPendingBlocks:   make(map[[32]byte]bool),
   111  		ctx:                 context.Background(),
   112  		rateLimiter:         newRateLimiter(p1),
   113  	}
   114  
   115  	// Setup streams
   116  	pcl := protocol.ID("/eth2/beacon_chain/req/beacon_blocks_by_root/1/ssz_snappy")
   117  	topic := string(pcl)
   118  	r.rateLimiter.limiterMap[topic] = leakybucket.NewCollector(10000, 10000, false)
   119  
   120  	var wg sync.WaitGroup
   121  	wg.Add(1)
   122  	p2.BHost.SetStreamHandler(pcl, func(stream network.Stream) {
   123  		defer wg.Done()
   124  		out := new(p2pTypes.BeaconBlockByRootsReq)
   125  		assert.NoError(t, p2.Encoding().DecodeWithMaxLength(stream, out))
   126  		assert.DeepEqual(t, &expectedRoots, out, "Did not receive expected message")
   127  		response := []*ethpb.SignedBeaconBlock{blockB, blockA}
   128  		for _, blk := range response {
   129  			_, err := stream.Write([]byte{responseCodeSuccess})
   130  			assert.NoError(t, err, "Could not write to stream")
   131  			_, err = p2.Encoding().EncodeWithMaxLength(stream, blk)
   132  			assert.NoError(t, err, "Could not send response back")
   133  		}
   134  		assert.NoError(t, stream.Close())
   135  	})
   136  
   137  	p1.Connect(p2)
   138  	require.NoError(t, r.sendRecentBeaconBlocksRequest(context.Background(), &expectedRoots, p2.PeerID()))
   139  
   140  	if testutil.WaitTimeout(&wg, 1*time.Second) {
   141  		t.Fatal("Did not receive stream within 1 sec")
   142  	}
   143  }
   144  
   145  func TestRecentBeaconBlocksRPCHandler_HandleZeroBlocks(t *testing.T) {
   146  	p1 := p2ptest.NewTestP2P(t)
   147  	p2 := p2ptest.NewTestP2P(t)
   148  	p1.Connect(p2)
   149  	assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected")
   150  	d := db.SetupDB(t)
   151  
   152  	r := &Service{cfg: &Config{P2P: p1, DB: d}, rateLimiter: newRateLimiter(p1)}
   153  	pcl := protocol.ID(p2p.RPCBlocksByRootTopicV1)
   154  	topic := string(pcl)
   155  	r.rateLimiter.limiterMap[topic] = leakybucket.NewCollector(1, 1, false)
   156  
   157  	var wg sync.WaitGroup
   158  	wg.Add(1)
   159  	p2.BHost.SetStreamHandler(pcl, func(stream network.Stream) {
   160  		defer wg.Done()
   161  		expectFailure(t, 1, "no block roots provided in request", stream)
   162  	})
   163  
   164  	stream1, err := p1.BHost.NewStream(context.Background(), p2.BHost.ID(), pcl)
   165  	require.NoError(t, err)
   166  	err = r.beaconBlocksRootRPCHandler(context.Background(), &p2pTypes.BeaconBlockByRootsReq{}, stream1)
   167  	assert.ErrorContains(t, "no block roots provided", err)
   168  	if testutil.WaitTimeout(&wg, 1*time.Second) {
   169  		t.Fatal("Did not receive stream within 1 sec")
   170  	}
   171  
   172  	r.rateLimiter.RLock() // retrieveCollector requires a lock to be held.
   173  	defer r.rateLimiter.RUnlock()
   174  	lter, err := r.rateLimiter.retrieveCollector(topic)
   175  	require.NoError(t, err)
   176  	assert.Equal(t, 1, int(lter.Count(stream1.Conn().RemotePeer().String())))
   177  }