Run cargo fmt on the whole code base (#9394)

* Run cargo fmt on the whole code base

* Second run

* Add CI check

* Fix compilation

* More unnecessary braces

* Handle weights

* Use --all

* Use correct attributes...

* Fix UI tests

* AHHHHHHHHH

* 🤦

* Docs

* Fix compilation

* 🤷

* Please stop

* 🤦 x 2

* More

* make rustfmt.toml consistent with polkadot

Co-authored-by: André Silva <andrerfosilva@gmail.com>
This commit is contained in:
Bastian Köcher
2021-07-21 16:32:32 +02:00
committed by GitHub
parent d451c38c1c
commit 7b56ab15b4
1010 changed files with 53339 additions and 51208 deletions
@@ -18,7 +18,7 @@
//! Two phase election pallet benchmarking.
use super::*;
use crate::{Pallet as MultiPhase, unsigned::IndexAssignmentOf};
use crate::{unsigned::IndexAssignmentOf, Pallet as MultiPhase};
use frame_benchmarking::{account, impl_benchmark_test_suite};
use frame_support::{assert_ok, traits::Hooks};
use frame_system::RawOrigin;
@@ -53,8 +53,9 @@ fn solution_with_size<T: Config>(
let stake: VoteWeight = ed.max(One::one()).saturating_mul(100);
// first generates random targets.
let targets: Vec<T::AccountId> =
(0..size.targets).map(|i| frame_benchmarking::account("Targets", i, SEED)).collect();
let targets: Vec<T::AccountId> = (0..size.targets)
.map(|i| frame_benchmarking::account("Targets", i, SEED))
.collect();
let mut rng = SmallRng::seed_from_u64(SEED.into());
@@ -80,8 +81,11 @@ fn solution_with_size<T: Config>(
.collect::<Vec<_>>();
// rest of the voters. They can only vote for non-winners.
let non_winners =
targets.iter().filter(|t| !winners.contains(t)).cloned().collect::<Vec<T::AccountId>>();
let non_winners = targets
.iter()
.filter(|t| !winners.contains(t))
.cloned()
.collect::<Vec<T::AccountId>>();
let rest_voters = (active_voters_count..size.voters)
.map(|i| {
let votes = (&non_winners)
@@ -147,14 +151,22 @@ fn set_up_data_provider<T: Config>(v: u32, t: u32) {
// number of votes in snapshot.
T::DataProvider::clear();
log!(info, "setting up with voters = {} [degree = {}], targets = {}", v, T::DataProvider::MAXIMUM_VOTES_PER_VOTER, t);
log!(
info,
"setting up with voters = {} [degree = {}], targets = {}",
v,
T::DataProvider::MAXIMUM_VOTES_PER_VOTER,
t
);
// fill targets.
let mut targets = (0..t).map(|i| {
let target = frame_benchmarking::account::<T::AccountId>("Target", i, SEED);
T::DataProvider::add_target(target.clone());
target
}).collect::<Vec<_>>();
let mut targets = (0..t)
.map(|i| {
let target = frame_benchmarking::account::<T::AccountId>("Target", i, SEED);
T::DataProvider::add_target(target.clone());
target
})
.collect::<Vec<_>>();
// we should always have enough voters to fill.
assert!(targets.len() > T::DataProvider::MAXIMUM_VOTES_PER_VOTER as usize);
targets.truncate(T::DataProvider::MAXIMUM_VOTES_PER_VOTER as usize);
@@ -17,7 +17,7 @@
//! Some helper functions/macros for this crate.
use super::{Config, VoteWeight, CompactVoterIndexOf, CompactTargetIndexOf};
use super::{CompactTargetIndexOf, CompactVoterIndexOf, Config, VoteWeight};
use sp_std::{collections::btree_map::BTreeMap, convert::TryInto, prelude::*};
#[macro_export]
@@ -58,7 +58,9 @@ pub fn voter_index_fn<T: Config>(
cache: &BTreeMap<T::AccountId, usize>,
) -> impl Fn(&T::AccountId) -> Option<CompactVoterIndexOf<T>> + '_ {
move |who| {
cache.get(who).and_then(|i| <usize as TryInto<CompactVoterIndexOf<T>>>::try_into(*i).ok())
cache
.get(who)
.and_then(|i| <usize as TryInto<CompactVoterIndexOf<T>>>::try_into(*i).ok())
}
}
@@ -70,7 +72,9 @@ pub fn voter_index_fn_owned<T: Config>(
cache: BTreeMap<T::AccountId, usize>,
) -> impl Fn(&T::AccountId) -> Option<CompactVoterIndexOf<T>> {
move |who| {
cache.get(who).and_then(|i| <usize as TryInto<CompactVoterIndexOf<T>>>::try_into(*i).ok())
cache
.get(who)
.and_then(|i| <usize as TryInto<CompactVoterIndexOf<T>>>::try_into(*i).ok())
}
}
@@ -173,7 +177,11 @@ pub fn stake_of_fn_linear<T: Config>(
snapshot: &Vec<(T::AccountId, VoteWeight, Vec<T::AccountId>)>,
) -> impl Fn(&T::AccountId) -> VoteWeight + '_ {
move |who| {
snapshot.iter().find(|(x, _, _)| x == who).map(|(_, x, _)| *x).unwrap_or_default()
snapshot
.iter()
.find(|(x, _, _)| x == who)
.map(|(_, x, _)| *x)
.unwrap_or_default()
}
}
@@ -48,7 +48,7 @@
//!
//! ### Signed Phase
//!
//! In the signed phase, solutions (of type [`RawSolution`]) are submitted and queued on chain. A
//! In the signed phase, solutions (of type [`RawSolution`]) are submitted and queued on chain. A
//! deposit is reserved, based on the size of the solution, for the cost of keeping this solution
//! on-chain for a number of blocks, and the potential weight of the solution upon being checked. A
//! maximum of `pallet::Config::MaxSignedSubmissions` solutions are stored. The queue is always
@@ -228,34 +228,31 @@
#![cfg_attr(not(feature = "std"), no_std)]
use codec::{Decode, Encode};
use frame_election_provider_support::{onchain, ElectionDataProvider, ElectionProvider};
use frame_support::{
dispatch::DispatchResultWithPostInfo,
ensure,
traits::{Currency, Get, ReservableCurrency, OnUnbalanced},
traits::{Currency, Get, OnUnbalanced, ReservableCurrency},
weights::Weight,
};
use frame_system::{ensure_none, offchain::SendTransactionTypes};
use frame_election_provider_support::{ElectionDataProvider, ElectionProvider, onchain};
use sp_arithmetic::{
traits::{CheckedAdd, Zero},
UpperOf,
};
use sp_npos_elections::{
assignment_ratio_to_staked_normalized, CompactSolution, ElectionScore,
EvaluateSupport, PerThing128, Supports, VoteWeight,
assignment_ratio_to_staked_normalized, CompactSolution, ElectionScore, EvaluateSupport,
PerThing128, Supports, VoteWeight,
};
use sp_runtime::{
traits::Bounded,
transaction_validity::{
InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity,
TransactionValidityError, ValidTransaction,
},
DispatchError, PerThing, Perbill, RuntimeDebug, SaturatedConversion,
traits::Bounded,
};
use sp_std::{
convert::TryInto,
prelude::*,
};
use sp_arithmetic::{
UpperOf,
traits::{Zero, CheckedAdd},
};
use sp_std::{convert::TryInto, prelude::*};
#[cfg(any(feature = "runtime-benchmarks", test))]
mod benchmarking;
@@ -562,7 +559,9 @@ pub mod pallet {
#[pallet::config]
pub trait Config: frame_system::Config + SendTransactionTypes<Call<Self>> {
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event> + TryInto<Event<Self>>;
type Event: From<Event<Self>>
+ IsType<<Self as frame_system::Config>::Event>
+ TryInto<Event<Self>>;
/// Currency type.
type Currency: ReservableCurrency<Self::AccountId> + Currency<Self::AccountId>;
@@ -701,21 +700,22 @@ pub mod pallet {
Ok(snap_weight) => {
log!(info, "Starting signed phase round {}.", Self::round());
T::WeightInfo::on_initialize_open_signed().saturating_add(snap_weight)
}
},
Err(why) => {
// Not much we can do about this at this point.
log!(warn, "failed to open signed phase due to {:?}", why);
T::WeightInfo::on_initialize_nothing()
// NOTE: ^^ The trait specifies that this is a noop in terms of weight
// in case of error.
}
},
}
}
},
Phase::Signed | Phase::Off
if remaining <= unsigned_deadline && remaining > Zero::zero() =>
{
// our needs vary according to whether or not the unsigned phase follows a signed phase
let (need_snapshot, enabled, signed_weight) = if current_phase == Phase::Signed {
let (need_snapshot, enabled, signed_weight) = if current_phase == Phase::Signed
{
// there was previously a signed phase: close the signed phase, no need for snapshot.
//
// Notes:
@@ -744,14 +744,14 @@ pub mod pallet {
};
base_weight.saturating_add(snap_weight).saturating_add(signed_weight)
}
},
Err(why) => {
// Not much we can do about this at this point.
log!(warn, "failed to open unsigned phase due to {:?}", why);
T::WeightInfo::on_initialize_nothing()
// NOTE: ^^ The trait specifies that this is a noop in terms of weight
// in case of error.
}
},
}
}
_ => T::WeightInfo::on_initialize_nothing(),
@@ -759,15 +759,16 @@ pub mod pallet {
}
fn offchain_worker(now: T::BlockNumber) {
use sp_runtime::offchain::storage_lock::{StorageLock, BlockAndTime};
use sp_runtime::offchain::storage_lock::{BlockAndTime, StorageLock};
// Create a lock with the maximum deadline of number of blocks in the unsigned phase.
// This should only come useful in an **abrupt** termination of execution, otherwise the
// guard will be dropped upon successful execution.
let mut lock = StorageLock::<BlockAndTime<frame_system::Pallet::<T>>>::with_block_deadline(
unsigned::OFFCHAIN_LOCK,
T::UnsignedPhase::get().saturated_into(),
);
let mut lock =
StorageLock::<BlockAndTime<frame_system::Pallet<T>>>::with_block_deadline(
unsigned::OFFCHAIN_LOCK,
T::UnsignedPhase::get().saturated_into(),
);
match lock.try_lock() {
Ok(_guard) => {
@@ -775,7 +776,7 @@ pub mod pallet {
},
Err(deadline) => {
log!(debug, "offchain worker lock not released, deadline is {:?}", deadline);
}
},
};
}
@@ -857,8 +858,7 @@ pub mod pallet {
witness: SolutionOrSnapshotSize,
) -> DispatchResultWithPostInfo {
ensure_none(origin)?;
let error_message =
"Invalid unsigned submission must produce invalid block and \
let error_message = "Invalid unsigned submission must produce invalid block and \
deprive validator from their authoring reward.";
// Check score being an improvement, phase, and desired targets.
@@ -921,11 +921,8 @@ pub mod pallet {
// Note: we don't `rotate_round` at this point; the next call to
// `ElectionProvider::elect` will succeed and take care of that.
let solution = ReadySolution {
supports,
score: [0, 0, 0],
compute: ElectionCompute::Emergency,
};
let solution =
ReadySolution { supports, score: [0, 0, 0], compute: ElectionCompute::Emergency };
<QueuedSolution<T>>::put(solution);
Ok(())
@@ -954,7 +951,8 @@ pub mod pallet {
// ensure witness data is correct.
ensure!(
num_signed_submissions >= <SignedSubmissions<T>>::decode_len().unwrap_or_default() as u32,
num_signed_submissions >=
<SignedSubmissions<T>>::decode_len().unwrap_or_default() as u32,
Error::<T>::SignedInvalidWitness,
);
@@ -989,8 +987,7 @@ pub mod pallet {
};
// collect deposit. Thereafter, the function cannot fail.
T::Currency::reserve(&who, deposit)
.map_err(|_| Error::<T>::SignedCannotPayDeposit)?;
T::Currency::reserve(&who, deposit).map_err(|_| Error::<T>::SignedCannotPayDeposit)?;
let ejected_a_solution = maybe_removed.is_some();
// if we had to remove the weakest solution, unreserve its deposit
@@ -1068,10 +1065,8 @@ pub mod pallet {
if let Call::submit_unsigned(solution, _) = call {
// Discard solution not coming from the local OCW.
match source {
TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ }
_ => {
return InvalidTransaction::Call.into();
}
TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ },
_ => return InvalidTransaction::Call.into(),
}
let _ = Self::unsigned_pre_dispatch_checks(solution)
@@ -1084,9 +1079,8 @@ pub mod pallet {
ValidTransaction::with_tag_prefix("OffchainElection")
// The higher the score[0], the better a solution is.
.priority(
T::MinerTxPriority::get().saturating_add(
solution.score[0].saturated_into()
),
T::MinerTxPriority::get()
.saturating_add(solution.score[0].saturated_into()),
)
// Used to deduplicate unsigned solutions: each validator should produce one
// solution per round at most, and solutions are not propagate.
@@ -1219,20 +1213,18 @@ impl<T: Config> Pallet<T> {
match current_phase {
Phase::Unsigned((true, opened)) if opened == now => {
// Mine a new solution, cache it, and attempt to submit it
let initial_output = Self::ensure_offchain_repeat_frequency(now).and_then(|_| {
Self::mine_check_save_submit()
});
let initial_output = Self::ensure_offchain_repeat_frequency(now)
.and_then(|_| Self::mine_check_save_submit());
log!(debug, "initial offchain thread output: {:?}", initial_output);
}
},
Phase::Unsigned((true, opened)) if opened < now => {
// Try and resubmit the cached solution, and recompute ONLY if it is not
// feasible.
let resubmit_output = Self::ensure_offchain_repeat_frequency(now).and_then(|_| {
Self::restore_or_compute_then_maybe_submit()
});
let resubmit_output = Self::ensure_offchain_repeat_frequency(now)
.and_then(|_| Self::restore_or_compute_then_maybe_submit());
log!(debug, "resubmit offchain thread output: {:?}", resubmit_output);
}
_ => {}
},
_ => {},
}
// After election finalization, clear OCW solution storage.
@@ -1242,9 +1234,7 @@ impl<T: Config> Pallet<T> {
let local_event = <T as Config>::Event::from(event_record.event);
local_event.try_into().ok()
})
.any(|event| {
matches!(event, Event::ElectionFinalized(_))
})
.any(|event| matches!(event, Event::ElectionFinalized(_)))
{
unsigned::kill_ocw_solution::<T>();
}
@@ -1308,14 +1298,12 @@ impl<T: Config> Pallet<T> {
// Defensive-only.
if targets.len() > target_limit || voters.len() > voter_limit {
debug_assert!(false, "Snapshot limit has not been respected.");
return Err(ElectionError::DataProvider("Snapshot too big for submission."));
return Err(ElectionError::DataProvider("Snapshot too big for submission."))
}
// Only write snapshot if all existed.
let metadata = SolutionOrSnapshotSize {
voters: voters.len() as u32,
targets: targets.len() as u32,
};
let metadata =
SolutionOrSnapshotSize { voters: voters.len() as u32, targets: targets.len() as u32 };
log!(debug, "creating a snapshot with metadata {:?}", metadata);
<SnapshotMetadata<T>>::put(metadata);
@@ -1335,7 +1323,10 @@ impl<T: Config> Pallet<T> {
debug_assert!(buffer.len() == size && size == buffer.capacity());
sp_io::storage::set(&<Snapshot<T>>::hashed_key(), &buffer);
Ok(w1.saturating_add(w2).saturating_add(w3).saturating_add(T::DbWeight::get().writes(3)))
Ok(w1
.saturating_add(w2)
.saturating_add(w3)
.saturating_add(T::DbWeight::get().writes(3)))
}
/// Kill everything created by [`Pallet::create_snapshot`].
@@ -1369,9 +1360,9 @@ impl<T: Config> Pallet<T> {
// Ensure that the solution's score can pass absolute min-score.
let submitted_score = solution.score.clone();
ensure!(
Self::minimum_untrusted_score().map_or(true, |min_score|
Self::minimum_untrusted_score().map_or(true, |min_score| {
sp_npos_elections::is_score_better(submitted_score, min_score, Perbill::zero())
),
}),
FeasibilityError::UntrustedScoreTooLow
);
@@ -1418,7 +1409,7 @@ impl<T: Config> Pallet<T> {
// Check that all of the targets are valid based on the snapshot.
if assignment.distribution.iter().any(|(d, _)| !targets.contains(d)) {
return Err(FeasibilityError::InvalidVote);
return Err(FeasibilityError::InvalidVote)
}
Ok(())
})
@@ -1494,8 +1485,13 @@ impl<T: Config> Pallet<T> {
.fold(Zero::zero(), |acc, next| acc + next.voters.len() as u32);
Ok((
supports,
T::WeightInfo::elect_queued(metadata.voters, metadata.targets, active_voters, desired),
compute
T::WeightInfo::elect_queued(
metadata.voters,
metadata.targets,
active_voters,
desired,
),
compute,
))
},
)
@@ -1526,12 +1522,12 @@ impl<T: Config> ElectionProvider<T::AccountId, T::BlockNumber> for Pallet<T> {
// All went okay, put sign to be Off, clean snapshot, etc.
Self::rotate_round();
Ok((supports, weight))
}
},
Err(why) => {
log!(error, "Entering emergency mode: {:?}", why);
<CurrentPhase<T>>::put(Phase::Emergency);
Err(why)
}
},
}
}
}
@@ -1553,11 +1549,9 @@ mod feasibility_check {
//! that is invalid, but gets through the system as valid.
use super::*;
use crate::{
mock::{
MultiPhase, Runtime, roll_to, TargetIndex, raw_solution, EpochLength, UnsignedPhase,
SignedPhase, VoterIndex, ExtBuilder,
},
use crate::mock::{
raw_solution, roll_to, EpochLength, ExtBuilder, MultiPhase, Runtime, SignedPhase,
TargetIndex, UnsignedPhase, VoterIndex,
};
use frame_support::assert_noop;
@@ -1728,11 +1722,11 @@ mod feasibility_check {
mod tests {
use super::*;
use crate::{
Phase,
mock::{
ExtBuilder, MultiPhase, Runtime, roll_to, MockWeightInfo, AccountId, TargetIndex,
Targets, multi_phase_events, System, SignedMaxSubmissions,
multi_phase_events, roll_to, AccountId, ExtBuilder, MockWeightInfo, MultiPhase,
Runtime, SignedMaxSubmissions, System, TargetIndex, Targets,
},
Phase,
};
use frame_election_provider_support::ElectionProvider;
use frame_support::{assert_noop, assert_ok};
@@ -2002,7 +1996,6 @@ mod tests {
roll_to(15);
assert_eq!(MultiPhase::current_phase(), Phase::Signed);
let (solution, _) = MultiPhase::mine_solution(2).unwrap();
// Default solution has a score of [50, 100, 5000].
assert_eq!(solution.score, [50, 100, 5000]);
@@ -2012,10 +2005,7 @@ mod tests {
<MinimumUntrustedScore<Runtime>>::put([51, 0, 0]);
assert_noop!(
MultiPhase::feasibility_check(
solution,
ElectionCompute::Signed
),
MultiPhase::feasibility_check(solution, ElectionCompute::Signed),
FeasibilityError::UntrustedScoreTooLow,
);
})
@@ -2039,9 +2029,9 @@ mod tests {
};
let mut active = 1;
while weight_with(active)
<= <Runtime as frame_system::Config>::BlockWeights::get().max_block
|| active == all_voters
while weight_with(active) <=
<Runtime as frame_system::Config>::BlockWeights::get().max_block ||
active == all_voters
{
active += 1;
}
@@ -17,13 +17,10 @@
use super::*;
use crate as multi_phase;
use multi_phase::unsigned::{IndexAssignmentOf, Voter};
use frame_election_provider_support::{data_provider, ElectionDataProvider};
pub use frame_support::{assert_noop, assert_ok};
use frame_support::{
parameter_types,
traits::{Hooks},
weights::Weight,
};
use frame_support::{parameter_types, traits::Hooks, weights::Weight};
use multi_phase::unsigned::{IndexAssignmentOf, Voter};
use parking_lot::RwLock;
use sp_core::{
offchain::{
@@ -32,7 +29,6 @@ use sp_core::{
},
H256,
};
use frame_election_provider_support::{ElectionDataProvider, data_provider};
use sp_npos_elections::{
assignment_ratio_to_staked_normalized, seq_phragmen, to_supports, to_without_backing,
CompactSolution, ElectionResult, EvaluateSupport,
@@ -405,7 +401,7 @@ impl ElectionDataProvider<AccountId, u64> for StakingMock {
let targets = Targets::get();
if maybe_max_len.map_or(false, |max_len| targets.len() > max_len) {
return Err("Targets too big");
return Err("Targets too big")
}
Ok((targets, 0))
@@ -416,7 +412,7 @@ impl ElectionDataProvider<AccountId, u64> for StakingMock {
) -> data_provider::Result<(Vec<(AccountId, VoteWeight, Vec<AccountId>)>, Weight)> {
let voters = Voters::get();
if maybe_max_len.map_or(false, |max_len| voters.len() > max_len) {
return Err("Voters too big");
return Err("Voters too big")
}
Ok((voters, 0))
@@ -18,11 +18,11 @@
//! The signed phase implementation.
use crate::{
CompactOf, Config, ElectionCompute, Pallet, RawSolution, ReadySolution, SolutionOrSnapshotSize,
Weight, WeightInfo, QueuedSolution, SignedSubmissionsMap, SignedSubmissionIndices,
SignedSubmissionNextIndex,
CompactOf, Config, ElectionCompute, Pallet, QueuedSolution, RawSolution, ReadySolution,
SignedSubmissionIndices, SignedSubmissionNextIndex, SignedSubmissionsMap,
SolutionOrSnapshotSize, Weight, WeightInfo,
};
use codec::{Encode, Decode, HasCompact};
use codec::{Decode, Encode, HasCompact};
use frame_support::{
storage::bounded_btree_map::BoundedBTreeMap,
traits::{Currency, Get, OnUnbalanced, ReservableCurrency},
@@ -31,8 +31,8 @@ use frame_support::{
use sp_arithmetic::traits::SaturatedConversion;
use sp_npos_elections::{is_score_better, CompactSolution, ElectionScore};
use sp_runtime::{
RuntimeDebug,
traits::{Saturating, Zero},
RuntimeDebug,
};
use sp_std::{
cmp::Ordering,
@@ -131,24 +131,30 @@ impl<T: Config> SignedSubmissions<T> {
deletion_overlay: BTreeSet::new(),
};
// validate that the stored state is sane
debug_assert!(submissions.indices.values().copied().max().map_or(
true,
|max_idx| submissions.next_idx > max_idx,
));
debug_assert!(submissions
.indices
.values()
.copied()
.max()
.map_or(true, |max_idx| submissions.next_idx > max_idx,));
submissions
}
/// Put the signed submissions back into storage.
pub fn put(mut self) {
// validate that we're going to write only sane things to storage
debug_assert!(self.insertion_overlay.keys().copied().max().map_or(
true,
|max_idx| self.next_idx > max_idx,
));
debug_assert!(self.indices.values().copied().max().map_or(
true,
|max_idx| self.next_idx > max_idx,
));
debug_assert!(self
.insertion_overlay
.keys()
.copied()
.max()
.map_or(true, |max_idx| self.next_idx > max_idx,));
debug_assert!(self
.indices
.values()
.copied()
.max()
.map_or(true, |max_idx| self.next_idx > max_idx,));
SignedSubmissionIndices::<T>::put(self.indices);
SignedSubmissionNextIndex::<T>::put(self.next_idx);
@@ -203,10 +209,12 @@ impl<T: Config> SignedSubmissions<T> {
}
self.insertion_overlay.remove(&remove_idx).or_else(|| {
(!self.deletion_overlay.contains(&remove_idx)).then(|| {
self.deletion_overlay.insert(remove_idx);
SignedSubmissionsMap::<T>::try_get(remove_idx).ok()
}).flatten()
(!self.deletion_overlay.contains(&remove_idx))
.then(|| {
self.deletion_overlay.insert(remove_idx);
SignedSubmissionsMap::<T>::try_get(remove_idx).ok()
})
.flatten()
})
}
@@ -256,10 +264,7 @@ impl<T: Config> SignedSubmissions<T> {
///
/// In the event that the new submission is not better than the current weakest according
/// to `is_score_better`, we do not change anything.
pub fn insert(
&mut self,
submission: SignedSubmissionOf<T>,
) -> InsertResult<T> {
pub fn insert(&mut self, submission: SignedSubmissionOf<T>) -> InsertResult<T> {
// verify the expectation that we never reuse an index
debug_assert!(!self.indices.values().any(|&idx| idx == self.next_idx));
@@ -271,12 +276,12 @@ impl<T: Config> SignedSubmissions<T> {
self.indices
.try_insert(submission.solution.score, prev_idx)
.expect("didn't change the map size; qed");
return InsertResult::NotInserted;
}
return InsertResult::NotInserted
},
Ok(None) => {
// successfully inserted into the set; no need to take out weakest member
None
}
},
Err((insert_score, insert_idx)) => {
// could not insert into the set because it is full.
// note that we short-circuit return here in case the iteration produces `None`.
@@ -290,11 +295,11 @@ impl<T: Config> SignedSubmissions<T> {
// if we haven't improved on the weakest score, don't change anything.
if !is_score_better(insert_score, weakest_score, threshold) {
return InsertResult::NotInserted;
return InsertResult::NotInserted
}
self.swap_out_submission(weakest_score, Some((insert_score, insert_idx)))
}
},
};
// we've taken out the weakest, so update the storage map and the next index
@@ -349,17 +354,12 @@ impl<T: Config> Pallet<T> {
let reward = T::SignedRewardBase::get();
while let Some(best) = all_submissions.pop_last() {
let SignedSubmission { solution, who, deposit} = best;
let SignedSubmission { solution, who, deposit } = best;
let active_voters = solution.compact.voter_count() as u32;
let feasibility_weight = {
// defensive only: at the end of signed phase, snapshot will exits.
let desired_targets = Self::desired_targets().unwrap_or_default();
T::WeightInfo::feasibility_check(
voters,
targets,
active_voters,
desired_targets,
)
T::WeightInfo::feasibility_check(voters, targets, active_voters, desired_targets)
};
// the feasibility check itself has some weight
weight = weight.saturating_add(feasibility_weight);
@@ -375,13 +375,13 @@ impl<T: Config> Pallet<T> {
weight = weight
.saturating_add(T::WeightInfo::finalize_signed_phase_accept_solution());
break;
}
break
},
Err(_) => {
Self::finalize_signed_phase_reject_solution(&who, deposit);
weight = weight
.saturating_add(T::WeightInfo::finalize_signed_phase_reject_solution());
}
},
}
}
@@ -398,7 +398,12 @@ impl<T: Config> Pallet<T> {
debug_assert!(!SignedSubmissionNextIndex::<T>::exists());
debug_assert!(SignedSubmissionsMap::<T>::iter().next().is_none());
log!(debug, "closed signed phase, found solution? {}, discarded {}", found_solution, discarded);
log!(
debug,
"closed signed phase, found solution? {}, discarded {}",
found_solution,
discarded
);
(found_solution, weight)
}
@@ -469,9 +474,12 @@ impl<T: Config> Pallet<T> {
let feasibility_weight = Self::feasibility_weight_of(solution, size);
let len_deposit = T::SignedDepositByte::get().saturating_mul(encoded_len);
let weight_deposit = T::SignedDepositWeight::get().saturating_mul(feasibility_weight.saturated_into());
let weight_deposit =
T::SignedDepositWeight::get().saturating_mul(feasibility_weight.saturated_into());
T::SignedDepositBase::get().saturating_add(len_deposit).saturating_add(weight_deposit)
T::SignedDepositBase::get()
.saturating_add(len_deposit)
.saturating_add(weight_deposit)
}
}
@@ -479,13 +487,13 @@ impl<T: Config> Pallet<T> {
mod tests {
use super::*;
use crate::{
Phase, Error,
mock::{
balances, ExtBuilder, MultiPhase, Origin, raw_solution, roll_to, Runtime,
balances, raw_solution, roll_to, ExtBuilder, MultiPhase, Origin, Runtime,
SignedMaxSubmissions, SignedMaxWeight,
},
Error, Phase,
};
use frame_support::{dispatch::DispatchResult, assert_noop, assert_storage_noop, assert_ok};
use frame_support::{assert_noop, assert_ok, assert_storage_noop, dispatch::DispatchResult};
fn submit_with_witness(
origin: Origin,
@@ -626,7 +634,6 @@ mod tests {
assert_ok!(submit_with_witness(Origin::signed(99), solution));
}
// weaker.
let solution = RawSolution { score: [4, 0, 0], ..Default::default() };
@@ -810,33 +817,36 @@ mod tests {
#[test]
fn cannot_consume_too_much_future_weight() {
ExtBuilder::default().signed_weight(40).mock_weight_info(true).build_and_execute(|| {
roll_to(15);
assert!(MultiPhase::current_phase().is_signed());
ExtBuilder::default()
.signed_weight(40)
.mock_weight_info(true)
.build_and_execute(|| {
roll_to(15);
assert!(MultiPhase::current_phase().is_signed());
let (solution, witness) = MultiPhase::mine_solution(2).unwrap();
let solution_weight = <Runtime as Config>::WeightInfo::feasibility_check(
witness.voters,
witness.targets,
solution.compact.voter_count() as u32,
solution.compact.unique_targets().len() as u32,
);
// default solution will have 5 edges (5 * 5 + 10)
assert_eq!(solution_weight, 35);
assert_eq!(solution.compact.voter_count(), 5);
assert_eq!(<Runtime as Config>::SignedMaxWeight::get(), 40);
let (solution, witness) = MultiPhase::mine_solution(2).unwrap();
let solution_weight = <Runtime as Config>::WeightInfo::feasibility_check(
witness.voters,
witness.targets,
solution.compact.voter_count() as u32,
solution.compact.unique_targets().len() as u32,
);
// default solution will have 5 edges (5 * 5 + 10)
assert_eq!(solution_weight, 35);
assert_eq!(solution.compact.voter_count(), 5);
assert_eq!(<Runtime as Config>::SignedMaxWeight::get(), 40);
assert_ok!(submit_with_witness(Origin::signed(99), solution.clone()));
assert_ok!(submit_with_witness(Origin::signed(99), solution.clone()));
<SignedMaxWeight>::set(30);
<SignedMaxWeight>::set(30);
// note: resubmitting the same solution is technically okay as long as the queue has
// space.
assert_noop!(
submit_with_witness(Origin::signed(99), solution),
Error::<Runtime>::SignedTooMuchWeight,
);
})
// note: resubmitting the same solution is technically okay as long as the queue has
// space.
assert_noop!(
submit_with_witness(Origin::signed(99), solution),
Error::<Runtime>::SignedTooMuchWeight,
);
})
}
#[test]
@@ -21,19 +21,18 @@ use crate::{
helpers, Call, CompactAccuracyOf, CompactOf, Config, ElectionCompute, Error, FeasibilityError,
Pallet, RawSolution, ReadySolution, RoundSnapshot, SolutionOrSnapshotSize, Weight, WeightInfo,
};
use codec::{Encode, Decode};
use codec::{Decode, Encode};
use frame_support::{dispatch::DispatchResult, ensure, traits::Get};
use frame_system::offchain::SubmitTransaction;
use sp_arithmetic::Perbill;
use sp_npos_elections::{
CompactSolution, ElectionResult, assignment_ratio_to_staked_normalized,
assignment_staked_to_ratio_normalized, is_score_better, seq_phragmen,
assignment_ratio_to_staked_normalized, assignment_staked_to_ratio_normalized, is_score_better,
seq_phragmen, CompactSolution, ElectionResult,
};
use sp_runtime::{
DispatchError,
SaturatedConversion,
offchain::storage::{MutateStorageError, StorageValueRef},
traits::TrailingZeroInput,
DispatchError, SaturatedConversion,
};
use sp_std::{cmp::Ordering, convert::TryFrom, vec::Vec};
@@ -54,10 +53,8 @@ pub type Voter<T> = (
);
/// The relative distribution of a voter's stake among the winning targets.
pub type Assignment<T> = sp_npos_elections::Assignment<
<T as frame_system::Config>::AccountId,
CompactAccuracyOf<T>,
>;
pub type Assignment<T> =
sp_npos_elections::Assignment<<T as frame_system::Config>::AccountId, CompactAccuracyOf<T>>;
/// The [`IndexAssignment`][sp_npos_elections::IndexAssignment] type specialized for a particular
/// runtime `T`.
@@ -105,7 +102,8 @@ fn save_solution<T: Config>(call: &Call<T>) -> Result<(), MinerError> {
let storage = StorageValueRef::persistent(&OFFCHAIN_CACHED_CALL);
match storage.mutate::<_, (), _>(|_| Ok(call.clone())) {
Ok(_) => Ok(()),
Err(MutateStorageError::ConcurrentModification(_)) => Err(MinerError::FailedToStoreSolution),
Err(MutateStorageError::ConcurrentModification(_)) =>
Err(MinerError::FailedToStoreSolution),
Err(MutateStorageError::ValueFunctionFailed(_)) => {
// this branch should be unreachable according to the definition of
// `StorageValueRef::mutate`: that function should only ever `Err` if the closure we
@@ -151,44 +149,45 @@ impl<T: Config> Pallet<T> {
/// Attempt to restore a solution from cache. Otherwise, compute it fresh. Either way, submit
/// if our call's score is greater than that of the cached solution.
pub fn restore_or_compute_then_maybe_submit() -> Result<(), MinerError> {
log!(debug,"miner attempting to restore or compute an unsigned solution.");
log!(debug, "miner attempting to restore or compute an unsigned solution.");
let call = restore_solution::<T>()
.and_then(|call| {
// ensure the cached call is still current before submitting
if let Call::submit_unsigned(solution, _) = &call {
// prevent errors arising from state changes in a forkful chain
Self::basic_checks(solution, "restored")?;
Ok(call)
} else {
Err(MinerError::SolutionCallInvalid)
}
}).or_else::<MinerError, _>(|error| {
log!(debug, "restoring solution failed due to {:?}", error);
match error {
MinerError::NoStoredSolution => {
log!(trace, "mining a new solution.");
// if not present or cache invalidated due to feasibility, regenerate.
// note that failing `Feasibility` can only mean that the solution was
// computed over a snapshot that has changed due to a fork.
let call = Self::mine_checked_call()?;
save_solution(&call)?;
.and_then(|call| {
// ensure the cached call is still current before submitting
if let Call::submit_unsigned(solution, _) = &call {
// prevent errors arising from state changes in a forkful chain
Self::basic_checks(solution, "restored")?;
Ok(call)
} else {
Err(MinerError::SolutionCallInvalid)
}
MinerError::Feasibility(_) => {
log!(trace, "wiping infeasible solution.");
// kill the infeasible solution, hopefully in the next runs (whenever they
// may be) we mine a new one.
kill_ocw_solution::<T>();
clear_offchain_repeat_frequency();
Err(error)
},
_ => {
// nothing to do. Return the error as-is.
Err(error)
})
.or_else::<MinerError, _>(|error| {
log!(debug, "restoring solution failed due to {:?}", error);
match error {
MinerError::NoStoredSolution => {
log!(trace, "mining a new solution.");
// if not present or cache invalidated due to feasibility, regenerate.
// note that failing `Feasibility` can only mean that the solution was
// computed over a snapshot that has changed due to a fork.
let call = Self::mine_checked_call()?;
save_solution(&call)?;
Ok(call)
},
MinerError::Feasibility(_) => {
log!(trace, "wiping infeasible solution.");
// kill the infeasible solution, hopefully in the next runs (whenever they
// may be) we mine a new one.
kill_ocw_solution::<T>();
clear_offchain_repeat_frequency();
Err(error)
},
_ => {
// nothing to do. Return the error as-is.
Err(error)
},
}
}
})?;
})?;
Self::submit_call(call)
}
@@ -240,10 +239,12 @@ impl<T: Config> Pallet<T> {
MinerError::PreDispatchChecksFailed(err)
})?;
Self::feasibility_check(raw_solution.clone(), ElectionCompute::Unsigned).map_err(|err| {
log!(debug, "feasibility check failed for {} solution: {:?}", solution_type, err);
err
})?;
Self::feasibility_check(raw_solution.clone(), ElectionCompute::Unsigned).map_err(
|err| {
log!(debug, "feasibility check failed for {} solution: {:?}", solution_type, err);
err
},
)?;
Ok(())
}
@@ -347,11 +348,7 @@ impl<T: Config> Pallet<T> {
// converting to `Compact`.
let mut index_assignments = sorted_assignments
.into_iter()
.map(|assignment| IndexAssignmentOf::<T>::new(
&assignment,
&voter_index,
&target_index,
))
.map(|assignment| IndexAssignmentOf::<T>::new(&assignment, &voter_index, &target_index))
.collect::<Result<Vec<_>, _>>()?;
// trim assignments list for weight and length.
@@ -390,10 +387,10 @@ impl<T: Config> Pallet<T> {
max @ _ => {
let seed = sp_io::offchain::random_seed();
let random = <u32>::decode(&mut TrailingZeroInput::new(seed.as_ref()))
.expect("input is padded with zeroes; qed")
% max.saturating_add(1);
.expect("input is padded with zeroes; qed") %
max.saturating_add(1);
random as usize
}
},
}
}
@@ -418,18 +415,16 @@ impl<T: Config> Pallet<T> {
max_weight: Weight,
assignments: &mut Vec<IndexAssignmentOf<T>>,
) {
let maximum_allowed_voters = Self::maximum_voter_for_weight::<T::WeightInfo>(
desired_targets,
size,
max_weight,
);
let removing: usize = assignments.len().saturating_sub(
maximum_allowed_voters.saturated_into(),
);
let maximum_allowed_voters =
Self::maximum_voter_for_weight::<T::WeightInfo>(desired_targets, size, max_weight);
let removing: usize =
assignments.len().saturating_sub(maximum_allowed_voters.saturated_into());
log!(
debug,
"from {} assignments, truncating to {} for weight, removing {}",
assignments.len(), maximum_allowed_voters, removing,
assignments.len(),
maximum_allowed_voters,
removing,
);
assignments.truncate(maximum_allowed_voters as usize);
}
@@ -461,7 +456,7 @@ impl<T: Config> Pallet<T> {
// not much we can do if assignments are already empty.
if high == low {
return Ok(());
return Ok(())
}
while high - low > 1 {
@@ -472,22 +467,21 @@ impl<T: Config> Pallet<T> {
high = test;
}
}
let maximum_allowed_voters =
if low < assignments.len() &&
encoded_size_of(&assignments[..low + 1])? <= max_allowed_length
{
low + 1
} else {
low
};
let maximum_allowed_voters = if low < assignments.len() &&
encoded_size_of(&assignments[..low + 1])? <= max_allowed_length
{
low + 1
} else {
low
};
// ensure our post-conditions are correct
debug_assert!(
encoded_size_of(&assignments[..maximum_allowed_voters]).unwrap() <= max_allowed_length
);
debug_assert!(if maximum_allowed_voters < assignments.len() {
encoded_size_of(&assignments[..maximum_allowed_voters + 1]).unwrap()
> max_allowed_length
encoded_size_of(&assignments[..maximum_allowed_voters + 1]).unwrap() >
max_allowed_length
} else {
true
});
@@ -517,7 +511,7 @@ impl<T: Config> Pallet<T> {
max_weight: Weight,
) -> u32 {
if size.voters < 1 {
return size.voters;
return size.voters
}
let max_voters = size.voters.max(1);
@@ -536,7 +530,7 @@ impl<T: Config> Pallet<T> {
Some(voters) if voters < max_voters => Ok(voters),
_ => Err(()),
}
}
},
Ordering::Greater => voters.checked_sub(step).ok_or(()),
Ordering::Equal => Ok(voters),
}
@@ -551,11 +545,9 @@ impl<T: Config> Pallet<T> {
// proceed with the binary search
Ok(next) if next != voters => {
voters = next;
}
},
// we are out of bounds, break out of the loop.
Err(()) => {
break;
}
Err(()) => break,
// we found the right value - early exit the function.
Ok(next) => return next,
}
@@ -599,17 +591,16 @@ impl<T: Config> Pallet<T> {
|maybe_head: Result<Option<T::BlockNumber>, _>| {
match maybe_head {
Ok(Some(head)) if now < head => Err("fork."),
Ok(Some(head)) if now >= head && now <= head + threshold => {
Err("recently executed.")
}
Ok(Some(head)) if now >= head && now <= head + threshold =>
Err("recently executed."),
Ok(Some(head)) if now > head + threshold => {
// we can run again now. Write the new head.
Ok(now)
}
},
_ => {
// value doesn't exists. Probably this node just booted up. Write, and run
Ok(now)
}
},
}
},
);
@@ -632,9 +623,7 @@ impl<T: Config> Pallet<T> {
///
/// NOTE: Ideally, these tests should move more and more outside of this and more to the miner's
/// code, so that we do less and less storage reads here.
pub fn unsigned_pre_dispatch_checks(
solution: &RawSolution<CompactOf<T>>,
) -> DispatchResult {
pub fn unsigned_pre_dispatch_checks(solution: &RawSolution<CompactOf<T>>) -> DispatchResult {
// ensure solution is timely. Don't panic yet. This is a cheap check.
ensure!(Self::current_phase().is_unsigned_open(), Error::<T>::PreDispatchEarlySubmission);
@@ -643,8 +632,8 @@ impl<T: Config> Pallet<T> {
// ensure correct number of winners.
ensure!(
Self::desired_targets().unwrap_or_default()
== solution.compact.unique_targets().len() as u32,
Self::desired_targets().unwrap_or_default() ==
solution.compact.unique_targets().len() as u32,
Error::<T>::PreDispatchWrongWinnerCount,
);
@@ -761,19 +750,22 @@ mod max_weight {
mod tests {
use super::*;
use crate::{
mock::{
roll_to, roll_to_with_ocw, trim_helpers, witness, BlockNumber, Call as OuterCall,
ExtBuilder, Extrinsic, MinerMaxWeight, MultiPhase, Origin, Runtime, System,
TestCompact, TrimHelpers, UnsignedPhase,
},
CurrentPhase, InvalidTransaction, Phase, QueuedSolution, TransactionSource,
TransactionValidityError,
mock::{
Call as OuterCall, ExtBuilder, Extrinsic, MinerMaxWeight, MultiPhase, Origin, Runtime,
TestCompact, TrimHelpers, roll_to, roll_to_with_ocw, trim_helpers, witness,
UnsignedPhase, BlockNumber, System,
},
};
use frame_benchmarking::Zero;
use frame_support::{assert_noop, assert_ok, dispatch::Dispatchable, traits::OffchainWorker};
use sp_npos_elections::IndexAssignment;
use sp_runtime::offchain::storage_lock::{StorageLock, BlockAndTime};
use sp_runtime::{traits::ValidateUnsigned, PerU16};
use sp_runtime::{
offchain::storage_lock::{BlockAndTime, StorageLock},
traits::ValidateUnsigned,
PerU16,
};
type Assignment = crate::unsigned::Assignment<Runtime>;
@@ -786,8 +778,11 @@ mod tests {
// initial
assert_eq!(MultiPhase::current_phase(), Phase::Off);
assert!(matches!(
<MultiPhase as ValidateUnsigned>::validate_unsigned(TransactionSource::Local, &call)
.unwrap_err(),
<MultiPhase as ValidateUnsigned>::validate_unsigned(
TransactionSource::Local,
&call
)
.unwrap_err(),
TransactionValidityError::Invalid(InvalidTransaction::Custom(0))
));
assert!(matches!(
@@ -799,8 +794,11 @@ mod tests {
roll_to(15);
assert_eq!(MultiPhase::current_phase(), Phase::Signed);
assert!(matches!(
<MultiPhase as ValidateUnsigned>::validate_unsigned(TransactionSource::Local, &call)
.unwrap_err(),
<MultiPhase as ValidateUnsigned>::validate_unsigned(
TransactionSource::Local,
&call
)
.unwrap_err(),
TransactionValidityError::Invalid(InvalidTransaction::Custom(0))
));
assert!(matches!(
@@ -823,8 +821,11 @@ mod tests {
<CurrentPhase<Runtime>>::put(Phase::Unsigned((false, 25)));
assert!(MultiPhase::current_phase().is_unsigned());
assert!(matches!(
<MultiPhase as ValidateUnsigned>::validate_unsigned(TransactionSource::Local, &call)
.unwrap_err(),
<MultiPhase as ValidateUnsigned>::validate_unsigned(
TransactionSource::Local,
&call
)
.unwrap_err(),
TransactionValidityError::Invalid(InvalidTransaction::Custom(0))
));
assert!(matches!(
@@ -895,23 +896,27 @@ mod tests {
#[test]
fn priority_is_set() {
ExtBuilder::default().miner_tx_priority(20).desired_targets(0).build_and_execute(|| {
roll_to(25);
assert!(MultiPhase::current_phase().is_unsigned());
ExtBuilder::default()
.miner_tx_priority(20)
.desired_targets(0)
.build_and_execute(|| {
roll_to(25);
assert!(MultiPhase::current_phase().is_unsigned());
let solution = RawSolution::<TestCompact> { score: [5, 0, 0], ..Default::default() };
let call = Call::submit_unsigned(solution.clone(), witness());
let solution =
RawSolution::<TestCompact> { score: [5, 0, 0], ..Default::default() };
let call = Call::submit_unsigned(solution.clone(), witness());
assert_eq!(
<MultiPhase as ValidateUnsigned>::validate_unsigned(
TransactionSource::Local,
&call
)
.unwrap()
.priority,
25
);
})
assert_eq!(
<MultiPhase as ValidateUnsigned>::validate_unsigned(
TransactionSource::Local,
&call
)
.unwrap()
.priority,
25
);
})
}
#[test]
@@ -974,35 +979,38 @@ mod tests {
#[test]
fn miner_trims_weight() {
ExtBuilder::default().miner_weight(100).mock_weight_info(true).build_and_execute(|| {
roll_to(25);
assert!(MultiPhase::current_phase().is_unsigned());
ExtBuilder::default()
.miner_weight(100)
.mock_weight_info(true)
.build_and_execute(|| {
roll_to(25);
assert!(MultiPhase::current_phase().is_unsigned());
let (solution, witness) = MultiPhase::mine_solution(2).unwrap();
let solution_weight = <Runtime as Config>::WeightInfo::submit_unsigned(
witness.voters,
witness.targets,
solution.compact.voter_count() as u32,
solution.compact.unique_targets().len() as u32,
);
// default solution will have 5 edges (5 * 5 + 10)
assert_eq!(solution_weight, 35);
assert_eq!(solution.compact.voter_count(), 5);
let (solution, witness) = MultiPhase::mine_solution(2).unwrap();
let solution_weight = <Runtime as Config>::WeightInfo::submit_unsigned(
witness.voters,
witness.targets,
solution.compact.voter_count() as u32,
solution.compact.unique_targets().len() as u32,
);
// default solution will have 5 edges (5 * 5 + 10)
assert_eq!(solution_weight, 35);
assert_eq!(solution.compact.voter_count(), 5);
// now reduce the max weight
<MinerMaxWeight>::set(25);
// now reduce the max weight
<MinerMaxWeight>::set(25);
let (solution, witness) = MultiPhase::mine_solution(2).unwrap();
let solution_weight = <Runtime as Config>::WeightInfo::submit_unsigned(
witness.voters,
witness.targets,
solution.compact.voter_count() as u32,
solution.compact.unique_targets().len() as u32,
);
// default solution will have 5 edges (5 * 5 + 10)
assert_eq!(solution_weight, 25);
assert_eq!(solution.compact.voter_count(), 3);
})
let (solution, witness) = MultiPhase::mine_solution(2).unwrap();
let solution_weight = <Runtime as Config>::WeightInfo::submit_unsigned(
witness.voters,
witness.targets,
solution.compact.voter_count() as u32,
solution.compact.unique_targets().len() as u32,
);
// default solution will have 5 edges (5 * 5 + 10)
assert_eq!(solution_weight, 25);
assert_eq!(solution.compact.voter_count(), 3);
})
}
#[test]
@@ -1014,7 +1022,7 @@ mod tests {
assert_eq!(
MultiPhase::mine_check_save_submit().unwrap_err(),
MinerError::PreDispatchChecksFailed(DispatchError::Module{
MinerError::PreDispatchChecksFailed(DispatchError::Module {
index: 2,
error: 1,
message: Some("PreDispatchWrongWinnerCount"),
@@ -1360,15 +1368,14 @@ mod tests {
};
// Custom(7) maps to PreDispatchChecksFailed
let pre_dispatch_check_error = TransactionValidityError::Invalid(
InvalidTransaction::Custom(7),
);
let pre_dispatch_check_error =
TransactionValidityError::Invalid(InvalidTransaction::Custom(7));
assert_eq!(
<MultiPhase as ValidateUnsigned>::validate_unsigned(
TransactionSource::Local,
&call,
)
.unwrap_err(),
.unwrap_err(),
pre_dispatch_check_error,
);
assert_eq!(
@@ -1384,21 +1391,14 @@ mod tests {
roll_to(25);
// given
let TrimHelpers {
mut assignments,
encoded_size_of,
..
} = trim_helpers();
let TrimHelpers { mut assignments, encoded_size_of, .. } = trim_helpers();
let compact = CompactOf::<Runtime>::try_from(assignments.as_slice()).unwrap();
let encoded_len = compact.encoded_size() as u32;
let compact_clone = compact.clone();
// when
MultiPhase::trim_assignments_length(
encoded_len,
&mut assignments,
encoded_size_of,
).unwrap();
MultiPhase::trim_assignments_length(encoded_len, &mut assignments, encoded_size_of)
.unwrap();
// then
let compact = CompactOf::<Runtime>::try_from(assignments.as_slice()).unwrap();
@@ -1412,11 +1412,7 @@ mod tests {
roll_to(25);
// given
let TrimHelpers {
mut assignments,
encoded_size_of,
..
} = trim_helpers();
let TrimHelpers { mut assignments, encoded_size_of, .. } = trim_helpers();
let compact = CompactOf::<Runtime>::try_from(assignments.as_slice()).unwrap();
let encoded_len = compact.encoded_size();
let compact_clone = compact.clone();
@@ -1426,7 +1422,8 @@ mod tests {
encoded_len as u32 - 1,
&mut assignments,
encoded_size_of,
).unwrap();
)
.unwrap();
// then
let compact = CompactOf::<Runtime>::try_from(assignments.as_slice()).unwrap();
@@ -1441,33 +1438,26 @@ mod tests {
roll_to(25);
// given
let TrimHelpers {
voters,
mut assignments,
encoded_size_of,
voter_index,
} = trim_helpers();
let TrimHelpers { voters, mut assignments, encoded_size_of, voter_index } =
trim_helpers();
let compact = CompactOf::<Runtime>::try_from(assignments.as_slice()).unwrap();
let encoded_len = compact.encoded_size() as u32;
let count = assignments.len();
let min_stake_voter = voters.iter()
let min_stake_voter = voters
.iter()
.map(|(id, weight, _)| (weight, id))
.min()
.and_then(|(_, id)| voter_index(id))
.unwrap();
// when
MultiPhase::trim_assignments_length(
encoded_len - 1,
&mut assignments,
encoded_size_of,
).unwrap();
MultiPhase::trim_assignments_length(encoded_len - 1, &mut assignments, encoded_size_of)
.unwrap();
// then
assert_eq!(assignments.len(), count - 1, "we must have removed exactly one assignment");
assert!(
assignments.iter()
.all(|IndexAssignment{ who, ..}| *who != min_stake_voter),
assignments.iter().all(|IndexAssignment { who, .. }| *who != min_stake_voter),
"min_stake_voter must no longer be in the set of voters",
);
});
@@ -36,6 +36,7 @@
// --template=./.maintain/frame-weight-template.hbs
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]