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}