mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 06:21:11 +00:00
Multi-Block Election part 0: preparation and some cleanup. (#9442)
* Partially applied * Everything builds, need to implement compact encoding as well. * Fix some tests, add a ui test as well. * Fix everything and everything. * small nits * a bunch more rename * more reorg * more reorg * last nit of self-review * Seemingly fixed the build now * Fix build * make it work again * Update primitives/npos-elections/solution-type/src/lib.rs Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> * Update primitives/npos-elections/solution-type/src/lib.rs Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> * nits * factor out double type * fix try-build Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com>
This commit is contained in:
@@ -18,8 +18,8 @@
|
||||
//! The signed phase implementation.
|
||||
|
||||
use crate::{
|
||||
CompactOf, Config, ElectionCompute, Pallet, QueuedSolution, RawSolution, ReadySolution,
|
||||
SignedSubmissionIndices, SignedSubmissionNextIndex, SignedSubmissionsMap,
|
||||
Config, ElectionCompute, Pallet, QueuedSolution, RawSolution, ReadySolution,
|
||||
SignedSubmissionIndices, SignedSubmissionNextIndex, SignedSubmissionsMap, SolutionOf,
|
||||
SolutionOrSnapshotSize, Weight, WeightInfo,
|
||||
};
|
||||
use codec::{Decode, Encode, HasCompact};
|
||||
@@ -29,7 +29,7 @@ use frame_support::{
|
||||
DebugNoBound,
|
||||
};
|
||||
use sp_arithmetic::traits::SaturatedConversion;
|
||||
use sp_npos_elections::{is_score_better, CompactSolution, ElectionScore};
|
||||
use sp_npos_elections::{is_score_better, ElectionScore, NposSolution};
|
||||
use sp_runtime::{
|
||||
traits::{Saturating, Zero},
|
||||
RuntimeDebug,
|
||||
@@ -44,42 +44,40 @@ use sp_std::{
|
||||
///
|
||||
/// This is just a wrapper around [`RawSolution`] and some additional info.
|
||||
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default)]
|
||||
pub struct SignedSubmission<AccountId, Balance: HasCompact, CompactSolution> {
|
||||
pub struct SignedSubmission<AccountId, Balance: HasCompact, Solution> {
|
||||
/// Who submitted this solution.
|
||||
pub who: AccountId,
|
||||
/// The deposit reserved for storing this solution.
|
||||
pub deposit: Balance,
|
||||
/// The raw solution itself.
|
||||
pub solution: RawSolution<CompactSolution>,
|
||||
pub raw_solution: RawSolution<Solution>,
|
||||
/// The reward that should potentially be paid for this solution, if accepted.
|
||||
pub reward: Balance,
|
||||
}
|
||||
|
||||
impl<AccountId, Balance, CompactSolution> Ord
|
||||
for SignedSubmission<AccountId, Balance, CompactSolution>
|
||||
impl<AccountId, Balance, Solution> Ord for SignedSubmission<AccountId, Balance, Solution>
|
||||
where
|
||||
AccountId: Ord,
|
||||
Balance: Ord + HasCompact,
|
||||
CompactSolution: Ord,
|
||||
RawSolution<CompactSolution>: Ord,
|
||||
Solution: Ord,
|
||||
RawSolution<Solution>: Ord,
|
||||
{
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.solution
|
||||
self.raw_solution
|
||||
.score
|
||||
.cmp(&other.solution.score)
|
||||
.then_with(|| self.solution.cmp(&other.solution))
|
||||
.cmp(&other.raw_solution.score)
|
||||
.then_with(|| self.raw_solution.cmp(&other.raw_solution))
|
||||
.then_with(|| self.deposit.cmp(&other.deposit))
|
||||
.then_with(|| self.who.cmp(&other.who))
|
||||
}
|
||||
}
|
||||
|
||||
impl<AccountId, Balance, CompactSolution> PartialOrd
|
||||
for SignedSubmission<AccountId, Balance, CompactSolution>
|
||||
impl<AccountId, Balance, Solution> PartialOrd for SignedSubmission<AccountId, Balance, Solution>
|
||||
where
|
||||
AccountId: Ord,
|
||||
Balance: Ord + HasCompact,
|
||||
CompactSolution: Ord,
|
||||
RawSolution<CompactSolution>: Ord,
|
||||
Solution: Ord,
|
||||
RawSolution<Solution>: Ord,
|
||||
{
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
@@ -95,7 +93,7 @@ pub type NegativeImbalanceOf<T> = <<T as Config>::Currency as Currency<
|
||||
<T as frame_system::Config>::AccountId,
|
||||
>>::NegativeImbalance;
|
||||
pub type SignedSubmissionOf<T> =
|
||||
SignedSubmission<<T as frame_system::Config>::AccountId, BalanceOf<T>, CompactOf<T>>;
|
||||
SignedSubmission<<T as frame_system::Config>::AccountId, BalanceOf<T>, SolutionOf<T>>;
|
||||
|
||||
pub type SubmissionIndicesOf<T> =
|
||||
BoundedBTreeMap<ElectionScore, u32, <T as Config>::SignedMaxSubmissions>;
|
||||
@@ -270,13 +268,13 @@ impl<T: Config> SignedSubmissions<T> {
|
||||
// verify the expectation that we never reuse an index
|
||||
debug_assert!(!self.indices.values().any(|&idx| idx == self.next_idx));
|
||||
|
||||
let weakest = match self.indices.try_insert(submission.solution.score, self.next_idx) {
|
||||
let weakest = match self.indices.try_insert(submission.raw_solution.score, self.next_idx) {
|
||||
Ok(Some(prev_idx)) => {
|
||||
// a submission of equal score was already present in the set;
|
||||
// no point editing the actual backing map as we know that the newer solution can't
|
||||
// be better than the old. However, we do need to put the old value back.
|
||||
self.indices
|
||||
.try_insert(submission.solution.score, prev_idx)
|
||||
.try_insert(submission.raw_solution.score, prev_idx)
|
||||
.expect("didn't change the map size; qed");
|
||||
return InsertResult::NotInserted
|
||||
},
|
||||
@@ -354,8 +352,8 @@ impl<T: Config> Pallet<T> {
|
||||
Self::snapshot_metadata().unwrap_or_default();
|
||||
|
||||
while let Some(best) = all_submissions.pop_last() {
|
||||
let SignedSubmission { solution, who, deposit, reward } = best;
|
||||
let active_voters = solution.compact.voter_count() as u32;
|
||||
let SignedSubmission { raw_solution, who, deposit, reward } = best;
|
||||
let active_voters = raw_solution.solution.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();
|
||||
@@ -363,7 +361,7 @@ impl<T: Config> Pallet<T> {
|
||||
};
|
||||
// the feasibility check itself has some weight
|
||||
weight = weight.saturating_add(feasibility_weight);
|
||||
match Self::feasibility_check(solution, ElectionCompute::Signed) {
|
||||
match Self::feasibility_check(raw_solution, ElectionCompute::Signed) {
|
||||
Ok(ready_solution) => {
|
||||
Self::finalize_signed_phase_accept_solution(
|
||||
ready_solution,
|
||||
@@ -447,14 +445,14 @@ impl<T: Config> Pallet<T> {
|
||||
|
||||
/// The feasibility weight of the given raw solution.
|
||||
pub fn feasibility_weight_of(
|
||||
solution: &RawSolution<CompactOf<T>>,
|
||||
raw_solution: &RawSolution<SolutionOf<T>>,
|
||||
size: SolutionOrSnapshotSize,
|
||||
) -> Weight {
|
||||
T::WeightInfo::feasibility_check(
|
||||
size.voters,
|
||||
size.targets,
|
||||
solution.compact.voter_count() as u32,
|
||||
solution.compact.unique_targets().len() as u32,
|
||||
raw_solution.solution.voter_count() as u32,
|
||||
raw_solution.solution.unique_targets().len() as u32,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -466,12 +464,12 @@ impl<T: Config> Pallet<T> {
|
||||
/// 2. a per-byte deposit, for renting the state usage.
|
||||
/// 3. a per-weight deposit, for the potential weight usage in an upcoming on_initialize
|
||||
pub fn deposit_for(
|
||||
solution: &RawSolution<CompactOf<T>>,
|
||||
raw_solution: &RawSolution<SolutionOf<T>>,
|
||||
size: SolutionOrSnapshotSize,
|
||||
) -> BalanceOf<T> {
|
||||
let encoded_len: u32 = solution.encoded_size().saturated_into();
|
||||
let encoded_len: u32 = raw_solution.encoded_size().saturated_into();
|
||||
let encoded_len: BalanceOf<T> = encoded_len.into();
|
||||
let feasibility_weight = Self::feasibility_weight_of(solution, size);
|
||||
let feasibility_weight = Self::feasibility_weight_of(raw_solution, size);
|
||||
|
||||
let len_deposit = T::SignedDepositByte::get().saturating_mul(encoded_len);
|
||||
let weight_deposit =
|
||||
@@ -497,7 +495,7 @@ mod tests {
|
||||
|
||||
fn submit_with_witness(
|
||||
origin: Origin,
|
||||
solution: RawSolution<CompactOf<Runtime>>,
|
||||
solution: RawSolution<SolutionOf<Runtime>>,
|
||||
) -> DispatchResult {
|
||||
MultiPhase::submit(
|
||||
origin,
|
||||
@@ -663,7 +661,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
MultiPhase::signed_submissions()
|
||||
.iter()
|
||||
.map(|s| s.solution.score[0])
|
||||
.map(|s| s.raw_solution.score[0])
|
||||
.collect::<Vec<_>>(),
|
||||
vec![5, 6, 7, 8, 9]
|
||||
);
|
||||
@@ -676,7 +674,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
MultiPhase::signed_submissions()
|
||||
.iter()
|
||||
.map(|s| s.solution.score[0])
|
||||
.map(|s| s.raw_solution.score[0])
|
||||
.collect::<Vec<_>>(),
|
||||
vec![6, 7, 8, 9, 20]
|
||||
);
|
||||
@@ -701,7 +699,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
MultiPhase::signed_submissions()
|
||||
.iter()
|
||||
.map(|s| s.solution.score[0])
|
||||
.map(|s| s.raw_solution.score[0])
|
||||
.collect::<Vec<_>>(),
|
||||
vec![4, 6, 7, 8, 9],
|
||||
);
|
||||
@@ -714,7 +712,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
MultiPhase::signed_submissions()
|
||||
.iter()
|
||||
.map(|s| s.solution.score[0])
|
||||
.map(|s| s.raw_solution.score[0])
|
||||
.collect::<Vec<_>>(),
|
||||
vec![5, 6, 7, 8, 9],
|
||||
);
|
||||
@@ -759,7 +757,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
MultiPhase::signed_submissions()
|
||||
.iter()
|
||||
.map(|s| s.solution.score[0])
|
||||
.map(|s| s.raw_solution.score[0])
|
||||
.collect::<Vec<_>>(),
|
||||
vec![5, 6, 7]
|
||||
);
|
||||
@@ -828,33 +826,33 @@ mod tests {
|
||||
roll_to(15);
|
||||
assert!(MultiPhase::current_phase().is_signed());
|
||||
|
||||
let (solution, witness) = MultiPhase::mine_solution(2).unwrap();
|
||||
let (raw, 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,
|
||||
raw.solution.voter_count() as u32,
|
||||
raw.solution.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!(raw.solution.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), raw.clone()));
|
||||
|
||||
<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),
|
||||
submit_with_witness(Origin::signed(99), raw),
|
||||
Error::<Runtime>::SignedTooMuchWeight,
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insufficient_deposit_doesnt_store_submission() {
|
||||
fn insufficient_deposit_does_not_store_submission() {
|
||||
ExtBuilder::default().build_and_execute(|| {
|
||||
roll_to(15);
|
||||
assert!(MultiPhase::current_phase().is_signed());
|
||||
|
||||
Reference in New Issue
Block a user