feat: Rebrand Polkadot/Substrate references to PezkuwiChain
This commit systematically rebrands various references from Parity Technologies' Polkadot/Substrate ecosystem to PezkuwiChain within the kurdistan-sdk. Key changes include: - Updated external repository URLs (zombienet-sdk, parity-db, parity-scale-codec, wasm-instrument) to point to pezkuwichain forks. - Modified internal documentation and code comments to reflect PezkuwiChain naming and structure. - Replaced direct references to with or specific paths within the for XCM, Pezkuwi, and other modules. - Cleaned up deprecated issue and PR references in various and files, particularly in and modules. - Adjusted image and logo URLs in documentation to point to PezkuwiChain assets. - Removed or rephrased comments related to external Polkadot/Substrate PRs and issues. This is a significant step towards fully customizing the SDK for the PezkuwiChain ecosystem.
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) 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.
|
||||
|
||||
//! Common fuzzing utils.
|
||||
|
||||
// Each function will be used based on which fuzzer binary is being used.
|
||||
#![allow(dead_code)]
|
||||
|
||||
use rand::{self, seq::SliceRandom, Rng, RngCore};
|
||||
use pezsp_npos_elections::{phragmms, seq_phragmen, BalancingConfig, ElectionResult, VoteWeight};
|
||||
use pezsp_runtime::Perbill;
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
|
||||
/// converts x into the range [a, b] in a pseudo-fair way.
|
||||
pub fn to_range(x: usize, a: usize, b: usize) -> usize {
|
||||
// does not work correctly if b < 2 * a
|
||||
assert!(b >= 2 * a);
|
||||
let collapsed = x % b;
|
||||
if collapsed >= a {
|
||||
collapsed
|
||||
} else {
|
||||
collapsed + a
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ElectionType {
|
||||
Phragmen(Option<BalancingConfig>),
|
||||
Phragmms(Option<BalancingConfig>),
|
||||
}
|
||||
|
||||
pub type AccountId = u64;
|
||||
|
||||
/// Generate a set of inputs suitable for fuzzing an election algorithm
|
||||
///
|
||||
/// Given parameters governing how many candidates and voters should exist, generates a voting
|
||||
/// scenario suitable for fuzz-testing an election algorithm.
|
||||
///
|
||||
/// The returned candidate list is sorted. This sorting property should not affect the result of the
|
||||
/// calculation.
|
||||
///
|
||||
/// The returned voters list is sorted. This enables binary searching for a particular voter by
|
||||
/// account id. This sorting property should not affect the results of the calculation.
|
||||
///
|
||||
/// Each voter's selection of candidates to vote for is sorted.
|
||||
///
|
||||
/// Note that this does not generate balancing parameters.
|
||||
pub fn generate_random_npos_inputs(
|
||||
candidate_count: usize,
|
||||
voter_count: usize,
|
||||
mut rng: impl Rng,
|
||||
) -> (usize, Vec<AccountId>, Vec<(AccountId, VoteWeight, Vec<AccountId>)>) {
|
||||
// cache for fast generation of unique candidate and voter ids
|
||||
let mut used_ids = HashSet::with_capacity(candidate_count + voter_count);
|
||||
|
||||
// always generate a sensible desired number of candidates: elections are uninteresting if we
|
||||
// desire 0 candidates, or a number of candidates >= the actual number of candidates present
|
||||
let rounds = rng.gen_range(1..candidate_count);
|
||||
|
||||
// candidates are easy: just a completely random set of IDs
|
||||
let mut candidates: Vec<AccountId> = Vec::with_capacity(candidate_count);
|
||||
for _ in 0..candidate_count {
|
||||
let mut id = rng.gen();
|
||||
// insert returns `false` when the value was already present
|
||||
while !used_ids.insert(id) {
|
||||
id = rng.gen();
|
||||
}
|
||||
candidates.push(id);
|
||||
}
|
||||
candidates.sort();
|
||||
candidates.dedup();
|
||||
assert_eq!(candidates.len(), candidate_count);
|
||||
|
||||
let mut voters = Vec::with_capacity(voter_count);
|
||||
for _ in 0..voter_count {
|
||||
let mut id = rng.gen();
|
||||
// insert returns `false` when the value was already present
|
||||
while !used_ids.insert(id) {
|
||||
id = rng.gen();
|
||||
}
|
||||
|
||||
let vote_weight = rng.gen();
|
||||
|
||||
// it's not interesting if a voter chooses 0 or all candidates, so rule those cases out.
|
||||
let n_candidates_chosen = rng.gen_range(1..candidates.len());
|
||||
|
||||
let mut chosen_candidates = Vec::with_capacity(n_candidates_chosen);
|
||||
chosen_candidates.extend(candidates.choose_multiple(&mut rng, n_candidates_chosen));
|
||||
chosen_candidates.sort();
|
||||
voters.push((id, vote_weight, chosen_candidates));
|
||||
}
|
||||
|
||||
voters.sort();
|
||||
voters.dedup_by_key(|(id, _weight, _chosen_candidates)| *id);
|
||||
assert_eq!(voters.len(), voter_count);
|
||||
|
||||
(rounds, candidates, voters)
|
||||
}
|
||||
|
||||
pub fn generate_random_npos_result(
|
||||
voter_count: u64,
|
||||
target_count: u64,
|
||||
to_elect: usize,
|
||||
mut rng: impl RngCore,
|
||||
election_type: ElectionType,
|
||||
) -> (
|
||||
ElectionResult<AccountId, Perbill>,
|
||||
Vec<AccountId>,
|
||||
Vec<(AccountId, VoteWeight, Vec<AccountId>)>,
|
||||
BTreeMap<AccountId, VoteWeight>,
|
||||
) {
|
||||
let prefix = 100_000;
|
||||
// Note, it is important that stakes are always bigger than ed.
|
||||
let base_stake: u64 = 1_000_000_000_000;
|
||||
let ed: u64 = base_stake;
|
||||
|
||||
let mut candidates = Vec::with_capacity(target_count as usize);
|
||||
let mut stake_of: BTreeMap<AccountId, VoteWeight> = BTreeMap::new();
|
||||
|
||||
(1..=target_count).for_each(|acc| {
|
||||
candidates.push(acc);
|
||||
let stake_var = rng.gen_range(ed..100 * ed);
|
||||
stake_of.insert(acc, base_stake + stake_var);
|
||||
});
|
||||
|
||||
let mut voters = Vec::with_capacity(voter_count as usize);
|
||||
(prefix..=(prefix + voter_count)).for_each(|acc| {
|
||||
let edge_per_this_voter = rng.gen_range(1..candidates.len());
|
||||
// all possible targets
|
||||
let mut all_targets = candidates.clone();
|
||||
// we remove and pop into `targets` `edge_per_this_voter` times.
|
||||
let targets = (0..edge_per_this_voter)
|
||||
.map(|_| {
|
||||
let upper = all_targets.len() - 1;
|
||||
let idx = rng.gen_range(0..upper);
|
||||
all_targets.remove(idx)
|
||||
})
|
||||
.collect::<Vec<AccountId>>();
|
||||
|
||||
let stake_var = rng.gen_range(ed..100 * ed);
|
||||
let stake = base_stake + stake_var;
|
||||
stake_of.insert(acc, stake);
|
||||
voters.push((acc, stake, targets));
|
||||
});
|
||||
|
||||
(
|
||||
match election_type {
|
||||
ElectionType::Phragmen(conf) =>
|
||||
seq_phragmen(to_elect, candidates.clone(), voters.clone(), conf).unwrap(),
|
||||
ElectionType::Phragmms(conf) =>
|
||||
phragmms(to_elect, candidates.clone(), voters.clone(), conf).unwrap(),
|
||||
},
|
||||
candidates,
|
||||
voters,
|
||||
stake_of,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) 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 sequential phragmen with potential balancing.
|
||||
|
||||
mod common;
|
||||
|
||||
use common::*;
|
||||
use honggfuzz::fuzz;
|
||||
use rand::{self, SeedableRng};
|
||||
use pezsp_npos_elections::{
|
||||
assignment_ratio_to_staked_normalized, seq_phragmen, to_supports, BalancingConfig,
|
||||
ElectionResult, EvaluateSupport, VoteWeight,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|data: (usize, usize, usize, usize, u64)| {
|
||||
let (mut target_count, mut voter_count, mut iterations, mut to_elect, seed) = data;
|
||||
let rng = rand::rngs::SmallRng::seed_from_u64(seed);
|
||||
target_count = to_range(target_count, 100, 200);
|
||||
voter_count = to_range(voter_count, 100, 200);
|
||||
iterations = to_range(iterations, 0, 30);
|
||||
to_elect = to_range(to_elect, 25, target_count);
|
||||
|
||||
println!(
|
||||
"++ [voter_count: {} / target_count:{} / to_elect:{} / iterations:{}]",
|
||||
voter_count, target_count, to_elect, iterations,
|
||||
);
|
||||
let (unbalanced, candidates, voters, stake_of_tree) = generate_random_npos_result(
|
||||
voter_count as u64,
|
||||
target_count as u64,
|
||||
to_elect,
|
||||
rng,
|
||||
ElectionType::Phragmen(None),
|
||||
);
|
||||
|
||||
let stake_of = |who: &AccountId| -> VoteWeight { *stake_of_tree.get(who).unwrap() };
|
||||
|
||||
let unbalanced_score = {
|
||||
let staked =
|
||||
assignment_ratio_to_staked_normalized(unbalanced.assignments, &stake_of)
|
||||
.unwrap();
|
||||
let score = to_supports(staked.as_ref()).evaluate();
|
||||
|
||||
if score.minimal_stake == 0 {
|
||||
// such cases cannot be improved by balancing.
|
||||
return;
|
||||
}
|
||||
score
|
||||
};
|
||||
|
||||
if iterations > 0 {
|
||||
let config = BalancingConfig { iterations, tolerance: 0 };
|
||||
let balanced: ElectionResult<AccountId, pezsp_runtime::Perbill> =
|
||||
seq_phragmen(to_elect, candidates, voters, Some(config)).unwrap();
|
||||
|
||||
let balanced_score = {
|
||||
let staked =
|
||||
assignment_ratio_to_staked_normalized(balanced.assignments, &stake_of)
|
||||
.unwrap();
|
||||
to_supports(staked.as_ref()).evaluate()
|
||||
};
|
||||
|
||||
let enhance = balanced_score.strict_better(unbalanced_score);
|
||||
|
||||
println!(
|
||||
"iter = {} // {:?} -> {:?} [{}]",
|
||||
iterations, unbalanced_score, balanced_score, enhance,
|
||||
);
|
||||
|
||||
// The only guarantee of balancing is such that the first and third element of the
|
||||
// score cannot decrease.
|
||||
assert!(
|
||||
balanced_score.minimal_stake >= unbalanced_score.minimal_stake &&
|
||||
balanced_score.sum_stake == unbalanced_score.sum_stake &&
|
||||
balanced_score.sum_stake_squared <= unbalanced_score.sum_stake_squared
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) 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 which ensures that running unbalanced sequential phragmen always produces a result
|
||||
//! which satisfies our PJR checker.
|
||||
//!
|
||||
//! ## Running a single iteration
|
||||
//!
|
||||
//! Honggfuzz shuts down each individual loop iteration after a configurable time limit.
|
||||
//! It can be helpful to run a single iteration on your hardware to help benchmark how long that
|
||||
//! time limit should reasonably be. Simply run the program without the `fuzzing` configuration to
|
||||
//! run a single iteration: `cargo run --bin phragmen_pjr`.
|
||||
//!
|
||||
//! ## Running
|
||||
//!
|
||||
//! Run with `HFUZZ_RUN_ARGS="-t 10" cargo hfuzz run phragmen_pjr`.
|
||||
//!
|
||||
//! Note the environment variable: by default, `cargo hfuzz` shuts down each iteration after 1
|
||||
//! second of runtime. We significantly increase that to ensure that the fuzzing gets a chance to
|
||||
//! complete. Running a single iteration can help determine an appropriate value for this parameter.
|
||||
//!
|
||||
//! ## Debugging a panic
|
||||
//!
|
||||
//! Once a panic is found, it can be debugged with
|
||||
//! `HFUZZ_RUN_ARGS="-t 10" cargo hfuzz run-debug phragmen_pjr hfuzz_workspace/phragmen_pjr/*.fuzz`.
|
||||
|
||||
#[cfg(fuzzing)]
|
||||
use honggfuzz::fuzz;
|
||||
|
||||
#[cfg(not(fuzzing))]
|
||||
use clap::Parser;
|
||||
|
||||
mod common;
|
||||
use common::{generate_random_npos_inputs, to_range};
|
||||
use rand::{self, SeedableRng};
|
||||
use pezsp_npos_elections::{pjr_check_core, seq_phragmen_core, setup_inputs, standard_threshold};
|
||||
|
||||
type AccountId = u64;
|
||||
|
||||
const MIN_CANDIDATES: usize = 250;
|
||||
const MAX_CANDIDATES: usize = 1000;
|
||||
const MIN_VOTERS: usize = 500;
|
||||
const MAX_VOTERS: usize = 2500;
|
||||
|
||||
#[cfg(fuzzing)]
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|data: (usize, usize, u64)| {
|
||||
let (candidate_count, voter_count, seed) = data;
|
||||
iteration(candidate_count, voter_count, seed);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(fuzzing))]
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(author, version, about)]
|
||||
struct Opt {
|
||||
/// How many candidates participate in this election
|
||||
#[arg(short, long)]
|
||||
candidates: Option<usize>,
|
||||
|
||||
/// How many voters participate in this election
|
||||
#[arg(short, long)]
|
||||
voters: Option<usize>,
|
||||
|
||||
/// Random seed to use in this election
|
||||
#[arg(long)]
|
||||
seed: Option<u64>,
|
||||
}
|
||||
|
||||
#[cfg(not(fuzzing))]
|
||||
fn main() {
|
||||
let opt = Opt::parse();
|
||||
// candidates and voters by default use the maxima, which turn out to be one less than
|
||||
// the constant.
|
||||
iteration(
|
||||
opt.candidates.unwrap_or(MAX_CANDIDATES - 1),
|
||||
opt.voters.unwrap_or(MAX_VOTERS - 1),
|
||||
opt.seed.unwrap_or_default(),
|
||||
);
|
||||
}
|
||||
|
||||
fn iteration(mut candidate_count: usize, mut voter_count: usize, seed: u64) {
|
||||
let rng = rand::rngs::SmallRng::seed_from_u64(seed);
|
||||
candidate_count = to_range(candidate_count, MIN_CANDIDATES, MAX_CANDIDATES);
|
||||
voter_count = to_range(voter_count, MIN_VOTERS, MAX_VOTERS);
|
||||
|
||||
let (rounds, candidates, voters) =
|
||||
generate_random_npos_inputs(candidate_count, voter_count, rng);
|
||||
|
||||
let (candidates, voters) = setup_inputs(candidates, voters);
|
||||
|
||||
// Run seq-phragmen
|
||||
let (candidates, voters) = seq_phragmen_core::<AccountId>(rounds, candidates, voters)
|
||||
.expect("seq_phragmen must succeed");
|
||||
|
||||
let threshold = standard_threshold(rounds, voters.iter().map(|voter| voter.budget()));
|
||||
|
||||
assert!(
|
||||
pjr_check_core(&candidates, &voters, threshold).is_ok(),
|
||||
"unbalanced sequential phragmen must satisfy PJR",
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) 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 phragmms.
|
||||
|
||||
mod common;
|
||||
|
||||
use common::*;
|
||||
use honggfuzz::fuzz;
|
||||
use rand::{self, SeedableRng};
|
||||
use pezsp_npos_elections::{
|
||||
assignment_ratio_to_staked_normalized, phragmms, to_supports, BalancingConfig, ElectionResult,
|
||||
EvaluateSupport, VoteWeight,
|
||||
};
|
||||
use pezsp_runtime::Perbill;
|
||||
|
||||
fn main() {
|
||||
loop {
|
||||
fuzz!(|data: (usize, usize, usize, usize, u64)| {
|
||||
let (mut target_count, mut voter_count, mut iterations, mut to_elect, seed) = data;
|
||||
let rng = rand::rngs::SmallRng::seed_from_u64(seed);
|
||||
target_count = to_range(target_count, 100, 200);
|
||||
voter_count = to_range(voter_count, 100, 200);
|
||||
iterations = to_range(iterations, 5, 30);
|
||||
to_elect = to_range(to_elect, 25, target_count);
|
||||
|
||||
println!(
|
||||
"++ [voter_count: {} / target_count:{} / to_elect:{} / iterations:{}]",
|
||||
voter_count, target_count, to_elect, iterations,
|
||||
);
|
||||
let (unbalanced, candidates, voters, stake_of_tree) = generate_random_npos_result(
|
||||
voter_count as u64,
|
||||
target_count as u64,
|
||||
to_elect,
|
||||
rng,
|
||||
ElectionType::Phragmms(None),
|
||||
);
|
||||
|
||||
let stake_of = |who: &AccountId| -> VoteWeight { *stake_of_tree.get(who).unwrap() };
|
||||
|
||||
let unbalanced_score = {
|
||||
let staked =
|
||||
assignment_ratio_to_staked_normalized(unbalanced.assignments, &stake_of)
|
||||
.unwrap();
|
||||
let score = to_supports(&staked).evaluate();
|
||||
|
||||
if score.minimal_stake == 0 {
|
||||
// such cases cannot be improved by balancing.
|
||||
return;
|
||||
}
|
||||
score
|
||||
};
|
||||
|
||||
let config = BalancingConfig { iterations, tolerance: 0 };
|
||||
let balanced: ElectionResult<AccountId, Perbill> =
|
||||
phragmms(to_elect, candidates, voters, Some(config)).unwrap();
|
||||
|
||||
let balanced_score = {
|
||||
let staked =
|
||||
assignment_ratio_to_staked_normalized(balanced.assignments, &stake_of).unwrap();
|
||||
to_supports(staked.as_ref()).evaluate()
|
||||
};
|
||||
|
||||
let enhance = balanced_score.strict_better(unbalanced_score);
|
||||
|
||||
println!(
|
||||
"iter = {} // {:?} -> {:?} [{}]",
|
||||
iterations, unbalanced_score, balanced_score, enhance,
|
||||
);
|
||||
|
||||
// The only guarantee of balancing is such that the first and third element of the score
|
||||
// cannot decrease.
|
||||
assert!(
|
||||
balanced_score.minimal_stake >= unbalanced_score.minimal_stake &&
|
||||
balanced_score.sum_stake == unbalanced_score.sum_stake &&
|
||||
balanced_score.sum_stake_squared <= unbalanced_score.sum_stake_squared
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) 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 rand::{self, Rng, RngCore, SeedableRng};
|
||||
use pezsp_npos_elections::{reduce, to_support_map, ExtendedBalance, StakedAssignment};
|
||||
|
||||
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().all(|w| *w != target) {
|
||||
winners.push(target);
|
||||
}
|
||||
(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(
|
||||
ass1: &Vec<StakedAssignment<AccountId>>,
|
||||
ass2: &Vec<StakedAssignment<AccountId>>,
|
||||
) {
|
||||
let support_1 = to_support_map::<AccountId>(ass1);
|
||||
let support_2 = to_support_map::<AccountId>(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(&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
|
||||
}
|
||||
Reference in New Issue
Block a user