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::max_with_normal_ratio(
136 5 * 1024 * 1024,
137 NORMAL_DISPATCH_RATIO,
138 );
139 /// All Polkadot-like chains have the same block weights.
140 ///
141 /// This is a copy-paste from the Polkadot repo's `polkadot-runtime-common` crate.
142 pub BlockWeights: limits::BlockWeights = limits::BlockWeights::builder()
143 .base_block(BlockExecutionWeight::get())
144 .for_class(DispatchClass::all(), |weights| {
145 weights.base_extrinsic = ExtrinsicBaseWeight::get();
146 })
147 .for_class(DispatchClass::Normal, |weights| {
148 weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT);
149 })
150 .for_class(DispatchClass::Operational, |weights| {
151 weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT);
152 // Operational transactions have an extra reserved space, so that they
153 // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`.
154 weights.reserved = Some(
155 MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT,
156 );
157 })
158 .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO)
159 .build_or_panic();
160}
161
162// TODO [#78] may need to be updated after https://github.com/paritytech/parity-bridges-common/issues/78
163/// Maximal number of messages in single delivery transaction.
164pub const MAX_MESSAGES_IN_DELIVERY_TRANSACTION: MessageNonce = 128;
165
166/// Maximal number of bytes, included in the signed Polkadot-like transaction apart from the encoded
167/// call itself.
168///
169/// Can be computed by subtracting encoded call size from raw transaction size.
170pub const TX_EXTRA_BYTES: u32 = 256;
171
172/// Re-export `time_units` to make usage easier.
173pub use time_units::*;
174
175/// Human readable time units defined in terms of number of blocks.
176pub mod time_units {
177 use super::BlockNumber;
178
179 /// Milliseconds between Polkadot-like chain blocks.
180 pub const MILLISECS_PER_BLOCK: u64 = 6000;
181 /// Slot duration in Polkadot-like chain consensus algorithms.
182 pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
183
184 /// A minute, expressed in Polkadot-like chain blocks.
185 pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
186 /// A hour, expressed in Polkadot-like chain blocks.
187 pub const HOURS: BlockNumber = MINUTES * 60;
188 /// A day, expressed in Polkadot-like chain blocks.
189 pub const DAYS: BlockNumber = HOURS * 24;
190}
191
192/// Block number type used in Polkadot-like chains.
193pub type BlockNumber = u32;
194
195/// Hash type used in Polkadot-like chains.
196pub type Hash = <BlakeTwo256 as HasherT>::Out;
197
198/// Hashing type.
199pub type Hashing = BlakeTwo256;
200
201/// The type of object that can produce hashes on Polkadot-like chains.
202pub type Hasher = BlakeTwo256;
203
204/// The header type used by Polkadot-like chains.
205pub type Header = generic::Header<BlockNumber, Hasher>;
206
207/// Signature type used by Polkadot-like chains.
208pub type Signature = MultiSignature;
209
210/// Public key of account on Polkadot-like chains.
211pub type AccountPublic = <Signature as Verify>::Signer;
212
213/// Id of account on Polkadot-like chains.
214pub type AccountId = <AccountPublic as IdentifyAccount>::AccountId;
215
216/// Address of account on Polkadot-like chains.
217pub type AccountAddress = MultiAddress<AccountId, ()>;
218
219/// Nonce of a transaction on the Polkadot-like chains.
220pub type Nonce = u32;
221
222/// Block type of Polkadot-like chains.
223pub type Block = generic::Block<Header, OpaqueExtrinsic>;
224
225/// Polkadot-like block signed with a Justification.
226pub type SignedBlock = generic::SignedBlock<Block>;
227
228/// The balance of an account on Polkadot-like chain.
229pub type Balance = u128;
230
231/// Unchecked Extrinsic type.
232pub type UncheckedExtrinsic<Call, TransactionExt> = generic::UncheckedExtrinsic<
233 AccountAddress,
234 EncodedOrDecodedCall<Call>,
235 Signature,
236 TransactionExt,
237>;
238
239/// Account address, used by the Polkadot-like chain.
240pub type Address = MultiAddress<AccountId, ()>;
241
242/// Returns maximal extrinsic size on all Polkadot-like chains.
243pub fn max_extrinsic_size() -> u32 {
244 *BlockLength::get().max.get(DispatchClass::Normal)
245}
246
247/// Returns maximal extrinsic weight on all Polkadot-like chains.
248pub fn max_extrinsic_weight() -> Weight {
249 BlockWeights::get()
250 .get(DispatchClass::Normal)
251 .max_extrinsic
252 .unwrap_or(Weight::MAX)
253}
254
255/// Provides a storage key for account data.
256///
257/// We need to use this approach when we don't have access to the runtime.
258/// The equivalent command to invoke in case full `Runtime` is known is this:
259/// `let key = frame_system::Account::<Runtime>::storage_map_final_key(&account_id);`
260pub struct AccountInfoStorageMapKeyProvider;
261
262impl StorageMapKeyProvider for AccountInfoStorageMapKeyProvider {
263 const MAP_NAME: &'static str = "Account";
264 type Hasher = Blake2_128Concat;
265 type Key = AccountId;
266 // This should actually be `AccountInfo`, but we don't use this property in order to decode the
267 // data. So we use `Vec<u8>` as if we would work with encoded data.
268 type Value = Vec<u8>;
269}
270
271impl AccountInfoStorageMapKeyProvider {
272 /// Name of the system pallet.
273 const PALLET_NAME: &'static str = "System";
274
275 /// Return storage key for given account data.
276 pub fn final_key(id: &AccountId) -> StorageKey {
277 <Self as StorageMapKeyProvider>::final_key(Self::PALLET_NAME, id)
278 }
279}
280
281/// Extra signed extension data that is used by most chains.
282pub type CommonTransactionExtra = (
283 CheckNonZeroSender,
284 CheckSpecVersion,
285 CheckTxVersion,
286 CheckGenesis<Hash>,
287 CheckEra<Hash>,
288 CheckNonce<Nonce>,
289 CheckWeight,
290 ChargeTransactionPayment<Balance>,
291);
292
293/// Extra transaction extension data that starts with `CommonTransactionExtra`.
294pub type SuffixedCommonTransactionExtension<Suffix> =
295 GenericTransactionExtension<(CommonTransactionExtra, Suffix)>;
296
297/// Helper trait to define some extra methods on `SuffixedCommonTransactionExtension`.
298pub trait SuffixedCommonTransactionExtensionExt<Suffix: TransactionExtensionSchema> {
299 /// Create signed extension from its components.
300 fn from_params(
301 spec_version: u32,
302 transaction_version: u32,
303 era: TransactionEra<BlockNumber, Hash>,
304 genesis_hash: Hash,
305 nonce: Nonce,
306 tip: Balance,
307 extra: (Suffix::Payload, Suffix::Implicit),
308 ) -> Self;
309
310 /// Return transaction nonce.
311 fn nonce(&self) -> Nonce;
312
313 /// Return transaction tip.
314 fn tip(&self) -> Balance;
315}
316
317impl<Suffix> SuffixedCommonTransactionExtensionExt<Suffix>
318 for SuffixedCommonTransactionExtension<Suffix>
319where
320 Suffix: TransactionExtensionSchema,
321{
322 fn from_params(
323 spec_version: u32,
324 transaction_version: u32,
325 era: TransactionEra<BlockNumber, Hash>,
326 genesis_hash: Hash,
327 nonce: Nonce,
328 tip: Balance,
329 extra: (Suffix::Payload, Suffix::Implicit),
330 ) -> Self {
331 GenericTransactionExtension::new(
332 (
333 (
334 (), // non-zero sender
335 (), // spec version
336 (), // tx version
337 (), // genesis
338 era.frame_era(), // era
339 nonce.into(), // nonce (compact encoding)
340 (), // Check weight
341 tip.into(), // transaction payment / tip (compact encoding)
342 ),
343 extra.0,
344 ),
345 Some((
346 (
347 (),
348 spec_version,
349 transaction_version,
350 genesis_hash,
351 era.signed_payload(genesis_hash),
352 (),
353 (),
354 (),
355 ),
356 extra.1,
357 )),
358 )
359 }
360
361 fn nonce(&self) -> Nonce {
362 let common_payload = self.payload.0;
363 common_payload.5 .0
364 }
365
366 fn tip(&self) -> Balance {
367 let common_payload = self.payload.0;
368 common_payload.7 .0
369 }
370}
371
372/// Signed extension that is used by most chains.
373pub type CommonTransactionExtension = SuffixedCommonTransactionExtension<()>;
374
375#[cfg(test)]
376mod tests {
377 use super::*;
378
379 #[test]
380 fn should_generate_storage_key() {
381 let acc = [
382 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
383 25, 26, 27, 28, 29, 30, 31, 32,
384 ]
385 .into();
386 let key = AccountInfoStorageMapKeyProvider::final_key(&acc);
387 assert_eq!(hex::encode(key), "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da92dccd599abfe1920a1cff8a7358231430102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20");
388 }
389}