github.com/amazechain/amc@v0.1.3/internal/sync/rpc_chunked_response.go (about) 1 package sync 2 3 import ( 4 "fmt" 5 "github.com/amazechain/amc/api/protocol/types_pb" 6 "github.com/amazechain/amc/common" 7 types "github.com/amazechain/amc/common/block" 8 "github.com/amazechain/amc/internal/p2p" 9 "github.com/amazechain/amc/internal/p2p/encoder" 10 "github.com/amazechain/amc/utils" 11 libp2pcore "github.com/libp2p/go-libp2p/core" 12 "github.com/pkg/errors" 13 ) 14 15 // chunkBlockWriter writes the given message as a chunked response to the given network 16 // stream. 17 // response_chunk ::= <result> | <context-bytes> | <encoding-dependent-header> | <encoded-payload> 18 func (s *Service) chunkBlockWriter(stream libp2pcore.Stream, blk types.IBlock) error { 19 SetStreamWriteDeadline(stream, defaultWriteDuration) 20 return WriteBlockChunk(stream, s.cfg.chain, s.cfg.p2p.Encoding(), blk) 21 } 22 23 // WriteBlockChunk writes block chunk object to stream. 24 // response_chunk ::= <result> | <context-bytes> | <encoding-dependent-header> | <encoded-payload> 25 func WriteBlockChunk(stream libp2pcore.Stream, chain common.IBlockChain, encoding encoder.NetworkEncoding, blk types.IBlock) error { 26 if _, err := stream.Write([]byte{responseCodeSuccess}); err != nil { 27 return err 28 } 29 30 digest, err := utils.CreateForkDigest(blk.Number64(), chain.GenesisBlock().Hash()) 31 if err != nil { 32 return err 33 } 34 35 if err = writeContextToStream(digest[:], stream, chain); err != nil { 36 return err 37 } 38 protoMsg := blk.ToProtoMessage() 39 _, err = encoding.EncodeWithMaxLength(stream, protoMsg.(*types_pb.Block)) 40 return err 41 } 42 43 // ReadChunkedBlock handles each response chunk that is sent by the 44 // peer and converts it into a beacon block. 45 func ReadChunkedBlock(stream libp2pcore.Stream, p2p p2p.EncodingProvider, isFirstChunk bool) (*types_pb.Block, error) { 46 // Handle deadlines differently for first chunk 47 if isFirstChunk { 48 return readFirstChunkedBlock(stream, p2p) 49 } 50 51 return readResponseChunk(stream, p2p) 52 } 53 54 // readFirstChunkedBlock reads the first chunked block and applies the appropriate deadlines to 55 // it. 56 func readFirstChunkedBlock(stream libp2pcore.Stream, p2p p2p.EncodingProvider) (*types_pb.Block, error) { 57 code, errMsg, err := ReadStatusCode(stream, p2p.Encoding()) 58 if err != nil { 59 return nil, err 60 } 61 if code != 0 { 62 return nil, fmt.Errorf("%s", errMsg) 63 } 64 _, err = readContextFromStream(stream) 65 if err != nil { 66 return nil, err 67 } 68 blk := &types_pb.Block{} 69 err = p2p.Encoding().DecodeWithMaxLength(stream, blk) 70 return blk, err 71 } 72 73 // readResponseChunk reads the response from the stream and decodes it into the 74 // provided message type. 75 func readResponseChunk(stream libp2pcore.Stream, p2p p2p.EncodingProvider) (*types_pb.Block, error) { 76 SetStreamReadDeadline(stream, respTimeout) 77 code, errMsg, err := readStatusCodeNoDeadline(stream, p2p.Encoding()) 78 if err != nil { 79 return nil, err 80 } 81 if code != 0 { 82 return nil, errors.New(errMsg) 83 } 84 // No-op for now with the rpc context. todo 85 _, err = readContextFromStream(stream) 86 if err != nil { 87 return nil, err 88 } 89 90 blk := &types_pb.Block{} 91 err = p2p.Encoding().DecodeWithMaxLength(stream, blk) 92 return blk, err 93 }