mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 23:21:02 +00:00
Weights for pallet-bridge-grandpa (#815)
* Add benchmarking skeleton * Allow runtime to indicate concrete header type for benches * Set up skeleton for benchmark tests * Play around with mutating bench header * Create a working test for benchmarking * Add benches related to enacting authority set changes * Add bench for checking effect of prec-commits/vote ancestries * Use new `no_std` test utils in benchmarks * Support pallet instances in benchmarking * Use correct benchmarking instance macro * Add instance to runtime benchmark helper impl * Start using new justification creation API * Allow mock header's number to be specified * Set up benches with correct fork/depth parameters * Use new pallet name during runtime bench setup * Use correct `set_id` in tests * Limit number of forks as workaround to get tests passing * Use number of authorities which matches number of forks * Make sure test post-conditions are checked properly * Only read `CurrentAuthoritySet` from storage once * Add combined benchmark for `submit_finality_proof` * Add bench test * Introduce config bounds related to justification verification * Use config consts from pallet in benchmarking * Return data relevant to benchmarks from helper functions * Annotate `submit_finality_proof` with autogenerated weights * Return actual weight after call execution * Ignore Clippy warnings in bench template * Update benchmark template * Use `test-utils` to create test headers * Clarify that helper is only for messages benches * Add more documentation to benches * Update TODOs * Clarify return types in comment * Fix pallet name post-merge * Update NOTE to a TODO item * Indicate that Config params are max values, not actual values * Change Config validator count type to be `u32` * Return decoded justification instead of fields * Add missing trait bounds for tests * Correctly issue weight refund Thanks for spotting this Tomek! * Update comment * Add note about SESSION_LENGTH * Fix benchmarking code
This commit is contained in:
committed by
Bastian Köcher
parent
67cdca8aa4
commit
025a9cad59
@@ -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<u32>;
|
||||
|
||||
/// 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<BridgedBlockNumber<Self, I>>;
|
||||
|
||||
/// 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<u32>;
|
||||
|
||||
/// 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<T>,
|
||||
finality_target: BridgedHeader<T, I>,
|
||||
@@ -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, <Error<T, I>>::OldHeader);
|
||||
|
||||
verify_justification::<T, I>(&justification, hash, *number)?;
|
||||
let authority_set = <CurrentAuthoritySet<T, I>>::get();
|
||||
let set_id = authority_set.set_id;
|
||||
verify_justification::<T, I>(&justification, hash, *number, authority_set)?;
|
||||
|
||||
try_enact_authority_change::<T, I>(&finality_target)?;
|
||||
let _enacted = try_enact_authority_change::<T, I>(&finality_target, set_id)?;
|
||||
<BestFinalized<T, I>>::put(hash);
|
||||
<ImportedHeaders<T, I>>::insert(hash, finality_target);
|
||||
<RequestCount<T, I>>::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<T: Config<I>, I: 'static>(
|
||||
header: &BridgedHeader<T, I>,
|
||||
) -> Result<(), sp_runtime::DispatchError> {
|
||||
current_set_id: sp_finality_grandpa::SetId,
|
||||
) -> Result<bool, sp_runtime::DispatchError> {
|
||||
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(), <Error<T, I>>::UnsupportedScheduledChange);
|
||||
|
||||
let current_set_id = <CurrentAuthoritySet<T, I>>::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.
|
||||
<CurrentAuthoritySet<T, I>>::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<T: Config<I>, I: 'static>(
|
||||
justification: &GrandpaJustification<BridgedHeader<T, I>>,
|
||||
hash: BridgedBlockHash<T, I>,
|
||||
number: BridgedBlockNumber<T, I>,
|
||||
authority_set: bp_header_chain::AuthoritySet,
|
||||
) -> Result<(), sp_runtime::DispatchError> {
|
||||
use bp_header_chain::justification::verify_justification;
|
||||
|
||||
let authority_set = <CurrentAuthoritySet<T, I>>::get();
|
||||
let voter_set = VoterSet::new(authority_set.authorities).ok_or(<Error<T, I>>::InvalidAuthoritySet)?;
|
||||
let set_id = authority_set.set_id;
|
||||
|
||||
@@ -510,7 +564,7 @@ pub(crate) fn find_forced_change<H: HeaderT>(
|
||||
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<T: Config<I>, I: 'static>(header: BridgedHeader<T, I>) {
|
||||
initialize_bridge::<T, I>(InitializationData {
|
||||
|
||||
Reference in New Issue
Block a user