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 }