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

     1  package sync
     2  
     3  import (
     4  	"context"
     5  	"io"
     6  
     7  	"github.com/libp2p/go-libp2p-core/peer"
     8  	"github.com/pkg/errors"
     9  	types "github.com/prysmaticlabs/eth2-types"
    10  	"github.com/prysmaticlabs/prysm/beacon-chain/blockchain"
    11  	"github.com/prysmaticlabs/prysm/beacon-chain/p2p"
    12  	p2ptypes "github.com/prysmaticlabs/prysm/beacon-chain/p2p/types"
    13  	pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
    14  	"github.com/prysmaticlabs/prysm/proto/interfaces"
    15  	"github.com/prysmaticlabs/prysm/shared/params"
    16  )
    17  
    18  // ErrInvalidFetchedData is thrown if stream fails to provide requested blocks.
    19  var ErrInvalidFetchedData = errors.New("invalid data returned from peer")
    20  
    21  // BeaconBlockProcessor defines a block processing function, which allows to start utilizing
    22  // blocks even before all blocks are ready.
    23  type BeaconBlockProcessor func(block interfaces.SignedBeaconBlock) error
    24  
    25  // SendBeaconBlocksByRangeRequest sends BeaconBlocksByRange and returns fetched blocks, if any.
    26  func SendBeaconBlocksByRangeRequest(
    27  	ctx context.Context, chain blockchain.ChainInfoFetcher, p2pProvider p2p.P2P, pid peer.ID,
    28  	req *pb.BeaconBlocksByRangeRequest, blockProcessor BeaconBlockProcessor,
    29  ) ([]interfaces.SignedBeaconBlock, error) {
    30  	stream, err := p2pProvider.Send(ctx, req, p2p.RPCBlocksByRangeTopicV1, pid)
    31  	if err != nil {
    32  		return nil, err
    33  	}
    34  	defer closeStream(stream, log)
    35  
    36  	// Augment block processing function, if non-nil block processor is provided.
    37  	blocks := make([]interfaces.SignedBeaconBlock, 0, req.Count)
    38  	process := func(blk interfaces.SignedBeaconBlock) error {
    39  		blocks = append(blocks, blk)
    40  		if blockProcessor != nil {
    41  			return blockProcessor(blk)
    42  		}
    43  		return nil
    44  	}
    45  	var prevSlot types.Slot
    46  	for i := uint64(0); ; i++ {
    47  		isFirstChunk := i == 0
    48  		blk, err := ReadChunkedBlock(stream, chain, p2pProvider, isFirstChunk)
    49  		if errors.Is(err, io.EOF) {
    50  			break
    51  		}
    52  		if err != nil {
    53  			return nil, err
    54  		}
    55  		// The response MUST contain no more than `count` blocks, and no more than
    56  		// MAX_REQUEST_BLOCKS blocks.
    57  		if i >= req.Count || i >= params.BeaconNetworkConfig().MaxRequestBlocks {
    58  			return nil, ErrInvalidFetchedData
    59  		}
    60  		// Returned blocks MUST be in the slot range [start_slot, start_slot + count * step).
    61  		if blk.Block().Slot() < req.StartSlot || blk.Block().Slot() >= req.StartSlot.Add(req.Count*req.Step) {
    62  			return nil, ErrInvalidFetchedData
    63  		}
    64  		// Returned blocks, where they exist, MUST be sent in a consecutive order.
    65  		// Consecutive blocks MUST have values in `step` increments (slots may be skipped in between).
    66  		isSlotOutOfOrder := false
    67  		if prevSlot >= blk.Block().Slot() {
    68  			isSlotOutOfOrder = true
    69  		} else if req.Step != 0 && blk.Block().Slot().SubSlot(prevSlot).Mod(req.Step) != 0 {
    70  			isSlotOutOfOrder = true
    71  		}
    72  		if !isFirstChunk && isSlotOutOfOrder {
    73  			return nil, ErrInvalidFetchedData
    74  		}
    75  		prevSlot = blk.Block().Slot()
    76  		if err := process(blk); err != nil {
    77  			return nil, err
    78  		}
    79  	}
    80  	return blocks, nil
    81  }
    82  
    83  // SendBeaconBlocksByRootRequest sends BeaconBlocksByRoot and returns fetched blocks, if any.
    84  func SendBeaconBlocksByRootRequest(
    85  	ctx context.Context, chain blockchain.ChainInfoFetcher, p2pProvider p2p.P2P, pid peer.ID,
    86  	req *p2ptypes.BeaconBlockByRootsReq, blockProcessor BeaconBlockProcessor,
    87  ) ([]interfaces.SignedBeaconBlock, error) {
    88  	stream, err := p2pProvider.Send(ctx, req, p2p.RPCBlocksByRootTopicV1, pid)
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  	defer closeStream(stream, log)
    93  
    94  	// Augment block processing function, if non-nil block processor is provided.
    95  	blocks := make([]interfaces.SignedBeaconBlock, 0, len(*req))
    96  	process := func(block interfaces.SignedBeaconBlock) error {
    97  		blocks = append(blocks, block)
    98  		if blockProcessor != nil {
    99  			return blockProcessor(block)
   100  		}
   101  		return nil
   102  	}
   103  	for i := 0; i < len(*req); i++ {
   104  		// Exit if peer sends more than max request blocks.
   105  		if uint64(i) >= params.BeaconNetworkConfig().MaxRequestBlocks {
   106  			break
   107  		}
   108  		isFirstChunk := i == 0
   109  		blk, err := ReadChunkedBlock(stream, chain, p2pProvider, isFirstChunk)
   110  		if errors.Is(err, io.EOF) {
   111  			break
   112  		}
   113  		if err != nil {
   114  			return nil, err
   115  		}
   116  
   117  		if err := process(blk); err != nil {
   118  			return nil, err
   119  		}
   120  	}
   121  	return blocks, nil
   122  }