mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 00:01:09 +00:00
8a8b4f99c3
* Rename and move sp-phragmen * More renames for equalise * Update main module doc * Fix line width * Line width
154 lines
4.4 KiB
Rust
154 lines
4.4 KiB
Rust
// This file is part of Substrate.
|
|
|
|
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
//! Fuzzing for the reduce algorithm.
|
|
//!
|
|
//! It that reduce always return a new set og edges in which the bound is kept (`edges_after <= m +
|
|
//! n,`) and the result must effectively be the same, meaning that the same support map should be
|
|
//! computable from both.
|
|
//!
|
|
//! # Running
|
|
//!
|
|
//! Run with `cargo hfuzz run reduce`. `honggfuzz`.
|
|
//!
|
|
//! # Debugging a panic
|
|
//!
|
|
//! Once a panic is found, it can be debugged with
|
|
//! `cargo hfuzz run-debug reduce hfuzz_workspace/reduce/*.fuzz`.
|
|
|
|
use honggfuzz::fuzz;
|
|
|
|
mod common;
|
|
use common::to_range;
|
|
use sp_npos_elections::{StakedAssignment, ExtendedBalance, build_support_map, reduce};
|
|
use rand::{self, Rng, SeedableRng, RngCore};
|
|
|
|
type Balance = u128;
|
|
type AccountId = u64;
|
|
|
|
/// Or any other token type.
|
|
const KSM: Balance = 1_000_000_000_000;
|
|
|
|
fn main() {
|
|
loop {
|
|
fuzz!(|data: (usize, usize, u64)| {
|
|
let (mut voter_count, mut target_count, seed) = data;
|
|
let rng = rand::rngs::SmallRng::seed_from_u64(seed);
|
|
target_count = to_range(target_count, 100, 1000);
|
|
voter_count = to_range(voter_count, 100, 2000);
|
|
let (assignments, winners) = generate_random_phragmen_assignment(
|
|
voter_count,
|
|
target_count,
|
|
8,
|
|
8,
|
|
rng
|
|
);
|
|
reduce_and_compare(&assignments, &winners);
|
|
});
|
|
}
|
|
}
|
|
|
|
fn generate_random_phragmen_assignment(
|
|
voter_count: usize,
|
|
target_count: usize,
|
|
avg_edge_per_voter: usize,
|
|
edge_per_voter_var: usize,
|
|
mut rng: impl RngCore,
|
|
) -> (Vec<StakedAssignment<AccountId>>, Vec<AccountId>) {
|
|
// prefix to distinguish the voter and target account ranges.
|
|
let target_prefix = 1_000_000;
|
|
assert!(voter_count < target_prefix);
|
|
|
|
let mut assignments = Vec::with_capacity(voter_count as usize);
|
|
let mut winners: Vec<AccountId> = Vec::new();
|
|
|
|
let all_targets = (target_prefix..(target_prefix + target_count))
|
|
.map(|a| a as AccountId)
|
|
.collect::<Vec<AccountId>>();
|
|
|
|
(1..=voter_count).for_each(|acc| {
|
|
let mut targets_to_chose_from = all_targets.clone();
|
|
let targets_to_chose = if edge_per_voter_var > 0 { rng.gen_range(
|
|
avg_edge_per_voter - edge_per_voter_var,
|
|
avg_edge_per_voter + edge_per_voter_var,
|
|
) } else { avg_edge_per_voter };
|
|
|
|
let distribution = (0..targets_to_chose).map(|_| {
|
|
let target = targets_to_chose_from.remove(rng.gen_range(0, targets_to_chose_from.len()));
|
|
if winners.iter().find(|w| **w == target).is_none() {
|
|
winners.push(target.clone());
|
|
}
|
|
(target, rng.gen_range(1 * KSM, 100 * KSM))
|
|
}).collect::<Vec<(AccountId, ExtendedBalance)>>();
|
|
|
|
assignments.push(StakedAssignment {
|
|
who: (acc as AccountId),
|
|
distribution,
|
|
});
|
|
});
|
|
|
|
(assignments, winners)
|
|
}
|
|
|
|
fn assert_assignments_equal(
|
|
winners: &Vec<AccountId>,
|
|
ass1: &Vec<StakedAssignment<AccountId>>,
|
|
ass2: &Vec<StakedAssignment<AccountId>>,
|
|
) {
|
|
|
|
let (support_1, _) = build_support_map::<AccountId>(winners, ass1);
|
|
let (support_2, _) = build_support_map::<AccountId>(winners, ass2);
|
|
|
|
for (who, support) in support_1.iter() {
|
|
assert_eq!(support.total, support_2.get(who).unwrap().total);
|
|
}
|
|
}
|
|
|
|
fn reduce_and_compare(
|
|
assignment: &Vec<StakedAssignment<AccountId>>,
|
|
winners: &Vec<AccountId>,
|
|
) {
|
|
let mut altered_assignment = assignment.clone();
|
|
let n = assignment.len() as u32;
|
|
let m = winners.len() as u32;
|
|
|
|
let edges_before = assignment_len(&assignment);
|
|
let num_changed = reduce(&mut altered_assignment);
|
|
let edges_after = edges_before - num_changed;
|
|
|
|
assert!(
|
|
edges_after <= m + n,
|
|
"reduce bound not satisfied. n = {}, m = {}, edges after reduce = {} (removed {})",
|
|
n,
|
|
m,
|
|
edges_after,
|
|
num_changed,
|
|
);
|
|
|
|
assert_assignments_equal(
|
|
winners,
|
|
&assignment,
|
|
&altered_assignment,
|
|
);
|
|
}
|
|
|
|
fn assignment_len(assignments: &[StakedAssignment<AccountId>]) -> u32 {
|
|
let mut counter = 0;
|
|
assignments.iter().for_each(|x| x.distribution.iter().for_each(|_| counter += 1));
|
|
counter
|
|
}
|