// Copyright (C) Parity Technologies (UK) Ltd. and Dijital Kurdistan Tech Institute
// This file is part of Pezkuwi.
// Pezkuwi is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Pezkuwi is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Pezkuwi. If not, see .
use crate::{
configuration, inclusion, initializer, paras,
paras::ParaKind,
paras_inherent,
scheduler::{
self,
common::{Assignment, AssignmentProvider},
},
session_info, shared,
};
use alloc::{
collections::{btree_map::BTreeMap, btree_set::BTreeSet, vec_deque::VecDeque},
vec,
vec::Vec,
};
use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec};
use pezframe_support::pezpallet_prelude::*;
use pezframe_system::pezpallet_prelude::*;
use pezkuwi_primitives::{
ApprovedPeerId, AvailabilityBitfield, BackedCandidate, CandidateCommitments,
CandidateDescriptorV2, CandidateHash, ClaimQueueOffset,
CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CompactStatement, CoreIndex,
CoreSelector, DisputeStatement, DisputeStatementSet, GroupIndex, HeadData, Id as ParaId,
IndexedVec, InherentData as TeyrchainsInherentData, InvalidDisputeStatementKind,
PersistedValidationData, SessionIndex, SigningContext, UMPSignal, UncheckedSigned,
ValidDisputeStatementKind, ValidationCode, ValidatorId, ValidatorIndex, ValidityAttestation,
UMP_SEPARATOR,
};
use pezsp_core::H256;
use pezsp_runtime::{
traits::{Header as HeaderT, One, TrailingZeroInput, Zero},
RuntimeAppPublic,
};
fn mock_validation_code() -> ValidationCode {
ValidationCode(vec![1, 2, 3])
}
/// Grab an account, seeded by a name and index.
///
/// This is directly from pezframe-benchmarking. Copy/pasted so we can use it when not compiling
/// with "features = runtime-benchmarks".
fn account(name: &'static str, index: u32, seed: u32) -> AccountId {
let entropy = (name, index, seed).using_encoded(pezsp_io::hashing::blake2_256);
AccountId::decode(&mut TrailingZeroInput::new(&entropy[..]))
.expect("infinite input; no invalid input; qed")
}
pub fn generate_validator_pairs(
validator_count: u32,
) -> Vec<(T::AccountId, ValidatorId)> {
(0..validator_count)
.map(|i| {
let public = ValidatorId::generate_pair(None);
// The account Id is not actually used anywhere, just necessary to fulfill the
// expected type of the `validators` param of `test_trigger_on_new_session`.
let account: T::AccountId = account("validator", i, i);
(account, public)
})
.collect()
}
/// Create a 32 byte slice based on the given number.
fn byte32_slice_from(n: u32) -> [u8; 32] {
let mut slice = [0u8; 32];
slice[31] = (n % (1 << 8)) as u8;
slice[30] = ((n >> 8) % (1 << 8)) as u8;
slice[29] = ((n >> 16) % (1 << 8)) as u8;
slice[28] = ((n >> 24) % (1 << 8)) as u8;
slice
}
/// Paras inherent `enter` benchmark scenario builder.
pub(crate) struct BenchBuilder {
/// Active validators. Validators should be declared prior to all other setup.
validators: Option>,
/// Starting block number; we expect it to get incremented on session setup.
block_number: BlockNumberFor,
/// Starting session; we expect it to get incremented on session setup.
session: SessionIndex,
/// Session we want the scenario to take place in. We will roll to this session.
target_session: u32,
/// Optionally set the max validators per core; otherwise uses the configuration value.
max_validators_per_core: Option,
/// Optionally set the max validators; otherwise uses the configuration value.
max_validators: Option,
/// Optionally set the number of dispute statements for each candidate.
dispute_statements: BTreeMap,
/// Session index of for each dispute. Index of slice corresponds to a core,
/// which is offset by the number of entries for `backed_and_concluding_paras`. I.E. if
/// `backed_and_concluding_paras` has 3 entries, the first index of `dispute_sessions`
/// will correspond to core index 3. There must be one entry for each core with a dispute
/// statement set.
dispute_sessions: Vec,
/// Paras here will both be backed in the inherent data and already occupying a core (which is
/// freed via bitfields).
///
/// Map from para id to number of validity votes. Core indices are generated based on
/// `elastic_paras` configuration. Each para id in `elastic_paras` gets the
/// specified amount of consecutive cores assigned to it. If a para id is not present
/// in `elastic_paras` it get assigned to a single core.
backed_and_concluding_paras: BTreeMap,
/// Paras which don't yet occupy a core, but will after the inherent has been processed.
backed_in_inherent_paras: BTreeMap,
/// Map from para id (seed) to number of chained candidates.
elastic_paras: BTreeMap,
/// Make every candidate include a code upgrade by setting this to `Some` where the interior
/// value is the byte length of the new code.
code_upgrade: Option,
/// Cores which should not be available when being populated with pending candidates.
unavailable_cores: Vec,
/// Use v2 candidate descriptor.
candidate_descriptor_v2: bool,
/// Send an approved peer ump signal. Only useful for v2 descriptors
approved_peer_signal: Option,
/// Apply custom changes to generated candidates
candidate_modifier: Option>,
_phantom: core::marker::PhantomData,
}
pub type CandidateModifier =
fn(CommittedCandidateReceipt) -> CommittedCandidateReceipt;
/// Paras inherent `enter` benchmark scenario.
#[cfg(any(feature = "runtime-benchmarks", test))]
pub(crate) struct Bench {
pub(crate) data: TeyrchainsInherentData>,
pub(crate) _session: u32,
pub(crate) _block_number: BlockNumberFor,
}
#[allow(dead_code)]
impl BenchBuilder {
/// Create a new `BenchBuilder` with some opinionated values that should work with the rest
/// of the functions in this implementation.
pub(crate) fn new() -> Self {
BenchBuilder {
validators: None,
block_number: Zero::zero(),
session: SessionIndex::from(0u32),
target_session: 2u32,
max_validators_per_core: None,
max_validators: None,
dispute_statements: BTreeMap::new(),
dispute_sessions: Default::default(),
backed_and_concluding_paras: Default::default(),
backed_in_inherent_paras: Default::default(),
elastic_paras: Default::default(),
code_upgrade: None,
unavailable_cores: vec![],
candidate_descriptor_v2: false,
approved_peer_signal: None,
candidate_modifier: None,
_phantom: core::marker::PhantomData::,
}
}
/// Set the session index for each dispute statement set (in other words, set the session the
/// the dispute statement set's relay chain block is from). Indexes of `dispute_sessions`
/// correspond to a core, which is offset by the number of entries for
/// `backed_and_concluding_paras`. I.E. if `backed_and_concluding_paras` cores has 3 entries,
/// the first index of `dispute_sessions` will correspond to core index 3.
///
/// Note that there must be an entry for each core with a dispute statement set.
pub(crate) fn set_dispute_sessions(mut self, dispute_sessions: impl AsRef<[u32]>) -> Self {
self.dispute_sessions = dispute_sessions.as_ref().to_vec();
self
}
/// Set the cores which should not be available when being populated with pending candidates.
pub(crate) fn set_unavailable_cores(mut self, unavailable_cores: Vec) -> Self {
self.unavailable_cores = unavailable_cores;
self
}
/// Set a map from para id seed to number of validity votes.
pub(crate) fn set_backed_and_concluding_paras(
mut self,
backed_and_concluding_paras: BTreeMap,
) -> Self {
self.backed_and_concluding_paras = backed_and_concluding_paras;
self
}
/// Set a map from para id seed to number of validity votes for votes in inherent data.
pub(crate) fn set_backed_in_inherent_paras(mut self, backed: BTreeMap) -> Self {
self.backed_in_inherent_paras = backed;
self
}
/// Set a map from para id seed to number of cores assigned to it.
pub(crate) fn set_elastic_paras(mut self, elastic_paras: BTreeMap) -> Self {
self.elastic_paras = elastic_paras;
self
}
/// Set to include a code upgrade for all backed candidates. The value will be the byte length
/// of the code.
pub(crate) fn set_code_upgrade(mut self, code_upgrade: impl Into