Use Vote Ancestries Directly in Weight Calculations (#862)

* Use more accurate weight calculation in declared weight

* Remove session length and validator set size config constants

* Remove config params from mock

* Allow specifying total number of votes-ancestries per justification

* Change limits used during benchmarking

* Regenerate weights

* Use simplified weight annotation

* Remove comment

* Address leftover TODO

* Prevent possible divide by zero errors

* Use correct argument order in weight declaration
This commit is contained in:
Hernando Castano
2021-04-05 12:36:29 -04:00
committed by Bastian Köcher
parent 0d7291d729
commit 1928e2b870
8 changed files with 90 additions and 112 deletions
+20 -10
View File
@@ -51,13 +51,23 @@ use bp_test_utils::{
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};
// The maximum number of vote ancestries to include in a justification.
//
// In practice this would be limited by the session length (number of blocks a single authority set
// can produce) of a given chain.
const MAX_VOTE_ANCESTRIES: u32 = 1000;
// The maximum number of pre-commits to include in a justification. In practice this scales with the
// number of validators.
//
// TODO [#846]: Right now this will break benchmarking if it is greater than `u8::MAX`
const MAX_VALIDATOR_SET_SIZE: u32 = 255;
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.
@@ -65,8 +75,8 @@ benchmarks_instance_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 v in 1..MAX_VOTE_ANCESTRIES;
let p in 1..MAX_VALIDATOR_SET_SIZE;
let caller: T::AccountId = whitelisted_caller();
@@ -90,8 +100,8 @@ benchmarks_instance_pallet! {
round: TEST_GRANDPA_ROUND,
set_id: TEST_GRANDPA_SET_ID,
authorities: accounts(p as u8).iter().map(|k| (*k, 1)).collect::<Vec<_>>(),
depth: s,
forks: p,
votes: v,
forks: 1,
};
let justification = make_justification_for_header(params);
@@ -108,7 +118,7 @@ benchmarks_instance_pallet! {
// 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 v in 1..MAX_VOTE_ANCESTRIES;
let caller: T::AccountId = whitelisted_caller();
@@ -127,7 +137,7 @@ benchmarks_instance_pallet! {
round: TEST_GRANDPA_ROUND,
set_id: TEST_GRANDPA_SET_ID,
authorities: test_keyring(),
depth: s,
votes: v,
forks: 1,
};
@@ -146,7 +156,7 @@ benchmarks_instance_pallet! {
// 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 p in 1..MAX_VALIDATOR_SET_SIZE;
let caller: T::AccountId = whitelisted_caller();
@@ -170,7 +180,7 @@ benchmarks_instance_pallet! {
round: TEST_GRANDPA_ROUND,
set_id: TEST_GRANDPA_SET_ID,
authorities: accounts(p as u8).iter().map(|k| (*k, 1)).collect::<Vec<_>>(),
depth: 2,
votes: p,
forks: p,
};
+3 -33
View File
@@ -44,7 +44,6 @@ 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};
@@ -92,27 +91,6 @@ pub mod pallet {
#[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;
}
@@ -141,8 +119,8 @@ pub mod pallet {
/// If successful in verification, it will write the target header to the underlying storage
/// pallet.
#[pallet::weight(T::WeightInfo::submit_finality_proof(
T::MaxBridgedSessionLength::get().as_() as u32,
T::MaxBridgedValidatorCount::get(),
justification.votes_ancestries.len() as u32,
justification.commit.precommits.len() as u32,
))]
pub fn submit_finality_proof(
origin: OriginFor<T>,
@@ -181,15 +159,7 @@ pub mod pallet {
log::info!(target: "runtime::bridge-grandpa", "Succesfully imported finalized header with hash {:?}!", hash);
// 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())
Ok(().into())
}
/// Bootstrap the bridge pallet with an initial header and authority set from which to sync.
-2
View File
@@ -87,8 +87,6 @@ parameter_types! {
impl grandpa::Config for TestRuntime {
type BridgedChain = TestBridgedChain;
type MaxRequests = MaxRequests;
type MaxBridgedSessionLength = SessionLength;
type MaxBridgedValidatorCount = NumValidators;
type WeightInfo = ();
}
+24 -35
View File
@@ -1,4 +1,4 @@
// Copyright 2021 Parity Technologies (UK) Ltd.
// 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
@@ -17,7 +17,7 @@
//! 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
//! DATE: 2021-04-02, STEPS: [50, ], REPEAT: 20
//! LOW RANGE: [], HIGH RANGE: []
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled
//! CHAIN: Some("dev"), DB CACHE: 128
@@ -57,85 +57,74 @@ 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(v: u32, p: u32) -> Weight;
fn submit_finality_proof_on_single_fork(v: 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<T>(PhantomData<T>);
impl<T: frame_system::Config> WeightInfo for RialtoWeight<T> {
fn submit_finality_proof(s: u32, p: u32) -> Weight {
fn submit_finality_proof(v: 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((160_060_000 as Weight).saturating_mul(v as Weight))
.saturating_add((640_223_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))
fn submit_finality_proof_on_single_fork(v: u32) -> Weight {
(189_597_000 as Weight)
.saturating_add((11_680_000 as Weight).saturating_mul(v 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((130_061_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))
(502_000 as Weight).saturating_add((8_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))
(7_677_000 as Weight)
.saturating_add((230_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 {
fn submit_finality_proof(v: 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((160_060_000 as Weight).saturating_mul(v as Weight))
.saturating_add((640_223_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))
fn submit_finality_proof_on_single_fork(v: u32) -> Weight {
(189_597_000 as Weight)
.saturating_add((11_680_000 as Weight).saturating_mul(v 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((130_061_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))
(502_000 as Weight).saturating_add((8_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))
(7_677_000 as Weight)
.saturating_add((230_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))
}
}