Skip to main content

soil_network/common/sync/
message.rs

1// This file is part of Soil.
2
3// Copyright (C) Soil contributors.
4// Copyright (C) Parity Technologies (UK) Ltd.
5// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
6
7//! Network packet message types. These get serialized and put into the lower level protocol
8//! payload.
9
10use crate::common::role::Roles;
11
12use bitflags::bitflags;
13use codec::{Decode, Encode, Error, Input, Output};
14pub use generic::{BlockAnnounce, FromBlock};
15use subsoil::runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor};
16
17/// Type alias for using the block request type using block type parameters.
18pub type BlockRequest<B> =
19	generic::BlockRequest<<B as BlockT>::Hash, <<B as BlockT>::Header as HeaderT>::Number>;
20
21/// Type alias for using the BlockData type using block type parameters.
22pub type BlockData<B> =
23	generic::BlockData<<B as BlockT>::Header, <B as BlockT>::Hash, <B as BlockT>::Extrinsic>;
24
25/// Type alias for using the BlockResponse type using block type parameters.
26pub type BlockResponse<B> =
27	generic::BlockResponse<<B as BlockT>::Header, <B as BlockT>::Hash, <B as BlockT>::Extrinsic>;
28
29// Bits of block data and associated artifacts to request.
30bitflags! {
31	/// Node roles bitmask.
32	pub struct BlockAttributes: u8 {
33		/// Include block header.
34		const HEADER = 0b00000001;
35		/// Include block body.
36		const BODY = 0b00000010;
37		/// Include block receipt.
38		const RECEIPT = 0b00000100;
39		/// Include block message queue.
40		const MESSAGE_QUEUE = 0b00001000;
41		/// Include a justification for the block.
42		const JUSTIFICATION = 0b00010000;
43		/// Include indexed transactions for a block.
44		const INDEXED_BODY = 0b00100000;
45	}
46}
47
48impl BlockAttributes {
49	/// Encodes attributes as big endian u32, compatible with SCALE-encoding (i.e the
50	/// significant byte has zero index).
51	pub fn to_be_u32(&self) -> u32 {
52		u32::from_be_bytes([self.bits(), 0, 0, 0])
53	}
54
55	/// Decodes attributes, encoded with the `encode_to_be_u32()` call.
56	pub fn from_be_u32(encoded: u32) -> Result<Self, Error> {
57		Self::from_bits(encoded.to_be_bytes()[0])
58			.ok_or_else(|| Error::from("Invalid BlockAttributes"))
59	}
60}
61
62impl Encode for BlockAttributes {
63	fn encode_to<T: Output + ?Sized>(&self, dest: &mut T) {
64		dest.push_byte(self.bits())
65	}
66}
67
68impl codec::EncodeLike for BlockAttributes {}
69
70impl Decode for BlockAttributes {
71	fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
72		Self::from_bits(input.read_byte()?).ok_or_else(|| Error::from("Invalid bytes"))
73	}
74}
75
76#[derive(Debug, PartialEq, Eq, Clone, Copy, Encode, Decode)]
77/// Block enumeration direction.
78pub enum Direction {
79	/// Enumerate in ascending order (from child to parent).
80	Ascending = 0,
81	/// Enumerate in descending order (from parent to canonical child).
82	Descending = 1,
83}
84
85/// Block state in the chain.
86#[derive(Debug, PartialEq, Eq, Clone, Copy, Encode, Decode)]
87pub enum BlockState {
88	/// Block is not part of the best chain.
89	Normal,
90	/// Latest best block.
91	Best,
92}
93
94/// Announcement summary used for debug logging.
95#[derive(Debug)]
96pub struct AnnouncementSummary<H: HeaderT> {
97	pub block_hash: H::Hash,
98	pub number: H::Number,
99	pub parent_hash: H::Hash,
100	pub state: Option<BlockState>,
101}
102
103impl<H: HeaderT> BlockAnnounce<H> {
104	pub fn summary(&self) -> AnnouncementSummary<H> {
105		AnnouncementSummary {
106			block_hash: self.header.hash(),
107			number: *self.header.number(),
108			parent_hash: *self.header.parent_hash(),
109			state: self.state,
110		}
111	}
112}
113
114/// Generic types.
115pub mod generic {
116	use super::{BlockAttributes, BlockState, Direction};
117	use crate::common::message::RequestId;
118	use codec::{Decode, Encode, Input, Output};
119	use subsoil::runtime::{EncodedJustification, Justifications};
120
121	/// Block data sent in the response.
122	#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)]
123	pub struct BlockData<Header, Hash, Extrinsic> {
124		/// Block header hash.
125		pub hash: Hash,
126		/// Block header if requested.
127		pub header: Option<Header>,
128		/// Block body if requested.
129		pub body: Option<Vec<Extrinsic>>,
130		/// Block body indexed transactions if requested.
131		pub indexed_body: Option<Vec<Vec<u8>>>,
132		/// Block receipt if requested.
133		pub receipt: Option<Vec<u8>>,
134		/// Block message queue if requested.
135		pub message_queue: Option<Vec<u8>>,
136		/// Justification if requested.
137		pub justification: Option<EncodedJustification>,
138		/// Justifications if requested.
139		pub justifications: Option<Justifications>,
140	}
141
142	/// Request block data from a peer.
143	#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)]
144	pub struct BlockRequest<Hash, Number> {
145		/// Unique request id.
146		pub id: RequestId,
147		/// Bits of block data to request.
148		pub fields: BlockAttributes,
149		/// Start from this block.
150		pub from: FromBlock<Hash, Number>,
151		/// Sequence direction.
152		pub direction: Direction,
153		/// Maximum number of blocks to return. An implementation defined maximum is used when
154		/// unspecified.
155		pub max: Option<u32>,
156	}
157
158	/// Identifies starting point of a block sequence.
159	#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)]
160	pub enum FromBlock<Hash, Number> {
161		/// Start with given hash.
162		Hash(Hash),
163		/// Start with given block number.
164		Number(Number),
165	}
166
167	/// Response to `BlockRequest`
168	#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)]
169	pub struct BlockResponse<Header, Hash, Extrinsic> {
170		/// Id of a request this response was made for.
171		pub id: RequestId,
172		/// Block data for the requested sequence.
173		pub blocks: Vec<BlockData<Header, Hash, Extrinsic>>,
174	}
175
176	/// Announce a new complete block on the network.
177	#[derive(Debug, PartialEq, Eq, Clone)]
178	pub struct BlockAnnounce<H> {
179		/// New block header.
180		pub header: H,
181		/// Block state. TODO: Remove `Option` and custom encoding when v4 becomes common.
182		pub state: Option<BlockState>,
183		/// Data associated with this block announcement, e.g. a candidate message.
184		pub data: Option<Vec<u8>>,
185	}
186
187	// Custom Encode/Decode impl to maintain backwards compatibility with v3.
188	// This assumes that the packet contains nothing but the announcement message.
189	// TODO: Get rid of it once protocol v4 is common.
190	impl<H: Encode> Encode for BlockAnnounce<H> {
191		fn encode_to<T: Output + ?Sized>(&self, dest: &mut T) {
192			self.header.encode_to(dest);
193			if let Some(state) = &self.state {
194				state.encode_to(dest);
195			}
196			if let Some(data) = &self.data {
197				data.encode_to(dest)
198			}
199		}
200	}
201
202	impl<H: Decode> Decode for BlockAnnounce<H> {
203		fn decode<I: Input>(input: &mut I) -> Result<Self, codec::Error> {
204			let header = H::decode(input)?;
205			let state = BlockState::decode(input).ok();
206			let data = Vec::decode(input).ok();
207			Ok(Self { header, state, data })
208		}
209	}
210}
211
212/// Handshake sent when we open a block announces substream.
213#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)]
214pub struct BlockAnnouncesHandshake<B: BlockT> {
215	/// Roles of the node.
216	pub roles: Roles,
217	/// Best block number.
218	pub best_number: NumberFor<B>,
219	/// Best block hash.
220	pub best_hash: B::Hash,
221	/// Genesis block hash.
222	pub genesis_hash: B::Hash,
223}
224
225impl<B: BlockT> BlockAnnouncesHandshake<B> {
226	pub fn build(
227		roles: Roles,
228		best_number: NumberFor<B>,
229		best_hash: B::Hash,
230		genesis_hash: B::Hash,
231	) -> Self {
232		Self { genesis_hash, roles, best_number, best_hash }
233	}
234}