// This file is part of Substrate. // Copyright (C) 2017-2020 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see . //! Network packet message types. These get serialized and put into the lower level protocol payload. use bitflags::bitflags; use sp_runtime::{ConsensusEngineId, traits::{Block as BlockT, Header as HeaderT}}; use codec::{Encode, Decode, Input, Output, Error}; pub use self::generic::{ BlockAnnounce, RemoteCallRequest, RemoteReadRequest, RemoteHeaderRequest, RemoteHeaderResponse, RemoteChangesRequest, RemoteChangesResponse, FinalityProofRequest, FinalityProofResponse, FromBlock, RemoteReadChildRequest, Roles, }; use sc_client_api::StorageProof; /// A unique ID of a request. pub type RequestId = u64; /// Type alias for using the message type using block type parameters. pub type Message = generic::Message< ::Header, ::Hash, <::Header as HeaderT>::Number, ::Extrinsic, >; /// Type alias for using the status type using block type parameters. pub type Status = generic::Status< ::Hash, <::Header as HeaderT>::Number, >; /// Type alias for using the block request type using block type parameters. pub type BlockRequest = generic::BlockRequest< ::Hash, <::Header as HeaderT>::Number, >; /// Type alias for using the BlockData type using block type parameters. pub type BlockData = generic::BlockData< ::Header, ::Hash, ::Extrinsic, >; /// Type alias for using the BlockResponse type using block type parameters. pub type BlockResponse = generic::BlockResponse< ::Header, ::Hash, ::Extrinsic, >; /// A set of transactions. pub type Transactions = Vec; // Bits of block data and associated artifacts to request. bitflags! { /// Node roles bitmask. pub struct BlockAttributes: u8 { /// Include block header. const HEADER = 0b00000001; /// Include block body. const BODY = 0b00000010; /// Include block receipt. const RECEIPT = 0b00000100; /// Include block message queue. const MESSAGE_QUEUE = 0b00001000; /// Include a justification for the block. const JUSTIFICATION = 0b00010000; } } impl BlockAttributes { /// Encodes attributes as big endian u32, compatible with SCALE-encoding (i.e the /// significant byte has zero index). pub fn to_be_u32(&self) -> u32 { u32::from_be_bytes([self.bits(), 0, 0, 0]) } /// Decodes attributes, encoded with the `encode_to_be_u32()` call. pub fn from_be_u32(encoded: u32) -> Result { BlockAttributes::from_bits(encoded.to_be_bytes()[0]) .ok_or_else(|| Error::from("Invalid BlockAttributes")) } } impl Encode for BlockAttributes { fn encode_to(&self, dest: &mut T) { dest.push_byte(self.bits()) } } impl codec::EncodeLike for BlockAttributes {} impl Decode for BlockAttributes { fn decode(input: &mut I) -> Result { Self::from_bits(input.read_byte()?).ok_or_else(|| Error::from("Invalid bytes")) } } #[derive(Debug, PartialEq, Eq, Clone, Copy, Encode, Decode)] /// Block enumeration direction. pub enum Direction { /// Enumerate in ascending order (from child to parent). Ascending = 0, /// Enumerate in descending order (from parent to canonical child). Descending = 1, } /// Block state in the chain. #[derive(Debug, PartialEq, Eq, Clone, Copy, Encode, Decode)] pub enum BlockState { /// Block is not part of the best chain. Normal, /// Latest best block. Best, } /// Remote call response. #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] pub struct RemoteCallResponse { /// Id of a request this response was made for. pub id: RequestId, /// Execution proof. pub proof: StorageProof, } #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] /// Remote read response. pub struct RemoteReadResponse { /// Id of a request this response was made for. pub id: RequestId, /// Read proof. pub proof: StorageProof, } /// Generic types. pub mod generic { use bitflags::bitflags; use codec::{Encode, Decode, Input, Output}; use sp_runtime::Justification; use super::{ RemoteReadResponse, Transactions, Direction, RequestId, BlockAttributes, RemoteCallResponse, ConsensusEngineId, BlockState, StorageProof, }; bitflags! { /// Bitmask of the roles that a node fulfills. pub struct Roles: u8 { /// No network. const NONE = 0b00000000; /// Full node, does not participate in consensus. const FULL = 0b00000001; /// Light client node. const LIGHT = 0b00000010; /// Act as an authority const AUTHORITY = 0b00000100; } } impl Roles { /// Does this role represents a client that holds full chain data locally? pub fn is_full(&self) -> bool { self.intersects(Roles::FULL | Roles::AUTHORITY) } /// Does this role represents a client that does not participates in the consensus? pub fn is_authority(&self) -> bool { *self == Roles::AUTHORITY } /// Does this role represents a client that does not hold full chain data locally? pub fn is_light(&self) -> bool { !self.is_full() } } impl<'a> From<&'a crate::config::Role> for Roles { fn from(roles: &'a crate::config::Role) -> Self { match roles { crate::config::Role::Full => Roles::FULL, crate::config::Role::Light => Roles::LIGHT, crate::config::Role::Sentry { .. } => Roles::AUTHORITY, crate::config::Role::Authority { .. } => Roles::AUTHORITY, } } } impl codec::Encode for Roles { fn encode_to(&self, dest: &mut T) { dest.push_byte(self.bits()) } } impl codec::EncodeLike for Roles {} impl codec::Decode for Roles { fn decode(input: &mut I) -> Result { Self::from_bits(input.read_byte()?).ok_or_else(|| codec::Error::from("Invalid bytes")) } } /// Consensus is mostly opaque to us #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] pub struct ConsensusMessage { /// Identifies consensus engine. pub engine_id: ConsensusEngineId, /// Message payload. pub data: Vec, } /// Block data sent in the response. #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] pub struct BlockData { /// Block header hash. pub hash: Hash, /// Block header if requested. pub header: Option
, /// Block body if requested. pub body: Option>, /// Block receipt if requested. pub receipt: Option>, /// Block message queue if requested. pub message_queue: Option>, /// Justification if requested. pub justification: Option, } /// Identifies starting point of a block sequence. #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] pub enum FromBlock { /// Start with given hash. Hash(Hash), /// Start with given block number. Number(Number), } /// A network message. #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] pub enum Message { /// Status packet. Status(Status), /// Block request. BlockRequest(BlockRequest), /// Block response. BlockResponse(BlockResponse), /// Block announce. BlockAnnounce(BlockAnnounce
), /// Transactions. Transactions(Transactions), /// Consensus protocol message. Consensus(ConsensusMessage), /// Remote method call request. RemoteCallRequest(RemoteCallRequest), /// Remote method call response. RemoteCallResponse(RemoteCallResponse), /// Remote storage read request. RemoteReadRequest(RemoteReadRequest), /// Remote storage read response. RemoteReadResponse(RemoteReadResponse), /// Remote header request. RemoteHeaderRequest(RemoteHeaderRequest), /// Remote header response. RemoteHeaderResponse(RemoteHeaderResponse
), /// Remote changes request. RemoteChangesRequest(RemoteChangesRequest), /// Remote changes response. RemoteChangesResponse(RemoteChangesResponse), /// Remote child storage read request. RemoteReadChildRequest(RemoteReadChildRequest), /// Finality proof request. FinalityProofRequest(FinalityProofRequest), /// Finality proof response. FinalityProofResponse(FinalityProofResponse), /// Batch of consensus protocol messages. ConsensusBatch(Vec), } impl Message { /// Message id useful for logging. pub fn id(&self) -> &'static str { match self { Message::Status(_) => "Status", Message::BlockRequest(_) => "BlockRequest", Message::BlockResponse(_) => "BlockResponse", Message::BlockAnnounce(_) => "BlockAnnounce", Message::Transactions(_) => "Transactions", Message::Consensus(_) => "Consensus", Message::RemoteCallRequest(_) => "RemoteCallRequest", Message::RemoteCallResponse(_) => "RemoteCallResponse", Message::RemoteReadRequest(_) => "RemoteReadRequest", Message::RemoteReadResponse(_) => "RemoteReadResponse", Message::RemoteHeaderRequest(_) => "RemoteHeaderRequest", Message::RemoteHeaderResponse(_) => "RemoteHeaderResponse", Message::RemoteChangesRequest(_) => "RemoteChangesRequest", Message::RemoteChangesResponse(_) => "RemoteChangesResponse", Message::RemoteReadChildRequest(_) => "RemoteReadChildRequest", Message::FinalityProofRequest(_) => "FinalityProofRequest", Message::FinalityProofResponse(_) => "FinalityProofResponse", Message::ConsensusBatch(_) => "ConsensusBatch", } } } /// Status sent on connection. // TODO https://github.com/paritytech/substrate/issues/4674: replace the `Status` // struct with this one, after waiting a few releases beyond `NetworkSpecialization`'s // removal (https://github.com/paritytech/substrate/pull/4665) // // and set MIN_VERSION to 6. #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] pub struct CompactStatus { /// Protocol version. pub version: u32, /// Minimum supported version. pub min_supported_version: u32, /// Supported roles. pub roles: Roles, /// Best block number. pub best_number: Number, /// Best block hash. pub best_hash: Hash, /// Genesis block hash. pub genesis_hash: Hash, } /// Status sent on connection. #[derive(Debug, PartialEq, Eq, Clone, Encode)] pub struct Status { /// Protocol version. pub version: u32, /// Minimum supported version. pub min_supported_version: u32, /// Supported roles. pub roles: Roles, /// Best block number. pub best_number: Number, /// Best block hash. pub best_hash: Hash, /// Genesis block hash. pub genesis_hash: Hash, /// DEPRECATED. Chain-specific status. pub chain_status: Vec, } impl Decode for Status { fn decode(value: &mut I) -> Result { const LAST_CHAIN_STATUS_VERSION: u32 = 5; let compact = CompactStatus::decode(value)?; let chain_status = match >::decode(value) { Ok(v) => v, Err(e) => if compact.version <= LAST_CHAIN_STATUS_VERSION { return Err(e) } else { Vec::new() } }; let CompactStatus { version, min_supported_version, roles, best_number, best_hash, genesis_hash, } = compact; Ok(Status { version, min_supported_version, roles, best_number, best_hash, genesis_hash, chain_status, }) } } /// Request block data from a peer. #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] pub struct BlockRequest { /// Unique request id. pub id: RequestId, /// Bits of block data to request. pub fields: BlockAttributes, /// Start from this block. pub from: FromBlock, /// End at this block. An implementation defined maximum is used when unspecified. pub to: Option, /// Sequence direction. pub direction: Direction, /// Maximum number of blocks to return. An implementation defined maximum is used when unspecified. pub max: Option, } /// Response to `BlockRequest` #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] pub struct BlockResponse { /// Id of a request this response was made for. pub id: RequestId, /// Block data for the requested sequence. pub blocks: Vec>, } /// Announce a new complete relay chain block on the network. #[derive(Debug, PartialEq, Eq, Clone)] pub struct BlockAnnounce { /// New block header. pub header: H, /// Block state. TODO: Remove `Option` and custom encoding when v4 becomes common. pub state: Option, /// Data associated with this block announcement, e.g. a candidate message. pub data: Option>, } // Custom Encode/Decode impl to maintain backwards compatibility with v3. // This assumes that the packet contains nothing but the announcement message. // TODO: Get rid of it once protocol v4 is common. impl Encode for BlockAnnounce { fn encode_to(&self, dest: &mut T) { self.header.encode_to(dest); if let Some(state) = &self.state { state.encode_to(dest); } if let Some(data) = &self.data { data.encode_to(dest) } } } impl Decode for BlockAnnounce { fn decode(input: &mut I) -> Result { let header = H::decode(input)?; let state = BlockState::decode(input).ok(); let data = Vec::decode(input).ok(); Ok(BlockAnnounce { header, state, data, }) } } #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] /// Remote call request. pub struct RemoteCallRequest { /// Unique request id. pub id: RequestId, /// Block at which to perform call. pub block: H, /// Method name. pub method: String, /// Call data. pub data: Vec, } #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] /// Remote storage read request. pub struct RemoteReadRequest { /// Unique request id. pub id: RequestId, /// Block at which to perform call. pub block: H, /// Storage key. pub keys: Vec>, } #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] /// Remote storage read child request. pub struct RemoteReadChildRequest { /// Unique request id. pub id: RequestId, /// Block at which to perform call. pub block: H, /// Child Storage key. pub storage_key: Vec, /// Storage key. pub keys: Vec>, } #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] /// Remote header request. pub struct RemoteHeaderRequest { /// Unique request id. pub id: RequestId, /// Block number to request header for. pub block: N, } #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] /// Remote header response. pub struct RemoteHeaderResponse
{ /// Id of a request this response was made for. pub id: RequestId, /// Header. None if proof generation has failed (e.g. header is unknown). pub header: Option
, /// Header proof. pub proof: StorageProof, } #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] /// Remote changes request. pub struct RemoteChangesRequest { /// Unique request id. pub id: RequestId, /// Hash of the first block of the range (including first) where changes are requested. pub first: H, /// Hash of the last block of the range (including last) where changes are requested. pub last: H, /// Hash of the first block for which the requester has the changes trie root. All other /// affected roots must be proved. pub min: H, /// Hash of the last block that we can use when querying changes. pub max: H, /// Storage child node key which changes are requested. pub storage_key: Option>, /// Storage key which changes are requested. pub key: Vec, } #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] /// Remote changes response. pub struct RemoteChangesResponse { /// Id of a request this response was made for. pub id: RequestId, /// Proof has been generated using block with this number as a max block. Should be /// less than or equal to the RemoteChangesRequest::max block number. pub max: N, /// Changes proof. pub proof: Vec>, /// Changes tries roots missing on the requester' node. pub roots: Vec<(N, H)>, /// Missing changes tries roots proof. pub roots_proof: StorageProof, } #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] /// Finality proof request. pub struct FinalityProofRequest { /// Unique request id. pub id: RequestId, /// Hash of the block to request proof for. pub block: H, /// Additional data blob (that both requester and provider understood) required for proving finality. pub request: Vec, } #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] /// Finality proof response. pub struct FinalityProofResponse { /// Id of a request this response was made for. pub id: RequestId, /// Hash of the block (the same as in the FinalityProofRequest). pub block: H, /// Finality proof (if available). pub proof: Option>, } }