Skip to content

Commit

Permalink
Fix offchain election to respect the weight (paritytech#7215)
Browse files Browse the repository at this point in the history
* Mockup

* Fix offchain election to respect the weight

* Fix builds a bit

* Update frame/staking/src/offchain_election.rs

Co-authored-by: Shawn Tabrizi <[email protected]>

* Update frame/staking/src/offchain_election.rs

Co-authored-by: Shawn Tabrizi <[email protected]>

* Make it build, binary search

* Fix a number of grumbles

* one more fix.

* remove unwrap.

* better alg.

* Better alg again.

* Final fixes

* Fix

* Rollback to normal

* Final touches.

* Better tests.

* Update frame/staking/src/lib.rs

Co-authored-by: Guillaume Thiolliere <[email protected]>

* Proper maxExtWeight

* Final fix

* Final fix for the find_voter

Co-authored-by: Shawn Tabrizi <[email protected]>
Co-authored-by: Guillaume Thiolliere <[email protected]>
  • Loading branch information
3 people authored and liuchengxu committed Oct 5, 2020
1 parent 5d856a2 commit 5378863
Show file tree
Hide file tree
Showing 16 changed files with 585 additions and 82 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ rls*.log
**/hfuzz_target/
**/hfuzz_workspace/
.cargo/
.cargo-remote.toml
15 changes: 10 additions & 5 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@
#![cfg_attr(not(feature = "std"), no_std)]
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
#![recursion_limit="256"]
#![recursion_limit = "256"]

use sp_std::prelude::*;

use sp_std::prelude::*;
use frame_support::{
construct_runtime, parameter_types, debug, RuntimeDebug,
weights::{
Expand Down Expand Up @@ -149,9 +149,8 @@ parameter_types! {
pub const MaximumBlockWeight: Weight = 2 * WEIGHT_PER_SECOND;
pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
/// Assume 10% of weight for average on_initialize calls.
pub MaximumExtrinsicWeight: Weight =
AvailableBlockRatio::get().saturating_sub(AVERAGE_ON_INITIALIZE_WEIGHT)
* MaximumBlockWeight::get();
pub MaximumExtrinsicWeight: Weight = AvailableBlockRatio::get().saturating_sub(AVERAGE_ON_INITIALIZE_WEIGHT)
* MaximumBlockWeight::get();
pub const MaximumBlockLength: u32 = 5 * 1024 * 1024;
pub const Version: RuntimeVersion = VERSION;
}
Expand Down Expand Up @@ -443,6 +442,9 @@ parameter_types! {
pub const MaxIterations: u32 = 10;
// 0.05%. The higher the value, the more strict solution acceptance becomes.
pub MinSolutionScoreBump: Perbill = Perbill::from_rational_approximation(5u32, 10_000);
pub OffchainSolutionWeightLimit: Weight = MaximumExtrinsicWeight::get()
.saturating_sub(BlockExecutionWeight::get())
.saturating_sub(ExtrinsicBaseWeight::get());
}

impl pallet_staking::Trait for Runtime {
Expand Down Expand Up @@ -471,6 +473,9 @@ impl pallet_staking::Trait for Runtime {
type MinSolutionScoreBump = MinSolutionScoreBump;
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
type UnsignedPriority = StakingUnsignedPriority;
// The unsigned solution weight targeted by the OCW. We set it to the maximum possible value of
// a single extrinsic.
type OffchainSolutionWeightLimit = OffchainSolutionWeightLimit;
type WeightInfo = weights::pallet_staking::WeightInfo<Runtime>;
}

Expand Down
1 change: 1 addition & 0 deletions frame/babe/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ impl pallet_staking::Trait for Test {
type UnsignedPriority = StakingUnsignedPriority;
type MaxIterations = ();
type MinSolutionScoreBump = ();
type OffchainSolutionWeightLimit = ();
type WeightInfo = ();
}

Expand Down
1 change: 1 addition & 0 deletions frame/grandpa/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ impl pallet_staking::Trait for Test {
type UnsignedPriority = StakingUnsignedPriority;
type MaxIterations = ();
type MinSolutionScoreBump = ();
type OffchainSolutionWeightLimit = ();
type WeightInfo = ();
}

Expand Down
1 change: 1 addition & 0 deletions frame/offences/benchmarking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ impl pallet_staking::Trait for Test {
type UnsignedPriority = ();
type MaxIterations = ();
type MinSolutionScoreBump = ();
type OffchainSolutionWeightLimit = ();
type WeightInfo = ();
}

Expand Down
1 change: 1 addition & 0 deletions frame/session/benchmarking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ impl pallet_staking::Trait for Test {
type UnsignedPriority = UnsignedPriority;
type MaxIterations = ();
type MinSolutionScoreBump = ();
type OffchainSolutionWeightLimit = ();
type WeightInfo = ();
}

Expand Down
1 change: 1 addition & 0 deletions frame/staking/fuzzer/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,5 +201,6 @@ impl pallet_staking::Trait for Test {
type MinSolutionScoreBump = ();
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
type UnsignedPriority = ();
type OffchainSolutionWeightLimit = ();
type WeightInfo = ();
}
4 changes: 2 additions & 2 deletions frame/staking/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,7 @@ benchmarks! {
compact,
score,
size
) = offchain_election::prepare_submission::<T>(assignments, winners, false).unwrap();
) = offchain_election::prepare_submission::<T>(assignments, winners, false, T::MaximumBlockWeight::get()).unwrap();

assert_eq!(
winners.len(), compact.unique_targets().len(),
Expand Down Expand Up @@ -590,7 +590,7 @@ benchmarks! {
compact,
score,
size
) = offchain_election::prepare_submission::<T>(assignments, winners, false).unwrap();
) = offchain_election::prepare_submission::<T>(assignments, winners, false, T::MaximumBlockWeight::get()).unwrap();

assert_eq!(
winners.len(), compact.unique_targets().len(),
Expand Down
24 changes: 16 additions & 8 deletions frame/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,7 @@ pub enum ElectionStatus<BlockNumber> {
/// Note that these values must reflect the __total__ number, not only those that are present in the
/// solution. In short, these should be the same size as the size of the values dumped in
/// `SnapshotValidators` and `SnapshotNominators`.
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default)]
#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug, Default)]
pub struct ElectionSize {
/// Number of validators in the snapshot of the current election round.
#[codec(compact)]
Expand Down Expand Up @@ -883,6 +883,13 @@ pub trait Trait: frame_system::Trait + SendTransactionTypes<Call<Self>> {
/// multiple pallets send unsigned transactions.
type UnsignedPriority: Get<TransactionPriority>;

/// Maximum weight that the unsigned transaction can have.
///
/// Chose this value with care. On one hand, it should be as high as possible, so the solution
/// can contain as many nominators/validators as possible. On the other hand, it should be small
/// enough to fit in the block.
type OffchainSolutionWeightLimit: Get<Weight>;

/// Weight information for extrinsics in this pallet.
type WeightInfo: WeightInfo;
}
Expand Down Expand Up @@ -1294,6 +1301,7 @@ decl_module! {
consumed_weight += T::DbWeight::get().reads_writes(reads, writes);
consumed_weight += weight;
};

if
// if we don't have any ongoing offchain compute.
Self::era_election_status().is_closed() &&
Expand Down Expand Up @@ -1339,12 +1347,12 @@ decl_module! {
if Self::era_election_status().is_open_at(now) {
let offchain_status = set_check_offchain_execution_status::<T>(now);
if let Err(why) = offchain_status {
log!(debug, "skipping offchain worker in open election window due to [{}]", why);
log!(warn, "💸 skipping offchain worker in open election window due to [{}]", why);
} else {
if let Err(e) = compute_offchain_election::<T>() {
log!(error, "💸 Error in election offchain worker: {:?}", e);
} else {
log!(debug, "Executed offchain worker thread without errors.");
log!(debug, "💸 Executed offchain worker thread without errors.");
}
}
}
Expand Down Expand Up @@ -2141,7 +2149,7 @@ decl_module! {
/// transaction in the block.
///
/// # <weight>
/// See `crate::weight` module.
/// See [`submit_election_solution`].
/// # </weight>
#[weight = T::WeightInfo::submit_solution_better(
size.validators.into(),
Expand Down Expand Up @@ -2171,6 +2179,7 @@ decl_module! {
effectively depriving the validators from their authoring reward. Hence, this panic
is expected."
);

Ok(adjustments)
}
}
Expand Down Expand Up @@ -3082,7 +3091,6 @@ impl<T: Trait> Module<T> {
pub fn set_slash_reward_fraction(fraction: Perbill) {
SlashRewardFraction::put(fraction);
}

}

/// In this implementation `new_session(session)` must be called before `end_session(session-1)`
Expand Down Expand Up @@ -3374,13 +3382,13 @@ impl<T: Trait> frame_support::unsigned::ValidateUnsigned for Module<T> {
let invalid = to_invalid(error_with_post_info);
log!(
debug,
"validate unsigned pre dispatch checks failed due to error #{:?}.",
"💸 validate unsigned pre dispatch checks failed due to error #{:?}.",
invalid,
);
return invalid .into();
return invalid.into();
}

log!(debug, "validateUnsigned succeeded for a solution at era {}.", era);
log!(debug, "💸 validateUnsigned succeeded for a solution at era {}.", era);

ValidTransaction::with_tag_prefix("StakingOffchain")
// The higher the score[0], the better a solution is.
Expand Down
38 changes: 23 additions & 15 deletions frame/staking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,29 @@

//! Test utilities
use std::{collections::HashSet, cell::RefCell};
use sp_runtime::Perbill;
use sp_runtime::curve::PiecewiseLinear;
use sp_runtime::traits::{IdentityLookup, Convert, SaturatedConversion, Zero};
use sp_runtime::testing::{Header, UintAuthorityId, TestXt};
use sp_staking::{SessionIndex, offence::{OffenceDetails, OnOffenceHandler}};
use sp_core::H256;
use crate::*;
use frame_support::{
assert_ok, impl_outer_origin, parameter_types, impl_outer_dispatch, impl_outer_event,
StorageValue, StorageMap, StorageDoubleMap, IterableStorageMap,
traits::{Currency, Get, FindAuthor, OnFinalize, OnInitialize},
weights::{Weight, constants::RocksDbWeight},
assert_ok, impl_outer_dispatch, impl_outer_event, impl_outer_origin, parameter_types,
traits::{Currency, FindAuthor, Get, OnFinalize, OnInitialize},
weights::{constants::RocksDbWeight, Weight},
IterableStorageMap, StorageDoubleMap, StorageMap, StorageValue,
};
use sp_core::H256;
use sp_io;
use sp_npos_elections::{
build_support_map, evaluate_support, reduce, ExtendedBalance, StakedAssignment, ElectionScore,
build_support_map, evaluate_support, reduce, ElectionScore, ExtendedBalance, StakedAssignment,
};
use crate::*;
use sp_runtime::{
curve::PiecewiseLinear,
testing::{Header, TestXt, UintAuthorityId},
traits::{Convert, IdentityLookup, SaturatedConversion, Zero},
Perbill,
};
use sp_staking::{
offence::{OffenceDetails, OnOffenceHandler},
SessionIndex,
};
use std::{cell::RefCell, collections::HashSet};

pub const INIT_TIMESTAMP: u64 = 30_000;

Expand Down Expand Up @@ -194,7 +199,7 @@ pub struct Test;

parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const MaximumBlockWeight: Weight = 1024;
pub const MaximumBlockWeight: Weight = frame_support::weights::constants::WEIGHT_PER_SECOND * 2;
pub const MaximumBlockLength: u32 = 2 * 1024;
pub const AvailableBlockRatio: Perbill = Perbill::one();
pub const MaxLocks: u32 = 1024;
Expand Down Expand Up @@ -297,6 +302,7 @@ parameter_types! {
pub const MaxNominatorRewardedPerValidator: u32 = 64;
pub const UnsignedPriority: u64 = 1 << 20;
pub const MinSolutionScoreBump: Perbill = Perbill::zero();
pub const OffchainSolutionWeightLimit: Weight = MaximumBlockWeight::get();
}

thread_local! {
Expand Down Expand Up @@ -335,10 +341,12 @@ impl Trait for Test {
type MinSolutionScoreBump = MinSolutionScoreBump;
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
type UnsignedPriority = UnsignedPriority;
type OffchainSolutionWeightLimit = OffchainSolutionWeightLimit;
type WeightInfo = ();
}

impl<LocalCall> frame_system::offchain::SendTransactionTypes<LocalCall> for Test where
impl<LocalCall> frame_system::offchain::SendTransactionTypes<LocalCall> for Test
where
Call: From<LocalCall>,
{
type OverarchingCall = Call;
Expand Down
Loading

0 comments on commit 5378863

Please sign in to comment.