Skip to main content

bp_polkadot_core/
lib.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Parity Bridges Common.
3
4// Parity Bridges Common is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Parity Bridges Common is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
16
17//! Primitives of the Polkadot-like chains.
18
19#![warn(missing_docs)]
20#![cfg_attr(not(feature = "std"), no_std)]
21
22use bp_messages::MessageNonce;
23use bp_runtime::{
24	self,
25	extensions::{
26		ChargeTransactionPayment, CheckEra, CheckGenesis, CheckNonZeroSender, CheckNonce,
27		CheckSpecVersion, CheckTxVersion, CheckWeight, GenericTransactionExtension,
28		TransactionExtensionSchema,
29	},
30	EncodedOrDecodedCall, StorageMapKeyProvider, TransactionEra,
31};
32use frame_support::{
33	dispatch::DispatchClass,
34	parameter_types,
35	weights::{
36		constants::{BlockExecutionWeight, WEIGHT_REF_TIME_PER_SECOND},
37		Weight,
38	},
39	Blake2_128Concat,
40};
41use frame_system::limits;
42use sp_core::{storage::StorageKey, Hasher as HasherT};
43use sp_runtime::{
44	generic,
45	traits::{BlakeTwo256, IdentifyAccount, Verify},
46	MultiAddress, MultiSignature, OpaqueExtrinsic,
47};
48use sp_std::prelude::Vec;
49
50// Re-export's to avoid extra substrate dependencies in chain-specific crates.
51pub use frame_support::{weights::constants::ExtrinsicBaseWeight, Parameter};
52pub use sp_runtime::{traits::Convert, Perbill};
53
54pub mod parachains;
55
56/// Maximal number of GRANDPA authorities at Polkadot-like chains.
57///
58/// Ideally, we would set it to the value of `MaxAuthorities` constant from bridged runtime
59/// configurations. But right now it is set to the `100_000`, which makes PoV size for
60/// our bridge hub parachains huge. So let's stick to the real-world value here.
61///
62/// Right now both Kusama and Polkadot aim to have around 1000 validators. Let's be safe here and
63/// take a bit more here.
64pub const MAX_AUTHORITIES_COUNT: u32 = 1_256;
65
66/// Reasonable number of headers in the `votes_ancestries` on Polkadot-like chains.
67///
68/// See `bp_header_chain::ChainWithGrandpa` for more details.
69///
70/// This value comes from recent (December, 2023) Kusama and Polkadot headers. There are no
71/// justifications with any additional headers in votes ancestry, so reasonable headers may
72/// be set to zero. But we assume that there may be small GRANDPA lags, so we're leaving some
73/// reserve here.
74pub const REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY: u32 = 2;
75
76/// Average header size in `votes_ancestries` field of justification on Polkadot-like
77/// chains.
78///
79/// See `bp_header_chain::ChainWithGrandpa` for more details.
80///
81/// This value comes from recent (December, 2023) Kusama headers. Most of headers are `327` bytes
82/// there, but let's have some reserve and make it 1024.
83pub const AVERAGE_HEADER_SIZE: u32 = 1024;
84
85/// Approximate maximal header size on Polkadot-like chains.
86///
87/// See `bp_header_chain::ChainWithGrandpa` for more details.
88///
89/// This value comes from recent (December, 2023) Kusama headers. Maximal header is a mandatory
90/// header. In its SCALE-encoded form it is `113407` bytes. Let's have some reserve here.
91pub const MAX_MANDATORY_HEADER_SIZE: u32 = 120 * 1024;
92
93/// Number of extra bytes (excluding size of storage value itself) of storage proof, built at
94/// Polkadot-like chain. This mostly depends on number of entries in the storage trie.
95/// Some reserve is reserved to account future chain growth.
96///
97/// To compute this value, we've synced Kusama chain blocks [0; 6545733] to see if there were
98/// any significant changes of the storage proof size (NO):
99///
100/// - at block 3072 the storage proof size overhead was 579 bytes;
101/// - at block 2479616 it was 578 bytes;
102/// - at block 4118528 it was 711 bytes;
103/// - at block 6540800 it was 779 bytes.
104///
105/// The number of storage entries at the block 6546170 was 351207 and number of trie nodes in
106/// the storage proof was 5 (log(16, 351207) ~ 4.6).
107///
108/// So the assumption is that the storage proof size overhead won't be larger than 1024 in the
109/// nearest future. If it'll ever break this barrier, then we'll need to update this constant
110/// at next runtime upgrade.
111pub const EXTRA_STORAGE_PROOF_SIZE: u32 = 1024;
112
113/// All Polkadot-like chains allow normal extrinsics to fill block up to 75 percent.
114///
115/// This is a copy-paste from the Polkadot repo's `polkadot-runtime-common` crate.
116const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
117
118/// All Polkadot-like chains allow 2 seconds of compute with a 6-second average block time.
119///
120/// This is a copy-paste from the Polkadot repo's `polkadot-runtime-common` crate.
121pub const MAXIMUM_BLOCK_WEIGHT: Weight =
122	Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2), u64::MAX);
123
124/// All Polkadot-like chains assume that an on-initialize consumes 1 percent of the weight on
125/// average, hence a single extrinsic will not be allowed to consume more than
126/// `AvailableBlockRatio - 1 percent`.
127///
128/// This is a copy-paste from the Polkadot repo's `polkadot-runtime-common` crate.
129pub const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(1);
130
131parameter_types! {
132	/// All Polkadot-like chains have maximal block size set to 5MB.
133	///
134	/// This is a copy-paste from the Polkadot repo's `polkadot-runtime-common` crate.
135	pub BlockLength: limits::BlockLength = limits::BlockLength::builder()
136		.max_length(5 * 1024 * 1024)
137		.modify_max_length_for_class(DispatchClass::Normal, |m| {
138			*m = NORMAL_DISPATCH_RATIO * *m
139		})
140		.build();
141	/// All Polkadot-like chains have the same block weights.
142	///
143	/// This is a copy-paste from the Polkadot repo's `polkadot-runtime-common` crate.
144	pub BlockWeights: limits::BlockWeights = limits::BlockWeights::builder()
145		.base_block(BlockExecutionWeight::get())
146		.for_class(DispatchClass::all(), |weights| {
147			weights.base_extrinsic = ExtrinsicBaseWeight::get();
148		})
149		.for_class(DispatchClass::Normal, |weights| {
150			weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT);
151		})
152		.for_class(DispatchClass::Operational, |weights| {
153			weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT);
154			// Operational transactions have an extra reserved space, so that they
155			// are included even if block reached `MAXIMUM_BLOCK_WEIGHT`.
156			weights.reserved = Some(
157				MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT,
158			);
159		})
160		.avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO)
161		.build_or_panic();
162}
163
164// TODO [#78] may need to be updated after https://github.com/paritytech/parity-bridges-common/issues/78
165/// Maximal number of messages in single delivery transaction.
166pub const MAX_MESSAGES_IN_DELIVERY_TRANSACTION: MessageNonce = 128;
167
168/// Maximal number of bytes, included in the signed Polkadot-like transaction apart from the encoded
169/// call itself.
170///
171/// Can be computed by subtracting encoded call size from raw transaction size.
172pub const TX_EXTRA_BYTES: u32 = 256;
173
174/// Re-export `time_units` to make usage easier.
175pub use time_units::*;
176
177/// Human readable time units defined in terms of number of blocks.
178pub mod time_units {
179	use super::BlockNumber;
180
181	/// Milliseconds between Polkadot-like chain blocks.
182	pub const MILLISECS_PER_BLOCK: u64 = 6000;
183	/// Slot duration in Polkadot-like chain consensus algorithms.
184	pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
185
186	/// A minute, expressed in Polkadot-like chain blocks.
187	pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
188	/// A hour, expressed in Polkadot-like chain blocks.
189	pub const HOURS: BlockNumber = MINUTES * 60;
190	/// A day, expressed in Polkadot-like chain blocks.
191	pub const DAYS: BlockNumber = HOURS * 24;
192}
193
194/// Block number type used in Polkadot-like chains.
195pub type BlockNumber = u32;
196
197/// Hash type used in Polkadot-like chains.
198pub type Hash = <BlakeTwo256 as HasherT>::Out;
199
200/// Hashing type.
201pub type Hashing = BlakeTwo256;
202
203/// The type of object that can produce hashes on Polkadot-like chains.
204pub type Hasher = BlakeTwo256;
205
206/// The header type used by Polkadot-like chains.
207pub type Header = generic::Header<BlockNumber, Hasher>;
208
209/// Signature type used by Polkadot-like chains.
210pub type Signature = MultiSignature;
211
212/// Public key of account on Polkadot-like chains.
213pub type AccountPublic = <Signature as Verify>::Signer;
214
215/// Id of account on Polkadot-like chains.
216pub type AccountId = <AccountPublic as IdentifyAccount>::AccountId;
217
218/// Address of account on Polkadot-like chains.
219pub type AccountAddress = MultiAddress<AccountId, ()>;
220
221/// Nonce of a transaction on the Polkadot-like chains.
222pub type Nonce = u32;
223
224/// Block type of Polkadot-like chains.
225pub type Block = generic::Block<Header, OpaqueExtrinsic>;
226
227/// Polkadot-like block signed with a Justification.
228pub type SignedBlock = generic::SignedBlock<Block>;
229
230/// The balance of an account on Polkadot-like chain.
231pub type Balance = u128;
232
233/// Unchecked Extrinsic type.
234pub type UncheckedExtrinsic<Call, TransactionExt> = generic::UncheckedExtrinsic<
235	AccountAddress,
236	EncodedOrDecodedCall<Call>,
237	Signature,
238	TransactionExt,
239>;
240
241/// Account address, used by the Polkadot-like chain.
242pub type Address = MultiAddress<AccountId, ()>;
243
244/// Returns maximal extrinsic size on all Polkadot-like chains.
245pub fn max_extrinsic_size() -> u32 {
246	*BlockLength::get().max.get(DispatchClass::Normal)
247}
248
249/// Returns maximal extrinsic weight on all Polkadot-like chains.
250pub fn max_extrinsic_weight() -> Weight {
251	BlockWeights::get()
252		.get(DispatchClass::Normal)
253		.max_extrinsic
254		.unwrap_or(Weight::MAX)
255}
256
257/// Provides a storage key for account data.
258///
259/// We need to use this approach when we don't have access to the runtime.
260/// The equivalent command to invoke in case full `Runtime` is known is this:
261/// `let key = frame_system::Account::<Runtime>::storage_map_final_key(&account_id);`
262pub struct AccountInfoStorageMapKeyProvider;
263
264impl StorageMapKeyProvider for AccountInfoStorageMapKeyProvider {
265	const MAP_NAME: &'static str = "Account";
266	type Hasher = Blake2_128Concat;
267	type Key = AccountId;
268	// This should actually be `AccountInfo`, but we don't use this property in order to decode the
269	// data. So we use `Vec<u8>` as if we would work with encoded data.
270	type Value = Vec<u8>;
271}
272
273impl AccountInfoStorageMapKeyProvider {
274	/// Name of the system pallet.
275	const PALLET_NAME: &'static str = "System";
276
277	/// Return storage key for given account data.
278	pub fn final_key(id: &AccountId) -> StorageKey {
279		<Self as StorageMapKeyProvider>::final_key(Self::PALLET_NAME, id)
280	}
281}
282
283/// Extra signed extension data that is used by most chains.
284pub type CommonTransactionExtra = (
285	CheckNonZeroSender,
286	CheckSpecVersion,
287	CheckTxVersion,
288	CheckGenesis<Hash>,
289	CheckEra<Hash>,
290	CheckNonce<Nonce>,
291	CheckWeight,
292	ChargeTransactionPayment<Balance>,
293);
294
295/// Extra transaction extension data that starts with `CommonTransactionExtra`.
296pub type SuffixedCommonTransactionExtension<Suffix> =
297	GenericTransactionExtension<(CommonTransactionExtra, Suffix)>;
298
299/// Helper trait to define some extra methods on `SuffixedCommonTransactionExtension`.
300pub trait SuffixedCommonTransactionExtensionExt<Suffix: TransactionExtensionSchema> {
301	/// Create signed extension from its components.
302	fn from_params(
303		spec_version: u32,
304		transaction_version: u32,
305		era: TransactionEra<BlockNumber, Hash>,
306		genesis_hash: Hash,
307		nonce: Nonce,
308		tip: Balance,
309		extra: (Suffix::Payload, Suffix::Implicit),
310	) -> Self;
311
312	/// Return transaction nonce.
313	fn nonce(&self) -> Nonce;
314
315	/// Return transaction tip.
316	fn tip(&self) -> Balance;
317}
318
319impl<Suffix> SuffixedCommonTransactionExtensionExt<Suffix>
320	for SuffixedCommonTransactionExtension<Suffix>
321where
322	Suffix: TransactionExtensionSchema,
323{
324	fn from_params(
325		spec_version: u32,
326		transaction_version: u32,
327		era: TransactionEra<BlockNumber, Hash>,
328		genesis_hash: Hash,
329		nonce: Nonce,
330		tip: Balance,
331		extra: (Suffix::Payload, Suffix::Implicit),
332	) -> Self {
333		GenericTransactionExtension::new(
334			(
335				(
336					(),              // non-zero sender
337					(),              // spec version
338					(),              // tx version
339					(),              // genesis
340					era.frame_era(), // era
341					nonce.into(),    // nonce (compact encoding)
342					(),              // Check weight
343					tip.into(),      // transaction payment / tip (compact encoding)
344				),
345				extra.0,
346			),
347			Some((
348				(
349					(),
350					spec_version,
351					transaction_version,
352					genesis_hash,
353					era.signed_payload(genesis_hash),
354					(),
355					(),
356					(),
357				),
358				extra.1,
359			)),
360		)
361	}
362
363	fn nonce(&self) -> Nonce {
364		let common_payload = self.payload.0;
365		common_payload.5 .0
366	}
367
368	fn tip(&self) -> Balance {
369		let common_payload = self.payload.0;
370		common_payload.7 .0
371	}
372}
373
374/// Signed extension that is used by most chains.
375pub type CommonTransactionExtension = SuffixedCommonTransactionExtension<()>;
376
377#[cfg(test)]
378mod tests {
379	use super::*;
380
381	#[test]
382	fn should_generate_storage_key() {
383		let acc = [
384			1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
385			25, 26, 27, 28, 29, 30, 31, 32,
386		]
387		.into();
388		let key = AccountInfoStorageMapKeyProvider::final_key(&acc);
389		assert_eq!(hex::encode(key), "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da92dccd599abfe1920a1cff8a7358231430102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20");
390	}
391}