feat: initialize Kurdistan SDK - independent fork of Polkadot SDK
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
use bitvec::{bitvec, prelude::Lsb0};
|
||||
use frame_benchmarking::v2::*;
|
||||
use pallet_message_queue as mq;
|
||||
use pezkuwi_primitives::{
|
||||
CandidateCommitments, CommittedCandidateReceiptV2 as CommittedCandidateReceipt, HrmpChannelId,
|
||||
OutboundHrmpMessage, SessionIndex,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
use crate::{
|
||||
builder::generate_validator_pairs,
|
||||
configuration,
|
||||
hrmp::{HrmpChannel, HrmpChannels},
|
||||
initializer, HeadData, ValidationCode,
|
||||
};
|
||||
|
||||
fn create_candidate_commitments<T: crate::hrmp::pallet::Config>(
|
||||
para_id: ParaId,
|
||||
head_data: HeadData,
|
||||
max_msg_len: usize,
|
||||
ump_msg_count: u32,
|
||||
hrmp_msg_count: u32,
|
||||
code_upgrade: bool,
|
||||
) -> CandidateCommitments {
|
||||
let upward_messages = {
|
||||
let unbounded = create_messages(max_msg_len, ump_msg_count as _);
|
||||
BoundedVec::truncate_from(unbounded)
|
||||
};
|
||||
|
||||
let horizontal_messages = {
|
||||
let unbounded = create_messages(max_msg_len, hrmp_msg_count as _);
|
||||
|
||||
for n in 0..unbounded.len() {
|
||||
let channel_id = HrmpChannelId { sender: para_id, recipient: para_id + n as u32 + 1 };
|
||||
HrmpChannels::<T>::insert(
|
||||
&channel_id,
|
||||
HrmpChannel {
|
||||
sender_deposit: 42,
|
||||
recipient_deposit: 42,
|
||||
max_capacity: 10_000_000,
|
||||
max_total_size: 1_000_000_000,
|
||||
max_message_size: 10_000_000,
|
||||
msg_count: 0,
|
||||
total_size: 0,
|
||||
mqc_head: None,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
let unbounded = unbounded
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(n, data)| OutboundHrmpMessage { recipient: para_id + n as u32 + 1, data })
|
||||
.collect();
|
||||
BoundedVec::truncate_from(unbounded)
|
||||
};
|
||||
|
||||
let new_validation_code = code_upgrade.then_some(ValidationCode(vec![42_u8; 1024]));
|
||||
|
||||
CandidateCommitments::<u32> {
|
||||
upward_messages,
|
||||
horizontal_messages,
|
||||
new_validation_code,
|
||||
head_data,
|
||||
processed_downward_messages: 0,
|
||||
hrmp_watermark: 10,
|
||||
}
|
||||
}
|
||||
|
||||
fn create_messages(msg_len: usize, n_msgs: usize) -> Vec<Vec<u8>> {
|
||||
let best_number = 73_u8; // Chuck Norris of numbers
|
||||
vec![vec![best_number; msg_len]; n_msgs]
|
||||
}
|
||||
|
||||
#[benchmarks(where T: mq::Config + configuration::Config + initializer::Config)]
|
||||
mod benchmarks {
|
||||
use super::*;
|
||||
|
||||
#[benchmark]
|
||||
fn enact_candidate(u: Linear<0, 2>, h: Linear<0, 2>, c: Linear<0, 1>) {
|
||||
let para = 42_u32.into(); // not especially important.
|
||||
|
||||
let max_len = mq::MaxMessageLenOf::<T>::get() as usize;
|
||||
|
||||
let config = configuration::ActiveConfig::<T>::get();
|
||||
let n_validators = config.max_validators.unwrap_or(500);
|
||||
let validators = generate_validator_pairs::<T>(n_validators);
|
||||
|
||||
let session = SessionIndex::from(0_u32);
|
||||
initializer::Pallet::<T>::test_trigger_on_new_session(
|
||||
false,
|
||||
session,
|
||||
validators.iter().map(|(a, v)| (a, v.clone())),
|
||||
None,
|
||||
);
|
||||
let backing_group_size = config.scheduler_params.max_validators_per_core.unwrap_or(5);
|
||||
let head_data = HeadData(vec![0xFF; 1024]);
|
||||
|
||||
let relay_parent_number = BlockNumberFor::<T>::from(10_u32);
|
||||
let commitments = create_candidate_commitments::<T>(para, head_data, max_len, u, h, c != 0);
|
||||
let backers = bitvec![u8, Lsb0; 1; backing_group_size as usize];
|
||||
let availability_votes = bitvec![u8, Lsb0; 1; n_validators as usize];
|
||||
let core_index = CoreIndex::from(0);
|
||||
let backing_group = GroupIndex::from(0);
|
||||
|
||||
let descriptor = CandidateDescriptor::<T::Hash>::new(
|
||||
para,
|
||||
Default::default(),
|
||||
CoreIndex(0),
|
||||
1,
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
ValidationCode(vec![1, 2, 3]).hash(),
|
||||
);
|
||||
|
||||
let receipt = CommittedCandidateReceipt::<T::Hash> { descriptor, commitments };
|
||||
|
||||
Pallet::<T>::receive_upward_messages(para, &vec![vec![0; max_len]; 1]);
|
||||
|
||||
#[block]
|
||||
{
|
||||
Pallet::<T>::enact_candidate(
|
||||
relay_parent_number,
|
||||
receipt,
|
||||
backers,
|
||||
availability_votes,
|
||||
core_index,
|
||||
backing_group,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl_benchmark_test_suite! {
|
||||
Pallet,
|
||||
crate::mock::new_test_ext(Default::default()),
|
||||
crate::mock::Test
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// 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.
|
||||
|
||||
pub use v1::MigrateToV1;
|
||||
|
||||
pub mod v0 {
|
||||
use crate::inclusion::{Config, Pallet};
|
||||
use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec};
|
||||
use codec::{Decode, Encode};
|
||||
use frame_support::{storage_alias, Twox64Concat};
|
||||
use frame_system::pallet_prelude::BlockNumberFor;
|
||||
use pezkuwi_primitives::{
|
||||
AvailabilityBitfield, CandidateCommitments, CandidateDescriptorV2 as CandidateDescriptor,
|
||||
CandidateHash, CoreIndex, GroupIndex, Id as ParaId, ValidatorIndex,
|
||||
};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
#[derive(Encode, Decode, PartialEq, TypeInfo, Clone, Debug)]
|
||||
pub struct CandidatePendingAvailability<H, N> {
|
||||
pub core: CoreIndex,
|
||||
pub hash: CandidateHash,
|
||||
pub descriptor: CandidateDescriptor<H>,
|
||||
pub availability_votes: BitVec<u8, BitOrderLsb0>,
|
||||
pub backers: BitVec<u8, BitOrderLsb0>,
|
||||
pub relay_parent_number: N,
|
||||
pub backed_in_number: N,
|
||||
pub backing_group: GroupIndex,
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, TypeInfo, Debug, PartialEq)]
|
||||
pub struct AvailabilityBitfieldRecord<N> {
|
||||
pub bitfield: AvailabilityBitfield,
|
||||
pub submitted_at: N,
|
||||
}
|
||||
|
||||
#[storage_alias]
|
||||
pub type PendingAvailability<T: Config> = StorageMap<
|
||||
Pallet<T>,
|
||||
Twox64Concat,
|
||||
ParaId,
|
||||
CandidatePendingAvailability<<T as frame_system::Config>::Hash, BlockNumberFor<T>>,
|
||||
>;
|
||||
|
||||
#[storage_alias]
|
||||
pub type PendingAvailabilityCommitments<T: Config> =
|
||||
StorageMap<Pallet<T>, Twox64Concat, ParaId, CandidateCommitments>;
|
||||
|
||||
#[storage_alias]
|
||||
pub type AvailabilityBitfields<T: Config> = StorageMap<
|
||||
Pallet<T>,
|
||||
Twox64Concat,
|
||||
ValidatorIndex,
|
||||
AvailabilityBitfieldRecord<BlockNumberFor<T>>,
|
||||
>;
|
||||
}
|
||||
|
||||
mod v1 {
|
||||
use super::v0::{
|
||||
AvailabilityBitfields, PendingAvailability as V0PendingAvailability,
|
||||
PendingAvailabilityCommitments as V0PendingAvailabilityCommitments,
|
||||
};
|
||||
use crate::inclusion::{
|
||||
CandidatePendingAvailability as V1CandidatePendingAvailability, Config, Pallet,
|
||||
PendingAvailability as V1PendingAvailability,
|
||||
};
|
||||
use alloc::{collections::vec_deque::VecDeque, vec::Vec};
|
||||
use frame_support::{traits::UncheckedOnRuntimeUpgrade, weights::Weight};
|
||||
use sp_core::Get;
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
use codec::{Decode, Encode};
|
||||
#[cfg(feature = "try-runtime")]
|
||||
use frame_support::{
|
||||
ensure,
|
||||
traits::{GetStorageVersion, StorageVersion},
|
||||
};
|
||||
|
||||
pub struct VersionUncheckedMigrateToV1<T>(core::marker::PhantomData<T>);
|
||||
|
||||
impl<T: Config> UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateToV1<T> {
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::TryRuntimeError> {
|
||||
log::trace!(target: crate::inclusion::LOG_TARGET, "Running pre_upgrade() for inclusion MigrateToV1");
|
||||
let candidates_before_upgrade = V0PendingAvailability::<T>::iter().count();
|
||||
let commitments_before_upgrade = V0PendingAvailabilityCommitments::<T>::iter().count();
|
||||
|
||||
if candidates_before_upgrade != commitments_before_upgrade {
|
||||
log::warn!(
|
||||
target: crate::inclusion::LOG_TARGET,
|
||||
"Number of pending candidates differ from the number of pending commitments. {} vs {}",
|
||||
candidates_before_upgrade,
|
||||
commitments_before_upgrade
|
||||
);
|
||||
}
|
||||
|
||||
Ok((candidates_before_upgrade as u32).encode())
|
||||
}
|
||||
|
||||
fn on_runtime_upgrade() -> Weight {
|
||||
let mut weight: Weight = Weight::zero();
|
||||
|
||||
let v0_candidates: Vec<_> = V0PendingAvailability::<T>::drain().collect();
|
||||
|
||||
for (para_id, candidate) in v0_candidates {
|
||||
let commitments = V0PendingAvailabilityCommitments::<T>::take(para_id);
|
||||
// One write for each removal (one candidate and one commitment).
|
||||
weight = weight.saturating_add(T::DbWeight::get().writes(2));
|
||||
|
||||
if let Some(commitments) = commitments {
|
||||
let mut per_para = VecDeque::new();
|
||||
per_para.push_back(V1CandidatePendingAvailability {
|
||||
core: candidate.core,
|
||||
hash: candidate.hash,
|
||||
descriptor: candidate.descriptor,
|
||||
availability_votes: candidate.availability_votes,
|
||||
backers: candidate.backers,
|
||||
relay_parent_number: candidate.relay_parent_number,
|
||||
backed_in_number: candidate.backed_in_number,
|
||||
backing_group: candidate.backing_group,
|
||||
commitments,
|
||||
});
|
||||
V1PendingAvailability::<T>::insert(para_id, per_para);
|
||||
|
||||
weight = weight.saturating_add(T::DbWeight::get().writes(1));
|
||||
}
|
||||
}
|
||||
|
||||
// should've already been drained by the above for loop, but as a sanity check, in case
|
||||
// there are more commitments than candidates.
|
||||
// V0PendingAvailabilityCommitments should not contain too many keys so removing
|
||||
// everything at once should be safe
|
||||
let res = V0PendingAvailabilityCommitments::<T>::clear(u32::MAX, None);
|
||||
weight = weight.saturating_add(
|
||||
T::DbWeight::get().reads_writes(res.loops as u64, res.backend as u64),
|
||||
);
|
||||
|
||||
// AvailabilityBitfields should not contain too many keys so removing everything at once
|
||||
// should be safe.
|
||||
let res = AvailabilityBitfields::<T>::clear(u32::MAX, None);
|
||||
weight = weight.saturating_add(
|
||||
T::DbWeight::get().reads_writes(res.loops as u64, res.backend as u64),
|
||||
);
|
||||
|
||||
weight
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
fn post_upgrade(state: Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
|
||||
log::trace!(target: crate::inclusion::LOG_TARGET, "Running post_upgrade() for inclusion MigrateToV1");
|
||||
ensure!(
|
||||
Pallet::<T>::on_chain_storage_version() >= StorageVersion::new(1),
|
||||
"Storage version should be >= 1 after the migration"
|
||||
);
|
||||
|
||||
let candidates_before_upgrade =
|
||||
u32::decode(&mut &state[..]).expect("Was properly encoded") as usize;
|
||||
let candidates_after_upgrade = V1PendingAvailability::<T>::iter().fold(
|
||||
0usize,
|
||||
|mut acc, (_paraid, para_candidates)| {
|
||||
acc += para_candidates.len();
|
||||
acc
|
||||
},
|
||||
);
|
||||
|
||||
ensure!(
|
||||
candidates_before_upgrade == candidates_after_upgrade,
|
||||
"Number of pending candidates should be the same as the one before the upgrade."
|
||||
);
|
||||
ensure!(
|
||||
V0PendingAvailability::<T>::iter().next() == None,
|
||||
"Pending availability candidates storage v0 should have been removed"
|
||||
);
|
||||
ensure!(
|
||||
V0PendingAvailabilityCommitments::<T>::iter().next() == None,
|
||||
"Pending availability commitments storage should have been removed"
|
||||
);
|
||||
ensure!(
|
||||
AvailabilityBitfields::<T>::iter().next() == None,
|
||||
"Availability bitfields storage should have been removed"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Migrate to v1 inclusion module storage.
|
||||
/// - merges the `PendingAvailabilityCommitments` into the `CandidatePendingAvailability`
|
||||
/// storage
|
||||
/// - removes the `AvailabilityBitfields` storage, which was never read.
|
||||
pub type MigrateToV1<T> = frame_support::migrations::VersionedMigration<
|
||||
0,
|
||||
1,
|
||||
VersionUncheckedMigrateToV1<T>,
|
||||
Pallet<T>,
|
||||
<T as frame_system::Config>::DbWeight,
|
||||
>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{v1::VersionUncheckedMigrateToV1, *};
|
||||
use crate::{
|
||||
inclusion::{
|
||||
CandidatePendingAvailability as V1CandidatePendingAvailability,
|
||||
PendingAvailability as V1PendingAvailability, *,
|
||||
},
|
||||
mock::{new_test_ext, MockGenesisConfig, Test},
|
||||
};
|
||||
use frame_support::traits::UncheckedOnRuntimeUpgrade;
|
||||
use pezkuwi_primitives::{AvailabilityBitfield, Id as ParaId};
|
||||
use pezkuwi_primitives_test_helpers::{
|
||||
dummy_candidate_commitments, dummy_candidate_descriptor_v2, dummy_hash,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn migrate_to_v1() {
|
||||
new_test_ext(MockGenesisConfig::default()).execute_with(|| {
|
||||
// No data to migrate.
|
||||
assert_eq!(
|
||||
<VersionUncheckedMigrateToV1<Test> as UncheckedOnRuntimeUpgrade>::on_runtime_upgrade(),
|
||||
Weight::zero()
|
||||
);
|
||||
assert!(V1PendingAvailability::<Test>::iter().next().is_none());
|
||||
|
||||
let mut expected = vec![];
|
||||
|
||||
for i in 1..5 {
|
||||
let descriptor = dummy_candidate_descriptor_v2(dummy_hash());
|
||||
v0::PendingAvailability::<Test>::insert(
|
||||
ParaId::from(i),
|
||||
v0::CandidatePendingAvailability {
|
||||
core: CoreIndex(i),
|
||||
descriptor: descriptor.clone(),
|
||||
relay_parent_number: i,
|
||||
hash: CandidateHash(dummy_hash()),
|
||||
availability_votes: Default::default(),
|
||||
backed_in_number: i,
|
||||
backers: Default::default(),
|
||||
backing_group: GroupIndex(i),
|
||||
},
|
||||
);
|
||||
v0::PendingAvailabilityCommitments::<Test>::insert(
|
||||
ParaId::from(i),
|
||||
dummy_candidate_commitments(HeadData(vec![i as _])),
|
||||
);
|
||||
|
||||
v0::AvailabilityBitfields::<Test>::insert(
|
||||
ValidatorIndex(i),
|
||||
v0::AvailabilityBitfieldRecord {
|
||||
bitfield: AvailabilityBitfield(Default::default()),
|
||||
submitted_at: i,
|
||||
},
|
||||
);
|
||||
|
||||
expected.push((
|
||||
ParaId::from(i),
|
||||
[V1CandidatePendingAvailability {
|
||||
core: CoreIndex(i),
|
||||
descriptor,
|
||||
relay_parent_number: i,
|
||||
hash: CandidateHash(dummy_hash()),
|
||||
availability_votes: Default::default(),
|
||||
backed_in_number: i,
|
||||
backers: Default::default(),
|
||||
backing_group: GroupIndex(i),
|
||||
commitments: dummy_candidate_commitments(HeadData(vec![i as _])),
|
||||
}]
|
||||
.into_iter()
|
||||
.collect::<VecDeque<_>>(),
|
||||
));
|
||||
}
|
||||
// add some wrong data also, candidates without commitments or commitments without
|
||||
// candidates.
|
||||
v0::PendingAvailability::<Test>::insert(
|
||||
ParaId::from(6),
|
||||
v0::CandidatePendingAvailability {
|
||||
core: CoreIndex(6),
|
||||
descriptor: dummy_candidate_descriptor_v2(dummy_hash()),
|
||||
relay_parent_number: 6,
|
||||
hash: CandidateHash(dummy_hash()),
|
||||
availability_votes: Default::default(),
|
||||
backed_in_number: 6,
|
||||
backers: Default::default(),
|
||||
backing_group: GroupIndex(6),
|
||||
},
|
||||
);
|
||||
v0::PendingAvailabilityCommitments::<Test>::insert(
|
||||
ParaId::from(7),
|
||||
dummy_candidate_commitments(HeadData(vec![7 as _])),
|
||||
);
|
||||
|
||||
// For tests, db weight is zero.
|
||||
assert_eq!(
|
||||
<VersionUncheckedMigrateToV1<Test> as UncheckedOnRuntimeUpgrade>::on_runtime_upgrade(),
|
||||
Weight::zero()
|
||||
);
|
||||
|
||||
assert_eq!(v0::PendingAvailabilityCommitments::<Test>::iter().next(), None);
|
||||
assert_eq!(v0::PendingAvailability::<Test>::iter().next(), None);
|
||||
assert_eq!(v0::AvailabilityBitfields::<Test>::iter().next(), None);
|
||||
|
||||
let mut actual = V1PendingAvailability::<Test>::iter().collect::<Vec<_>>();
|
||||
actual.sort_by(|(id1, _), (id2, _)| id1.cmp(id2));
|
||||
expected.sort_by(|(id1, _), (id2, _)| id1.cmp(id2));
|
||||
|
||||
assert_eq!(actual, expected);
|
||||
});
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user