// This file is part of Substrate. // Copyright (C) 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 crate::role::Roles; use bitflags::bitflags; use codec::{Decode, Encode, Error, Input, Output}; pub use generic::{BlockAnnounce, FromBlock}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; /// 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>; // 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; /// Include indexed transactions for a block. const INDEXED_BODY = 0b00100000; } } 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 { Self::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, } /// Announcement summary used for debug logging. #[derive(Debug)] pub struct AnnouncementSummary { pub block_hash: H::Hash, pub number: H::Number, pub parent_hash: H::Hash, pub state: Option, } impl BlockAnnounce { pub fn summary(&self) -> AnnouncementSummary { AnnouncementSummary { block_hash: self.header.hash(), number: *self.header.number(), parent_hash: *self.header.parent_hash(), state: self.state, } } } /// Generic types. pub mod generic { use super::{BlockAttributes, BlockState, Direction}; use crate::message::RequestId; use codec::{Decode, Encode, Input, Output}; use sp_runtime::{EncodedJustification, Justifications}; /// 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 body indexed transactions if requested. pub indexed_body: Option>>, /// Block receipt if requested. pub receipt: Option>, /// Block message queue if requested. pub message_queue: Option>, /// Justification if requested. pub justification: Option, /// Justifications if requested. pub justifications: Option, } /// 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, /// Sequence direction. pub direction: Direction, /// Maximum number of blocks to return. An implementation defined maximum is used when /// unspecified. pub max: 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), } /// 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 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(Self { header, state, data }) } } } /// Handshake sent when we open a block announces substream. #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] pub struct BlockAnnouncesHandshake { /// Roles of the node. pub roles: Roles, /// Best block number. pub best_number: NumberFor, /// Best block hash. pub best_hash: B::Hash, /// Genesis block hash. pub genesis_hash: B::Hash, } impl BlockAnnouncesHandshake { pub fn build( roles: Roles, best_number: NumberFor, best_hash: B::Hash, genesis_hash: B::Hash, ) -> Self { Self { genesis_hash, roles, best_number, best_hash } } }