diff --git a/bridges/bin/millau/runtime/src/lib.rs b/bridges/bin/millau/runtime/src/lib.rs index 7ac3cc73bf..cdd8b5a87f 100644 --- a/bridges/bin/millau/runtime/src/lib.rs +++ b/bridges/bin/millau/runtime/src/lib.rs @@ -311,18 +311,34 @@ parameter_types! { // Note that once this is hit the pallet will essentially throttle incoming requests down to one // call per block. pub const MaxRequests: u32 = 50; + pub const WestendSessionLength: bp_westend::BlockNumber = bp_westend::SESSION_LENGTH; + pub const RialtoSessionLength: bp_rialto::BlockNumber = bp_rialto::SESSION_LENGTH; + + // TODO [#846]: Right now this will break benchmarking if it is greater than `u8::MAX` + pub const RialtoValidatorCount: u32 = 255; + pub const WestendValidatorCount: u32 = 255; } pub type RialtoGrandpaInstance = (); impl pallet_bridge_grandpa::Config for Runtime { type BridgedChain = bp_rialto::Rialto; type MaxRequests = MaxRequests; + type MaxBridgedSessionLength = RialtoSessionLength; + type MaxBridgedValidatorCount = RialtoValidatorCount; + + // TODO [#391]: Use weights generated for the Millau runtime instead of Rialto ones. + type WeightInfo = pallet_bridge_grandpa::weights::RialtoWeight; } pub type WestendGrandpaInstance = pallet_bridge_grandpa::Instance1; impl pallet_bridge_grandpa::Config for Runtime { type BridgedChain = bp_westend::Westend; type MaxRequests = MaxRequests; + type MaxBridgedSessionLength = WestendSessionLength; + type MaxBridgedValidatorCount = WestendValidatorCount; + + // TODO [#391]: Use weights generated for the Millau runtime instead of Rialto ones. + type WeightInfo = pallet_bridge_grandpa::weights::RialtoWeight; } impl pallet_shift_session_manager::Config for Runtime {} diff --git a/bridges/bin/rialto/runtime/src/lib.rs b/bridges/bin/rialto/runtime/src/lib.rs index c2c50f05a7..a0ccbf27e6 100644 --- a/bridges/bin/rialto/runtime/src/lib.rs +++ b/bridges/bin/rialto/runtime/src/lib.rs @@ -417,11 +417,18 @@ parameter_types! { // Note that once this is hit the pallet will essentially throttle incoming requests down to one // call per block. pub const MaxRequests: u32 = 50; + pub const MillauSessionLength: bp_millau::BlockNumber = bp_millau::SESSION_LENGTH; + + // TODO [#846]: Right now this will break benchmarking if it is greater than `u8::MAX` + pub const MillauValidatorCount: u32 = 255; } impl pallet_bridge_grandpa::Config for Runtime { type BridgedChain = bp_millau::Millau; type MaxRequests = MaxRequests; + type MaxBridgedSessionLength = MillauSessionLength; + type MaxBridgedValidatorCount = MillauValidatorCount; + type WeightInfo = pallet_bridge_grandpa::weights::RialtoWeight; } impl pallet_shift_session_manager::Config for Runtime {} @@ -799,6 +806,7 @@ impl_runtime_apis! { config: frame_benchmarking::BenchmarkConfig, ) -> Result, sp_runtime::RuntimeString> { use frame_benchmarking::{Benchmarking, BenchmarkBatch, TrackedStorageKey, add_benchmark}; + let whitelist: Vec = vec![ // Block Number hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(), @@ -945,6 +953,7 @@ impl_runtime_apis! { >( &lane_id, ).0; + let make_millau_header = |state_root| bp_millau::Header::new( 0, Default::default(), @@ -1005,7 +1014,6 @@ impl_runtime_apis! { } } - add_benchmark!(params, batches, pallet_bridge_eth_poa, BridgeKovan); add_benchmark!( params, batches, @@ -1018,6 +1026,7 @@ impl_runtime_apis! { pallet_bridge_messages, MessagesBench:: ); + add_benchmark!(params, batches, pallet_bridge_grandpa, BridgeMillauGrandpa); if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } Ok(batches) diff --git a/bridges/modules/grandpa/Cargo.toml b/bridges/modules/grandpa/Cargo.toml index 4b35905ecb..1191c8c8fc 100644 --- a/bridges/modules/grandpa/Cargo.toml +++ b/bridges/modules/grandpa/Cargo.toml @@ -11,6 +11,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } finality-grandpa = { version = "0.14.0", default-features = false } log = { version = "0.4.14", default-features = false } +num-traits = { version = "0.2", default-features = false } serde = { version = "1.0", optional = true } # Bridge Dependencies @@ -27,25 +28,33 @@ sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master sp-std = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false } sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false } +# Optional Benchmarking Dependencies +bp-test-utils = { path = "../../primitives/test-utils", default-features = false, optional = true } +frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false, optional = true } + [dev-dependencies] -bp-test-utils = {path = "../../primitives/test-utils" } pallet-substrate-bridge = { path = "../../modules/substrate" } sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } [features] default = ["std"] std = [ - "bp-runtime/std", "bp-header-chain/std", + "bp-runtime/std", + "bp-test-utils/std", "codec/std", "finality-grandpa/std", "frame-support/std", "frame-system/std", "log/std", + "num-traits/std", "serde", "sp-finality-grandpa/std", "sp-runtime/std", "sp-std/std", "sp-trie/std", ] -runtime-benchmarks = [] +runtime-benchmarks = [ + "bp-test-utils", + "frame-benchmarking", +] diff --git a/bridges/modules/grandpa/src/benchmarking.rs b/bridges/modules/grandpa/src/benchmarking.rs new file mode 100644 index 0000000000..089e7f88e7 --- /dev/null +++ b/bridges/modules/grandpa/src/benchmarking.rs @@ -0,0 +1,264 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Benchmarks for the GRANDPA Pallet. +//! +//! The main dispatchable for the GRANDPA pallet is `submit_finality_proof`, so these benchmarks are +//! based around that. There are to main factors which affect finality proof verification: +//! +//! 1. The number of `votes-ancestries` in the justification +//! 2. The number of `pre-commits` in the justification +//! +//! Vote ancestries are the headers between (`finality_target`, `head_of_chain`], where +//! `header_of_chain` is a decendant of `finality_target`. +//! +//! Pre-commits are messages which are signed by validators at the head of the chain they think is +//! the best. +//! +//! Consider the following: +//! +//! / [B'] <- [C'] +//! [A] <- [B] <- [C] +//! +//! The common ancestor of both forks is block A, so this is what GRANDPA will finalize. In order to +//! verify this we will have vote ancestries of [B, C, B', C'] and pre-commits [C, C']. +//! +//! Note that the worst case scenario here would be a justification where each validator has it's +//! own fork which is `SESSION_LENGTH` blocks long. +//! +//! As far as benchmarking results go, the only benchmark that should be used in +//! `pallet-bridge-grandpa` to annotate weights is the `submit_finality_proof` one. The others are +//! looking at the effects of specific code paths and do not actually reflect the overall worst case +//! scenario. + +use crate::*; + +use bp_test_utils::{ + accounts, authority_list, make_justification_for_header, test_keyring, JustificationGeneratorParams, ALICE, + TEST_GRANDPA_ROUND, TEST_GRANDPA_SET_ID, +}; +use frame_benchmarking::{benchmarks_instance_pallet, whitelisted_caller}; +use frame_support::traits::Get; +use frame_system::RawOrigin; +use num_traits::cast::AsPrimitive; +use sp_finality_grandpa::AuthorityId; +use sp_runtime::traits::{One, Zero}; +use sp_std::{vec, vec::Vec}; + +benchmarks_instance_pallet! { + // This is the "gold standard" benchmark for this extrinsic, and it's what should be used to + // annotate the weight in the pallet. + // + // The other benchmarks related to `submit_finality_proof` are looking at the effect of specific + // parameters and are there mostly for seeing how specific codepaths behave. + submit_finality_proof { + let s in 1..T::MaxBridgedSessionLength::get().as_() as u32; + let p in 1..T::MaxBridgedValidatorCount::get(); + + let caller: T::AccountId = whitelisted_caller(); + + let authority_list = accounts(p as u8) + .iter() + .map(|id| (AuthorityId::from(*id), 1)) + .collect::>(); + + let init_data = InitializationData { + header: bp_test_utils::test_header(Zero::zero()), + authority_list, + set_id: TEST_GRANDPA_SET_ID, + is_halted: false, + }; + + initialize_bridge::(init_data); + let header: BridgedHeader = bp_test_utils::test_header(One::one()); + + let params = JustificationGeneratorParams { + header: header.clone(), + round: TEST_GRANDPA_ROUND, + set_id: TEST_GRANDPA_SET_ID, + authorities: accounts(p as u8).iter().map(|k| (*k, 1)).collect::>(), + depth: s, + forks: p, + }; + + let justification = make_justification_for_header(params); + + }: _(RawOrigin::Signed(caller), header, justification) + verify { + let header: BridgedHeader = bp_test_utils::test_header(One::one()); + let expected_hash = header.hash(); + + assert_eq!(>::get(), expected_hash); + assert!(>::contains_key(expected_hash)); + } + + // What we want to check here is the effect of vote ancestries on justification verification + // do this by varying the number of headers between `finality_target` and `header_of_chain`. + submit_finality_proof_on_single_fork { + let s in 1..T::MaxBridgedSessionLength::get().as_() as u32; + + let caller: T::AccountId = whitelisted_caller(); + + let init_data = InitializationData { + header: bp_test_utils::test_header(Zero::zero()), + authority_list: authority_list(), + set_id: TEST_GRANDPA_SET_ID, + is_halted: false, + }; + + initialize_bridge::(init_data); + let header: BridgedHeader = bp_test_utils::test_header(One::one()); + + let params = JustificationGeneratorParams { + header: header.clone(), + round: TEST_GRANDPA_ROUND, + set_id: TEST_GRANDPA_SET_ID, + authorities: test_keyring(), + depth: s, + forks: 1, + }; + + let justification = make_justification_for_header(params); + + }: submit_finality_proof(RawOrigin::Signed(caller), header, justification) + verify { + let header: BridgedHeader = bp_test_utils::test_header(One::one()); + let expected_hash = header.hash(); + + assert_eq!(>::get(), expected_hash); + assert!(>::contains_key(expected_hash)); + } + + // What we want to check here is the effect of many pre-commits on justification verification. + // We do this by creating many forks, whose head will be used as a signed pre-commit in the + // final justification. + submit_finality_proof_on_many_forks { + let p in 1..T::MaxBridgedValidatorCount::get(); + + let caller: T::AccountId = whitelisted_caller(); + + let authority_list = accounts(p as u8) + .iter() + .map(|id| (AuthorityId::from(*id), 1)) + .collect::>(); + + let init_data = InitializationData { + header: bp_test_utils::test_header(Zero::zero()), + authority_list, + set_id: TEST_GRANDPA_SET_ID, + is_halted: false, + }; + + initialize_bridge::(init_data); + let header: BridgedHeader = bp_test_utils::test_header(One::one()); + + let params = JustificationGeneratorParams { + header: header.clone(), + round: TEST_GRANDPA_ROUND, + set_id: TEST_GRANDPA_SET_ID, + authorities: accounts(p as u8).iter().map(|k| (*k, 1)).collect::>(), + depth: 2, + forks: p, + }; + + let justification = make_justification_for_header(params); + + }: submit_finality_proof(RawOrigin::Signed(caller), header, justification) + verify { + let header: BridgedHeader = bp_test_utils::test_header(One::one()); + let expected_hash = header.hash(); + + assert_eq!(>::get(), expected_hash); + assert!(>::contains_key(expected_hash)); + } + + // Here we want to find out the overheaded of looking through consensus digests found in a + // header. As the number of logs in a header grows, how much more work do we require to look + // through them? + // + // Note that this should be the same for looking through scheduled changes and forces changes, + // which is why we only have one benchmark for this. + find_scheduled_change { + // Not really sure what a good bound for this is. + let n in 1..1000; + + let mut logs = vec![]; + for i in 0..n { + // We chose a non-consensus log on purpose since that way we have to look through all + // the logs in the header + logs.push(sp_runtime::DigestItem::Other(vec![])); + } + + let mut header: BridgedHeader = bp_test_utils::test_header(Zero::zero()); + let digest = header.digest_mut(); + *digest = sp_runtime::Digest { + logs, + }; + + }: { + crate::find_scheduled_change(&header) + } + + // What we want to check here is how long it takes to read and write the authority set tracked + // by the pallet as the number of authorities grows. + read_write_authority_sets { + // The current max target number of validators on Polkadot/Kusama + let n in 1..1000; + + let mut authorities = vec![]; + for i in 0..n { + authorities.push((ALICE, 1)); + } + + let authority_set = bp_header_chain::AuthoritySet { + authorities: authorities.iter().map(|(id, w)| (AuthorityId::from(*id), *w)).collect(), + set_id: 0 + }; + + >::put(&authority_set); + + }: { + let authority_set = >::get(); + >::put(&authority_set); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use frame_support::assert_ok; + + #[test] + fn finality_proof_is_valid() { + mock::run_test(|| { + assert_ok!(test_benchmark_submit_finality_proof::()); + }); + } + + #[test] + fn single_fork_finality_proof_is_valid() { + mock::run_test(|| { + assert_ok!(test_benchmark_submit_finality_proof_on_single_fork::()); + }); + } + + #[test] + fn multi_fork_finality_proof_is_valid() { + mock::run_test(|| { + assert_ok!(test_benchmark_submit_finality_proof_on_many_forks::()); + }); + } +} diff --git a/bridges/modules/grandpa/src/lib.rs b/bridges/modules/grandpa/src/lib.rs index acf9b7e736..2721507d47 100644 --- a/bridges/modules/grandpa/src/lib.rs +++ b/bridges/modules/grandpa/src/lib.rs @@ -36,12 +36,15 @@ // Runtime-generated enums #![allow(clippy::large_enum_variant)] +use crate::weights::WeightInfo; + use bp_header_chain::justification::GrandpaJustification; use bp_runtime::{BlockNumberOf, Chain, HashOf, HasherOf, HeaderOf}; use codec::{Decode, Encode}; use finality_grandpa::voter_set::VoterSet; use frame_support::ensure; use frame_system::{ensure_signed, RawOrigin}; +use num_traits::cast::AsPrimitive; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; use sp_finality_grandpa::{ConsensusLog, GRANDPA_ENGINE_ID}; @@ -51,6 +54,12 @@ use sp_runtime::RuntimeDebug; #[cfg(test)] mod mock; +/// Module containing weights for this pallet. +pub mod weights; + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; + // Re-export in crate namespace for `construct_runtime!` pub use pallet::*; @@ -82,6 +91,30 @@ pub mod pallet { /// until the request count has decreased. #[pallet::constant] type MaxRequests: Get; + + /// The maximum length of a session on the bridged chain. + /// + /// The pallet uses this to bound justification verification since justifications contain + /// ancestry proofs whose size is capped at `MaxBridgedSessionLength`. + #[pallet::constant] + type MaxBridgedSessionLength: Get>; + + /// The number of validators on the bridged chain. + /// + /// The pallet uses this to bound justification verification since justifications may + /// contain up to `MaxBridgedValidatorCount` number of signed `pre-commit` messages which + /// need to be verified. + /// + /// Note that `MaxBridgedValidatorCount` should *not* match the exact number of validators + /// on the bridged chain. Instead it should be a number which is greater than the actual + /// number of validators in order to provide some buffer room should the validator set + /// increase in size. If this number ends up being lower than the actual number of + /// validators on the bridged chain you risk stalling the bridge. + #[pallet::constant] + type MaxBridgedValidatorCount: Get; + + /// Weights gathered through benchmarking. + type WeightInfo: WeightInfo; } #[pallet::pallet] @@ -107,7 +140,10 @@ pub mod pallet { /// /// If successful in verification, it will write the target header to the underlying storage /// pallet. - #[pallet::weight(0)] + #[pallet::weight(T::WeightInfo::submit_finality_proof( + T::MaxBridgedSessionLength::get().as_() as u32, + T::MaxBridgedValidatorCount::get(), + ))] pub fn submit_finality_proof( origin: OriginFor, finality_target: BridgedHeader, @@ -134,16 +170,26 @@ pub mod pallet { // "travelling back in time" (which could be indicative of something bad, e.g a hard-fork). ensure!(best_finalized.number() < number, >::OldHeader); - verify_justification::(&justification, hash, *number)?; + let authority_set = >::get(); + let set_id = authority_set.set_id; + verify_justification::(&justification, hash, *number, authority_set)?; - try_enact_authority_change::(&finality_target)?; + let _enacted = try_enact_authority_change::(&finality_target, set_id)?; >::put(hash); >::insert(hash, finality_target); >::mutate(|count| *count += 1); log::info!(target: "runtime::bridge-grandpa", "Succesfully imported finalized header with hash {:?}!", hash); - Ok(().into()) + // Note that the number of precommits is indicitive of the number of GRANDPA forks being + // voted on. + let precommits = justification.commit.precommits.len(); + + // This represents the average number of votes in a single fork since the weight formula + // uses that metric instead of the aggregated number of vote ancestries. + let votes = (justification.votes_ancestries.len() + precommits - 1) / precommits; + + Ok(Some(T::WeightInfo::submit_finality_proof(votes as u32, precommits as u32)).into()) } /// Bootstrap the bridge pallet with an initial header and authority set from which to sync. @@ -319,9 +365,14 @@ pub mod pallet { /// /// This function does not support forced changes, or scheduled changes with delays /// since these types of changes are indicitive of abnormal behaviour from GRANDPA. + /// + /// Returned value will indicate if a change was enacted or not. pub(crate) fn try_enact_authority_change, I: 'static>( header: &BridgedHeader, - ) -> Result<(), sp_runtime::DispatchError> { + current_set_id: sp_finality_grandpa::SetId, + ) -> Result { + let mut change_enacted = false; + // We don't support forced changes - at that point governance intervention is required. ensure!( super::find_forced_change(header).is_none(), @@ -332,7 +383,6 @@ pub mod pallet { // GRANDPA only includes a `delay` for forced changes, so this isn't valid. ensure!(change.delay == Zero::zero(), >::UnsupportedScheduledChange); - let current_set_id = >::get().set_id; // TODO [#788]: Stop manually increasing the `set_id` here. let next_authorities = bp_header_chain::AuthoritySet { authorities: change.next_authorities, @@ -342,6 +392,7 @@ pub mod pallet { // Since our header schedules a change and we know the delay is 0, it must also enact // the change. >::put(&next_authorities); + change_enacted = true; log::info!( target: "runtime::bridge-grandpa", @@ -352,20 +403,23 @@ pub mod pallet { ); }; - Ok(()) + Ok(change_enacted) } /// Verify a GRANDPA justification (finality proof) for a given header. /// /// Will use the GRANDPA current authorities known to the pallet. + /// + /// If succesful it returns the decoded GRANDPA justification so we can refund any weight which + /// was overcharged in the initial call. pub(crate) fn verify_justification, I: 'static>( justification: &GrandpaJustification>, hash: BridgedBlockHash, number: BridgedBlockNumber, + authority_set: bp_header_chain::AuthoritySet, ) -> Result<(), sp_runtime::DispatchError> { use bp_header_chain::justification::verify_justification; - let authority_set = >::get(); let voter_set = VoterSet::new(authority_set.authorities).ok_or(>::InvalidAuthoritySet)?; let set_id = authority_set.set_id; @@ -510,7 +564,7 @@ pub(crate) fn find_forced_change( header.digest().convert_first(|l| l.try_to(id).and_then(filter_log)) } -/// (Re)initialize bridge with given header for using it in external benchmarks. +/// (Re)initialize bridge with given header for using it in `pallet-bridge-messages` benchmarks. #[cfg(feature = "runtime-benchmarks")] pub fn initialize_for_benchmarks, I: 'static>(header: BridgedHeader) { initialize_bridge::(InitializationData { diff --git a/bridges/modules/grandpa/src/mock.rs b/bridges/modules/grandpa/src/mock.rs index 8deca8ae85..1f9857eaf0 100644 --- a/bridges/modules/grandpa/src/mock.rs +++ b/bridges/modules/grandpa/src/mock.rs @@ -80,11 +80,16 @@ impl frame_system::Config for TestRuntime { parameter_types! { pub const MaxRequests: u32 = 2; + pub const SessionLength: u64 = 5; + pub const NumValidators: u32 = 5; } impl grandpa::Config for TestRuntime { type BridgedChain = TestBridgedChain; type MaxRequests = MaxRequests; + type MaxBridgedSessionLength = SessionLength; + type MaxBridgedValidatorCount = NumValidators; + type WeightInfo = (); } #[derive(Debug)] diff --git a/bridges/modules/grandpa/src/weights.rs b/bridges/modules/grandpa/src/weights.rs new file mode 100644 index 0000000000..dec26d061d --- /dev/null +++ b/bridges/modules/grandpa/src/weights.rs @@ -0,0 +1,141 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common 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. + +// Parity Bridges Common 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 Parity Bridges Common. If not, see . + +//! Autogenerated weights for pallet_bridge_grandpa +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 +//! DATE: 2021-03-26, STEPS: [50, ], REPEAT: 20 +//! LOW RANGE: [], HIGH RANGE: [] +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled +//! CHAIN: Some("dev"), DB CACHE: 128 + +// Executed Command: +// ./target/release/rialto-bridge-node +// benchmark +// --chain +// dev +// --execution +// wasm +// --extrinsic +// * +// --pallet +// pallet_bridge_grandpa +// --wasm-execution +// compiled +// --steps +// 50 +// --repeat +// 20 +// --template +// ./.maintain/rialto-weight-template.hbs +// --output +// ./grandpa-template.txt +// --raw + +#![allow(clippy::all)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{ + traits::Get, + weights::{constants::RocksDbWeight, Weight}, +}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_bridge_grandpa. +pub trait WeightInfo { + fn submit_finality_proof(s: u32, p: u32) -> Weight; + fn submit_finality_proof_on_single_fork(s: u32) -> Weight; + fn submit_finality_proof_on_many_forks(p: u32) -> Weight; + fn find_scheduled_change(n: u32) -> Weight; + fn read_write_authority_sets(n: u32) -> Weight; + fn write_authority_sets(n: u32) -> Weight; +} + +/// Weights for pallet_bridge_grandpa using the Rialto node and recommended hardware. +pub struct RialtoWeight(PhantomData); +impl WeightInfo for RialtoWeight { + fn submit_finality_proof(s: u32, p: u32) -> Weight { + (0 as Weight) + .saturating_add((3_248_661_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((776_552_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + fn submit_finality_proof_on_single_fork(s: u32) -> Weight { + (189_213_000 as Weight) + .saturating_add((12_937_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + fn submit_finality_proof_on_many_forks(p: u32) -> Weight { + (0 as Weight) + .saturating_add((138_751_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + fn find_scheduled_change(n: u32) -> Weight { + (301_000 as Weight).saturating_add((10_000 as Weight).saturating_mul(n as Weight)) + } + fn read_write_authority_sets(n: u32) -> Weight { + (6_787_000 as Weight) + .saturating_add((247_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + fn write_authority_sets(n: u32) -> Weight { + (3_383_000 as Weight) + .saturating_add((99_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + fn submit_finality_proof(s: u32, p: u32) -> Weight { + (0 as Weight) + .saturating_add((3_248_661_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((776_552_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + fn submit_finality_proof_on_single_fork(s: u32) -> Weight { + (189_213_000 as Weight) + .saturating_add((12_937_000 as Weight).saturating_mul(s as Weight)) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + fn submit_finality_proof_on_many_forks(p: u32) -> Weight { + (0 as Weight) + .saturating_add((138_751_000 as Weight).saturating_mul(p as Weight)) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + fn find_scheduled_change(n: u32) -> Weight { + (301_000 as Weight).saturating_add((10_000 as Weight).saturating_mul(n as Weight)) + } + fn read_write_authority_sets(n: u32) -> Weight { + (6_787_000 as Weight) + .saturating_add((247_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + fn write_authority_sets(n: u32) -> Weight { + (3_383_000 as Weight) + .saturating_add((99_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } +} diff --git a/bridges/primitives/chain-millau/src/lib.rs b/bridges/primitives/chain-millau/src/lib.rs index a8fa00af3f..28ad3a3881 100644 --- a/bridges/primitives/chain-millau/src/lib.rs +++ b/bridges/primitives/chain-millau/src/lib.rs @@ -95,7 +95,11 @@ pub const ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT: Weight = 25_000; /// runtime upgrades. pub const MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT: Weight = 2_000_000_000; -/// The length of a session (how often authorities change) on Millau measured in of number of blocks. +/// The target length of a session (how often authorities change) on Millau measured in of number of +/// blocks. +/// +/// Note that since this is a target sessions may change before/after this time depending on network +/// conditions. pub const SESSION_LENGTH: BlockNumber = 5 * time_units::MINUTES; /// Re-export `time_units` to make usage easier. diff --git a/bridges/primitives/chain-rialto/src/lib.rs b/bridges/primitives/chain-rialto/src/lib.rs index b373bbe9a0..f85e239fbe 100644 --- a/bridges/primitives/chain-rialto/src/lib.rs +++ b/bridges/primitives/chain-rialto/src/lib.rs @@ -86,7 +86,11 @@ pub const ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT: Weight = 25_000; /// runtime upgrades. pub const MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT: Weight = 2_000_000_000; -/// The length of a session (how often authorities change) on Rialto measured in of number of blocks. +/// The target length of a session (how often authorities change) on Rialto measured in of number of +/// blocks. +/// +/// Note that since this is a target sessions may change before/after this time depending on network +/// conditions. pub const SESSION_LENGTH: BlockNumber = 4; /// Re-export `time_units` to make usage easier. diff --git a/bridges/primitives/chain-westend/src/lib.rs b/bridges/primitives/chain-westend/src/lib.rs index 0587e76125..c4f4b0b644 100644 --- a/bridges/primitives/chain-westend/src/lib.rs +++ b/bridges/primitives/chain-westend/src/lib.rs @@ -69,6 +69,13 @@ pub const FROM_WESTEND_LATEST_CONFIRMED_NONCE_METHOD: &str = "FromWestendInbound /// Name of the `FromWestendInboundLaneApi::unrewarded_relayers_state` runtime method. pub const FROM_WESTEND_UNREWARDED_RELAYERS_STATE: &str = "FromWestendInboundLaneApi_unrewarded_relayers_state"; +/// The target length of a session (how often authorities change) on Westend measured in of number of +/// blocks. +/// +/// Note that since this is a target sessions may change before/after this time depending on network +/// conditions. +pub const SESSION_LENGTH: BlockNumber = 10 * time_units::MINUTES; + sp_api::decl_runtime_apis! { /// API for querying information about the finalized Westend headers. /// diff --git a/bridges/primitives/polkadot-core/src/lib.rs b/bridges/primitives/polkadot-core/src/lib.rs index eaeddfa2af..94e9dda903 100644 --- a/bridges/primitives/polkadot-core/src/lib.rs +++ b/bridges/primitives/polkadot-core/src/lib.rs @@ -136,6 +136,21 @@ pub const MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE: MessageNonce = 128; /// Maximal number of unconfirmed messages at inbound lane. pub const MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE: MessageNonce = 8192; +/// Re-export `time_units` to make usage easier. +pub use time_units::*; + +/// Human readable time units defined in terms of number of blocks. +pub mod time_units { + use super::BlockNumber; + + pub const MILLISECS_PER_BLOCK: u64 = 6000; + pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; + + pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); + pub const HOURS: BlockNumber = MINUTES * 60; + pub const DAYS: BlockNumber = HOURS * 24; +} + /// Block number type used in Polkadot-like chains. pub type BlockNumber = u32; diff --git a/bridges/primitives/test-utils/src/keyring.rs b/bridges/primitives/test-utils/src/keyring.rs index 5b96b98a3a..fbc1496e16 100644 --- a/bridges/primitives/test-utils/src/keyring.rs +++ b/bridges/primitives/test-utils/src/keyring.rs @@ -21,6 +21,7 @@ use finality_grandpa::voter_set::VoterSet; use sp_application_crypto::Public; use sp_finality_grandpa::{AuthorityId, AuthorityList, AuthorityWeight}; use sp_runtime::RuntimeDebug; +use sp_std::prelude::*; /// Set of test accounts with friendly names. pub const ALICE: Account = Account(0);