2019-09-24 14:56:50 +00:00
package sync
import (
2022-10-07 07:24:51 +00:00
libp2pcore "github.com/libp2p/go-libp2p/core"
2021-09-03 16:00:56 +00:00
"github.com/pkg/errors"
2024-02-15 05:46:47 +00:00
"github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/signing"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p/encoder"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p/types"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/network/forks"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/time/slots"
2019-09-24 14:56:50 +00:00
)
2021-09-03 16:00:56 +00:00
// chunkBlockWriter writes the given message as a chunked response to the given network
2019-09-24 14:56:50 +00:00
// stream.
2021-05-17 19:25:59 +00:00
// response_chunk ::= <result> | <context-bytes> | <encoding-dependent-header> | <encoded-payload>
2023-02-09 09:23:32 +00:00
func ( s * Service ) chunkBlockWriter ( stream libp2pcore . Stream , blk interfaces . ReadOnlySignedBeaconBlock ) error {
2020-06-25 22:36:18 +00:00
SetStreamWriteDeadline ( stream , defaultWriteDuration )
2023-05-03 04:34:01 +00:00
return WriteBlockChunk ( stream , s . cfg . clock , s . cfg . p2p . Encoding ( ) , blk )
2019-09-25 17:00:04 +00:00
}
2021-09-24 17:42:16 +00:00
// WriteBlockChunk writes block chunk object to stream.
2021-05-17 19:25:59 +00:00
// response_chunk ::= <result> | <context-bytes> | <encoding-dependent-header> | <encoded-payload>
2023-05-03 04:34:01 +00:00
func WriteBlockChunk ( stream libp2pcore . Stream , tor blockchain . TemporalOracle , encoding encoder . NetworkEncoding , blk interfaces . ReadOnlySignedBeaconBlock ) error {
2019-09-24 14:56:50 +00:00
if _ , err := stream . Write ( [ ] byte { responseCodeSuccess } ) ; err != nil {
return err
}
2021-09-24 17:42:16 +00:00
var obtainedCtx [ ] byte
2022-07-13 17:18:30 +00:00
2023-05-03 04:34:01 +00:00
valRoot := tor . GenesisValidatorsRoot ( )
2021-09-03 16:00:56 +00:00
switch blk . Version ( ) {
case version . Phase0 :
2021-09-17 19:20:50 +00:00
digest , err := forks . ForkDigestFromEpoch ( params . BeaconConfig ( ) . GenesisEpoch , valRoot [ : ] )
2021-09-03 16:00:56 +00:00
if err != nil {
return err
}
obtainedCtx = digest [ : ]
case version . Altair :
2021-09-17 19:20:50 +00:00
digest , err := forks . ForkDigestFromEpoch ( params . BeaconConfig ( ) . AltairForkEpoch , valRoot [ : ] )
2021-09-03 16:00:56 +00:00
if err != nil {
return err
}
obtainedCtx = digest [ : ]
2022-08-10 22:00:10 +00:00
case version . Bellatrix :
2022-01-28 16:26:52 +00:00
digest , err := forks . ForkDigestFromEpoch ( params . BeaconConfig ( ) . BellatrixForkEpoch , valRoot [ : ] )
if err != nil {
return err
}
obtainedCtx = digest [ : ]
2023-05-03 04:34:01 +00:00
case version . Capella :
digest , err := forks . ForkDigestFromEpoch ( params . BeaconConfig ( ) . CapellaForkEpoch , valRoot [ : ] )
if err != nil {
return err
}
obtainedCtx = digest [ : ]
2023-07-10 19:02:44 +00:00
case version . Deneb :
digest , err := forks . ForkDigestFromEpoch ( params . BeaconConfig ( ) . DenebForkEpoch , valRoot [ : ] )
if err != nil {
return err
}
obtainedCtx = digest [ : ]
2023-05-03 04:34:01 +00:00
default :
return errors . Wrapf ( ErrUnrecognizedVersion , "block version %d is not recognized" , blk . Version ( ) )
2021-09-03 16:00:56 +00:00
}
2023-05-03 04:34:01 +00:00
if err := writeContextToStream ( obtainedCtx , stream ) ; err != nil {
2021-05-17 19:25:59 +00:00
return err
}
2021-09-03 16:00:56 +00:00
_ , err := encoding . EncodeWithMaxLength ( stream , blk )
2019-09-24 14:56:50 +00:00
return err
}
// ReadChunkedBlock handles each response chunk that is sent by the
// peer and converts it into a beacon block.
2023-05-03 04:34:01 +00:00
func ReadChunkedBlock ( stream libp2pcore . Stream , tor blockchain . TemporalOracle , p2p p2p . EncodingProvider , isFirstChunk bool ) ( interfaces . ReadOnlySignedBeaconBlock , error ) {
2020-07-13 19:40:12 +00:00
// Handle deadlines differently for first chunk
if isFirstChunk {
2023-05-03 04:34:01 +00:00
return readFirstChunkedBlock ( stream , tor , p2p )
2020-07-13 19:40:12 +00:00
}
2021-09-03 16:00:56 +00:00
2023-05-03 04:34:01 +00:00
return readResponseChunk ( stream , tor , p2p )
2019-09-24 14:56:50 +00:00
}
2020-07-13 19:40:12 +00:00
// readFirstChunkedBlock reads the first chunked block and applies the appropriate deadlines to
// it.
2023-05-03 04:34:01 +00:00
func readFirstChunkedBlock ( stream libp2pcore . Stream , tor blockchain . TemporalOracle , p2p p2p . EncodingProvider ) ( interfaces . ReadOnlySignedBeaconBlock , error ) {
2020-07-13 19:40:12 +00:00
code , errMsg , err := ReadStatusCode ( stream , p2p . Encoding ( ) )
if err != nil {
return nil , err
}
if code != 0 {
return nil , errors . New ( errMsg )
}
2023-05-03 04:34:01 +00:00
rpcCtx , err := readContextFromStream ( stream )
2021-09-03 16:00:56 +00:00
if err != nil {
return nil , err
}
2023-05-03 04:34:01 +00:00
blk , err := extractBlockDataType ( rpcCtx , tor )
2021-05-17 19:25:59 +00:00
if err != nil {
return nil , err
}
2020-07-13 19:40:12 +00:00
err = p2p . Encoding ( ) . DecodeWithMaxLength ( stream , blk )
2021-09-03 16:00:56 +00:00
return blk , err
2020-07-13 19:40:12 +00:00
}
2019-09-24 14:56:50 +00:00
// readResponseChunk reads the response from the stream and decodes it into the
// provided message type.
2023-05-03 04:34:01 +00:00
func readResponseChunk ( stream libp2pcore . Stream , tor blockchain . TemporalOracle , p2p p2p . EncodingProvider ) ( interfaces . ReadOnlySignedBeaconBlock , error ) {
2020-07-01 09:47:59 +00:00
SetStreamReadDeadline ( stream , respTimeout )
2020-07-13 19:40:12 +00:00
code , errMsg , err := readStatusCodeNoDeadline ( stream , p2p . Encoding ( ) )
2019-09-24 14:56:50 +00:00
if err != nil {
2021-09-03 16:00:56 +00:00
return nil , err
2019-09-24 14:56:50 +00:00
}
if code != 0 {
2021-09-03 16:00:56 +00:00
return nil , errors . New ( errMsg )
2019-09-24 14:56:50 +00:00
}
2021-05-17 19:25:59 +00:00
// No-op for now with the rpc context.
2023-05-03 04:34:01 +00:00
rpcCtx , err := readContextFromStream ( stream )
2021-05-17 19:25:59 +00:00
if err != nil {
2021-09-03 16:00:56 +00:00
return nil , err
}
2023-05-03 04:34:01 +00:00
blk , err := extractBlockDataType ( rpcCtx , tor )
2021-09-03 16:00:56 +00:00
if err != nil {
return nil , err
}
err = p2p . Encoding ( ) . DecodeWithMaxLength ( stream , blk )
return blk , err
}
2023-05-03 04:34:01 +00:00
func extractBlockDataType ( digest [ ] byte , tor blockchain . TemporalOracle ) ( interfaces . ReadOnlySignedBeaconBlock , error ) {
2021-09-03 16:00:56 +00:00
if len ( digest ) == 0 {
bFunc , ok := types . BlockMap [ bytesutil . ToBytes4 ( params . BeaconConfig ( ) . GenesisForkVersion ) ]
if ! ok {
return nil , errors . New ( "no block type exists for the genesis fork version." )
}
return bFunc ( )
}
if len ( digest ) != forkDigestLength {
return nil , errors . Errorf ( "invalid digest returned, wanted a length of %d but received %d" , forkDigestLength , len ( digest ) )
}
2023-05-03 04:34:01 +00:00
vRoot := tor . GenesisValidatorsRoot ( )
2021-09-03 16:00:56 +00:00
for k , blkFunc := range types . BlockMap {
2021-09-27 16:19:20 +00:00
rDigest , err := signing . ComputeForkDigest ( k [ : ] , vRoot [ : ] )
2021-09-03 16:00:56 +00:00
if err != nil {
return nil , err
}
if rDigest == bytesutil . ToBytes4 ( digest ) {
return blkFunc ( )
}
2021-05-17 19:25:59 +00:00
}
2023-05-03 04:34:01 +00:00
return nil , errors . Wrapf ( ErrNoValidDigest , "could not extract block data type, saw digest=%#x, genesis=%v, vr=%#x" , digest , tor . GenesisTime ( ) , tor . GenesisValidatorsRoot ( ) )
2019-09-24 14:56:50 +00:00
}
2023-06-15 19:38:08 +00:00
// WriteBlobSidecarChunk writes blob chunk object to stream.
// response_chunk ::= <result> | <context-bytes> | <encoding-dependent-header> | <encoded-payload>
2023-11-21 18:44:38 +00:00
func WriteBlobSidecarChunk ( stream libp2pcore . Stream , tor blockchain . TemporalOracle , encoding encoder . NetworkEncoding , sidecar blocks . VerifiedROBlob ) error {
2023-06-15 19:38:08 +00:00
if _ , err := stream . Write ( [ ] byte { responseCodeSuccess } ) ; err != nil {
return err
}
valRoot := tor . GenesisValidatorsRoot ( )
2023-11-21 18:44:38 +00:00
ctxBytes , err := forks . ForkDigestFromEpoch ( slots . ToEpoch ( sidecar . Slot ( ) ) , valRoot [ : ] )
2023-06-15 19:38:08 +00:00
if err != nil {
return err
}
if err := writeContextToStream ( ctxBytes [ : ] , stream ) ; err != nil {
return err
}
_ , err = encoding . EncodeWithMaxLength ( stream , sidecar )
return err
}