diff --git a/Cargo.lock b/Cargo.lock index 5ea406367..f3b8b8b93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7532,6 +7532,19 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8dd856d451cc0da70e2ef2ce95a18e39a93b7558bedf10201ad28503f918568" +[[package]] +name = "manual-randomness-rpc" +version = "0.1.0" +dependencies = [ + "cumulus-primitives-core", + "flume 0.10.14", + "hex-literal 0.3.4", + "jsonrpsee", + "parity-scale-codec", + "sp-core", + "staging-xcm", +] + [[package]] name = "manual-xcm-rpc" version = "0.1.0" @@ -17846,6 +17859,7 @@ dependencies = [ "hex-literal 0.3.4", "jsonrpsee", "log", + "manual-randomness-rpc", "manual-xcm-rpc", "nimbus-consensus", "nimbus-primitives", diff --git a/Cargo.toml b/Cargo.toml index 8624cbd7e..1b58c1bda 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -87,6 +87,7 @@ flashbox-runtime = { path = "runtime/flashbox", default-features = false } dancelight-runtime = { path = "solo-chains/runtime/dancelight", default-features = false } dancelight-runtime-constants = { path = "solo-chains/runtime/dancelight/constants", default-features = false } ethabi = { package = "ethabi-decode", version = "1.0.0", default-features = false } +manual-randomness-rpc = { path = "client/manual-randomness" } manual-xcm-rpc = { path = "client/manual-xcm" } node-common = { path = "client/node-common" } services-payment-rpc = { path = "client/services-payment" } diff --git a/client/manual-randomness/Cargo.toml b/client/manual-randomness/Cargo.toml new file mode 100644 index 000000000..e0651a77f --- /dev/null +++ b/client/manual-randomness/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "manual-randomness-rpc" +authors = { workspace = true } +edition = "2021" +license = "GPL-3.0-only" +repository = { workspace = true } +version = "0.1.0" + +[lints] +workspace = true + +[dependencies] +cumulus-primitives-core = { workspace = true, features = [ "std" ] } +flume = { workspace = true } +hex-literal = { workspace = true } +jsonrpsee = { workspace = true, features = [ "macros", "server" ] } +parity-scale-codec = { workspace = true, features = [ "std" ] } +sp-core = { workspace = true, features = [ "std" ] } +staging-xcm = { workspace = true } diff --git a/client/manual-randomness/src/lib.rs b/client/manual-randomness/src/lib.rs new file mode 100644 index 000000000..b08e4d705 --- /dev/null +++ b/client/manual-randomness/src/lib.rs @@ -0,0 +1,70 @@ +// Copyright (C) Moondance Labs Ltd. +// This file is part of Tanssi. + +// Tanssi 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. + +// Tanssi 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 Tanssi. If not, see . +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; +use sp_core::H256; + +#[rpc(server)] +#[jsonrpsee::core::async_trait] +pub trait ManualRandomnessApi { + /// Inject randomness + #[method(name = "mock_activateRandomness")] + async fn activate_randomness(&self, seed: Option) -> RpcResult<()>; + #[method(name = "mock_deactivateRandomness")] + async fn deactivate_randomness(&self) -> RpcResult<()>; +} + +pub struct ManualRandomness { + pub randomness_message_channel: flume::Sender<(bool, Option<[u8; 32]>)>, +} + +#[jsonrpsee::core::async_trait] +impl ManualRandomnessApiServer for ManualRandomness { + async fn activate_randomness(&self, seed: Option) -> RpcResult<()> { + let randomness_message_channel = self.randomness_message_channel.clone(); + + // Push the message to the shared channel where it will be queued up + // to be injected in to an upcoming block. + randomness_message_channel + .send_async((true, seed.map(|x| x.into()))) + .await + .map_err(|err| internal_err(err.to_string()))?; + + Ok(()) + } + + async fn deactivate_randomness(&self) -> RpcResult<()> { + let randomness_message_channel = self.randomness_message_channel.clone(); + + // Push the message to the shared channel where it will be queued up + // to be injected in to an upcoming block. + randomness_message_channel + .send_async((false, None)) + .await + .map_err(|err| internal_err(err.to_string()))?; + + Ok(()) + } +} + +// This bit cribbed from frontier. +pub fn internal_err>(message: T) -> jsonrpsee::types::ErrorObjectOwned { + jsonrpsee::types::error::ErrorObject::borrowed( + jsonrpsee::types::error::INTERNAL_ERROR_CODE, + message.as_ref(), + None, + ) + .into_owned() +} diff --git a/node/Cargo.toml b/node/Cargo.toml index a083d571f..20e8930a4 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -36,6 +36,7 @@ dancebox-runtime = { workspace = true, features = [ "std" ] } dp-container-chain-genesis-data = { workspace = true, features = [ "json", "std" ] } dp-slot-duration-runtime-api = { workspace = true } flashbox-runtime = { workspace = true, features = [ "std" ] } +manual-randomness-rpc = { workspace = true } manual-xcm-rpc = { workspace = true } node-common = { workspace = true } pallet-author-noting-runtime-api = { workspace = true, features = [ "std" ] } diff --git a/node/src/chain_spec/dancebox.rs b/node/src/chain_spec/dancebox.rs index 709fe17e3..0a38acbc5 100644 --- a/node/src/chain_spec/dancebox.rs +++ b/node/src/chain_spec/dancebox.rs @@ -98,6 +98,7 @@ pub fn development_config( parathreads_per_collator: 1, target_container_chain_fullness: Perbill::from_percent(80), max_parachain_cores_percentage: None, + full_rotation_mode: Default::default(), }, ..Default::default() }, @@ -161,6 +162,7 @@ pub fn local_dancebox_config( parathreads_per_collator: 1, target_container_chain_fullness: Perbill::from_percent(80), max_parachain_cores_percentage: None, + full_rotation_mode: Default::default(), }, ..Default::default() }, diff --git a/node/src/chain_spec/flashbox.rs b/node/src/chain_spec/flashbox.rs index 555cd6ac4..06e3583fe 100644 --- a/node/src/chain_spec/flashbox.rs +++ b/node/src/chain_spec/flashbox.rs @@ -98,6 +98,7 @@ pub fn development_config( parathreads_per_collator: 1, target_container_chain_fullness: Perbill::from_percent(80), max_parachain_cores_percentage: None, + full_rotation_mode: Default::default(), }, ..Default::default() }, @@ -161,6 +162,7 @@ pub fn local_flashbox_config( parathreads_per_collator: 1, target_container_chain_fullness: Perbill::from_percent(80), max_parachain_cores_percentage: None, + full_rotation_mode: Default::default(), }, ..Default::default() }, diff --git a/node/src/rpc.rs b/node/src/rpc.rs index 26317acdd..bf0d75361 100644 --- a/node/src/rpc.rs +++ b/node/src/rpc.rs @@ -24,6 +24,7 @@ use { cumulus_primitives_core::ParaId, dancebox_runtime::{opaque::Block, AccountId, Index as Nonce}, + manual_randomness_rpc::{ManualRandomness, ManualRandomnessApiServer}, manual_xcm_rpc::{ManualXcm, ManualXcmApiServer}, polkadot_primitives::Hash, sc_client_api::{AuxStore, UsageProvider}, @@ -55,6 +56,8 @@ pub struct FullDeps { pub command_sink: Option>>, /// Channels for manual xcm messages (downward, hrmp) pub xcm_senders: Option<(flume::Sender>, flume::Sender<(ParaId, Vec)>)>, + /// Channels for manually activating the randomness + pub randomness_sender: Option)>>, } /// Instantiate all RPC extensions. @@ -84,6 +87,7 @@ where pool, command_sink, xcm_senders, + randomness_sender, } = deps; module.merge(System::new(client.clone(), pool).into_rpc())?; @@ -108,5 +112,14 @@ where )?; } + if let Some(randomness_message_channel) = randomness_sender { + module.merge( + ManualRandomness { + randomness_message_channel, + } + .into_rpc(), + )?; + } + Ok(module) } diff --git a/node/src/service.rs b/node/src/service.rs index 68780f9c8..d0d5e90b6 100644 --- a/node/src/service.rs +++ b/node/src/service.rs @@ -51,7 +51,7 @@ use { pallet_author_noting_runtime_api::AuthorNotingApi, pallet_data_preservers_runtime_api::DataPreserversApi, pallet_registrar_runtime_api::RegistrarApi, - parity_scale_codec::Encode, + parity_scale_codec::{Decode, Encode}, polkadot_cli::ProvideRuntimeApi, polkadot_parachain_primitives::primitives::HeadData, polkadot_service::Handle, @@ -94,6 +94,9 @@ use { mod mocked_relay_keys; +// We use this to detect whether randomness is activated +const RANDOMNESS_ACTIVATED_AUX_KEY: &[u8] = b"__DEV_RANDOMNESS_ACTIVATED"; + type FullBackend = TFullBackend; pub struct NodeConfig; @@ -287,6 +290,7 @@ async fn start_node_impl( pool: transaction_pool.clone(), command_sink: None, xcm_senders: None, + randomness_sender: None, }; crate::rpc::create_full(deps).map_err(Into::into) @@ -893,11 +897,18 @@ pub fn start_dev_node( // production. let mut command_sink = None; let mut xcm_senders = None; + let mut randomness_sender = None; if parachain_config.role.is_authority() { let client = node_builder.client.clone(); let (downward_xcm_sender, downward_xcm_receiver) = flume::bounded::>(100); + let (hrmp_xcm_sender, hrmp_xcm_receiver) = flume::bounded::<(ParaId, Vec)>(100); + // Create channels for mocked parachain candidates. + let (mock_randomness_sender, mock_randomness_receiver) = + flume::bounded::<(bool, Option<[u8; 32]>)>(100); + xcm_senders = Some((downward_xcm_sender, hrmp_xcm_sender)); + randomness_sender = Some(mock_randomness_sender); command_sink = node_builder.install_manual_seal(ManualSealConfiguration { block_import, @@ -958,6 +969,34 @@ pub fn start_dev_node( let downward_xcm_receiver = downward_xcm_receiver.clone(); let hrmp_xcm_receiver = hrmp_xcm_receiver.clone(); + let randomness_enabler_messages: Vec<(bool, Option<[u8; 32]>)> = mock_randomness_receiver.drain().collect(); + + // If there is a value to be updated, we update it + if let Some((enable_randomness, new_seed)) = randomness_enabler_messages.last() { + let value = client + .get_aux(RANDOMNESS_ACTIVATED_AUX_KEY) + .expect("Should be able to query aux storage; qed").unwrap_or((false, Option::<[u8; 32]>::None).encode()); + let (_mock_additional_randomness, mut mock_randomness_seed): (bool, Option<[u8; 32]>) = Decode::decode(&mut value.as_slice()).expect("Boolean non-decodable"); + + if let Some(new_seed) = new_seed { + mock_randomness_seed = Some(*new_seed); + } + + client + .insert_aux( + &[(RANDOMNESS_ACTIVATED_AUX_KEY, (enable_randomness, mock_randomness_seed).encode().as_slice())], + &[], + ) + .expect("Should be able to write to aux storage; qed"); + } + + // We read the value + // If error when reading, we simply put false + let value = client + .get_aux(RANDOMNESS_ACTIVATED_AUX_KEY) + .expect("Should be able to query aux storage; qed").unwrap_or((false, Option::<[u8; 32]>::None).encode()); + let (mock_additional_randomness, mock_randomness_seed): (bool, Option<[u8; 32]>) = Decode::decode(&mut value.as_slice()).expect("Boolean non-decodable"); + let client_for_xcm = client.clone(); async move { let mocked_author_noting = @@ -974,6 +1013,18 @@ pub fn start_dev_node( let (registrar_paras_key_2002, para_info_2002) = mocked_relay_keys::get_mocked_registrar_paras(2002.into()); additional_keys.extend([(para_head_key, para_head_data), (relay_slot_key, Slot::from(relay_slot).encode()), (registrar_paras_key_2002, para_info_2002)]); + if mock_additional_randomness { + let mut mock_randomness: [u8; 32] = [0u8; 32]; + mock_randomness[..4].copy_from_slice(¤t_para_block.to_be_bytes()); + if let Some(seed) = mock_randomness_seed { + for i in 0..32 { + mock_randomness[i] ^= seed[i]; + } + } + additional_keys.extend([(RelayWellKnownKeys::CURRENT_BLOCK_RANDOMNESS.to_vec(), Some(mock_randomness).encode())]); + log::info!("mokcing randomnessss!!! {}", current_para_block); + } + let time = MockTimestampInherentDataProvider; let mocked_parachain = MockValidationDataInherentDataProvider { current_para_block, @@ -1011,6 +1062,7 @@ pub fn start_dev_node( pool: transaction_pool.clone(), command_sink: command_sink.clone(), xcm_senders: xcm_senders.clone(), + randomness_sender: randomness_sender.clone(), }; crate::rpc::create_full(deps).map_err(Into::into) diff --git a/pallets/collator-assignment/src/assignment.rs b/pallets/collator-assignment/src/assignment.rs index d5f52e685..29139318f 100644 --- a/pallets/collator-assignment/src/assignment.rs +++ b/pallets/collator-assignment/src/assignment.rs @@ -24,7 +24,9 @@ use { mem, vec::Vec, }, - tp_traits::{ParaId, RemoveInvulnerables as RemoveInvulnerablesT}, + tp_traits::{ + FullRotationMode, FullRotationModes, ParaId, RemoveInvulnerables as RemoveInvulnerablesT, + }, }; // Separate import of `sp_std::vec!` macro, which cause issues with rustfmt if grouped @@ -38,29 +40,6 @@ impl Assignment where T: crate::Config, { - /// Recompute collator assignment from scratch. If the list of collators and the list of - /// container chains are shuffled, this returns a random assignment. - pub fn assign_collators_rotate_all( - collators: Vec, - orchestrator_chain: ChainNumCollators, - chains: Vec, - shuffle: Option, - ) -> Result, AssignmentError> - where - TShuffle: FnOnce(&mut Vec), - { - // This is just the "always_keep_old" algorithm but with an empty "old" - let old_assigned = Default::default(); - - Self::assign_collators_always_keep_old( - collators, - orchestrator_chain, - chains, - old_assigned, - shuffle, - ) - } - /// Assign new collators to missing container_chains. /// Old collators always have preference to remain on the same chain. /// If there are no missing collators, nothing is changed. @@ -80,10 +59,11 @@ where orchestrator_chain: ChainNumCollators, mut chains: Vec, mut old_assigned: AssignedCollators, - shuffle: Option, + mut shuffle: Option, + full_rotation_mode: FullRotationModes, ) -> Result, AssignmentError> where - TShuffle: FnOnce(&mut Vec), + TShuffle: FnMut(&mut Vec), { if collators.is_empty() && !T::ForceEmptyOrchestrator::get() { return Err(AssignmentError::ZeroCollators); @@ -111,7 +91,24 @@ where &collators_set, ); + // Remove some previously assigned collators to allow new collators to take their place. + // Based on full_rotation_mode. In regular sessions this is FullRotationMode::KeepAll, a no-op. + for chain in chains.iter() { + let mode = if chain.para_id == orchestrator_chain.para_id { + full_rotation_mode.orchestrator.clone() + } else if chain.parathread { + full_rotation_mode.parathread.clone() + } else { + full_rotation_mode.parachain.clone() + }; + + let collators = old_assigned.get_mut(&chain.para_id); + Self::keep_collator_subset(collators, mode, chain.max_collators, shuffle.as_mut()); + } + // Ensure the first `min_orchestrator_collators` of orchestrator chain are invulnerables + // Invulnerables can be unassigned by `keep_collator_subset`, but here we will assign other + // invulnerables again. The downside is that the new invulnerables can be different. Self::prioritize_invulnerables(&collators, orchestrator_chain, &mut old_assigned); let new_assigned_chains = @@ -142,6 +139,48 @@ where Ok(new_assigned) } + /// Keep a subset of collators instead of rotating all of them. + pub fn keep_collator_subset( + collators: Option<&mut Vec>, + full_rotation_mode: FullRotationMode, + max_collators: u32, + shuffle: Option<&mut TShuffle>, + ) where + TShuffle: FnMut(&mut Vec), + { + let collators = match collators { + Some(x) => x, + None => return, + }; + + let num_to_keep = match full_rotation_mode { + FullRotationMode::RotateAll => 0, + FullRotationMode::KeepAll => { + return; + } + FullRotationMode::KeepCollators { keep } => keep, + FullRotationMode::KeepPerbill { percentage: keep } => keep * max_collators, + }; + + if num_to_keep == 0 { + // Remove all + collators.clear(); + return; + } + + // Less than N collators, no need to shuffle + if collators.len() as u32 <= num_to_keep { + return; + } + + // Shuffle and keep first N + if let Some(shuffle) = shuffle { + shuffle(collators); + } + + collators.truncate(num_to_keep as usize); + } + /// Select which container chains will be assigned collators and how many collators, but do not specify which /// collator goes to which chain. /// @@ -488,8 +527,12 @@ pub enum AssignmentError { /// This can be a container chain, a parathread, or the orchestrator chain. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct ChainNumCollators { + /// Para id. pub para_id: ParaId, + /// Min collators. pub min_collators: u32, - // This will only be filled if all the other min have been reached + /// Max collators. This will only be filled if all the other chains have reached min_collators pub max_collators: u32, + /// True if this a parathread. False means parachain or orchestrator. + pub parathread: bool, } diff --git a/pallets/collator-assignment/src/benchmarking.rs b/pallets/collator-assignment/src/benchmarking.rs index 10b67e07e..fa3c54177 100644 --- a/pallets/collator-assignment/src/benchmarking.rs +++ b/pallets/collator-assignment/src/benchmarking.rs @@ -110,6 +110,7 @@ mod benchmarks { random_seed, full_rotation: false, target_session: T::SessionIndex::from(1u32), + full_rotation_mode: FullRotationModes::keep_all(), } .into(), ); diff --git a/pallets/collator-assignment/src/lib.rs b/pallets/collator-assignment/src/lib.rs index 227b5e7b3..c8360cc43 100644 --- a/pallets/collator-assignment/src/lib.rs +++ b/pallets/collator-assignment/src/lib.rs @@ -54,7 +54,7 @@ use { }, sp_std::{collections::btree_set::BTreeSet, fmt::Debug, prelude::*, vec}, tp_traits::{ - CollatorAssignmentTip, GetContainerChainAuthor, GetHostConfiguration, + CollatorAssignmentTip, FullRotationModes, GetContainerChainAuthor, GetHostConfiguration, GetSessionContainerChains, ParaId, ParaIdAssignmentHooks, RemoveInvulnerables, ShouldRotateAllCollators, Slot, }, @@ -121,6 +121,7 @@ pub mod pallet { random_seed: [u8; 32], full_rotation: bool, target_session: T::SessionIndex, + full_rotation_mode: FullRotationModes, }, } @@ -334,6 +335,7 @@ pub mod pallet { para_id: T::SelfParaId::get(), min_collators: 0u32, max_collators: 0u32, + parathread: false, } } else { ChainNumCollators { @@ -344,6 +346,7 @@ pub mod pallet { max_collators: T::HostConfiguration::max_collators_for_orchestrator( target_session_index, ), + parathread: false, } }; @@ -360,6 +363,7 @@ pub mod pallet { para_id: *para_id, min_collators: collators_per_container, max_collators: collators_per_container, + parathread: false, }); } for para_id in ¶threads { @@ -367,6 +371,7 @@ pub mod pallet { para_id: *para_id, min_collators: collators_per_parathread, max_collators: collators_per_parathread, + parathread: true, }); } @@ -394,47 +399,44 @@ pub mod pallet { // We assign new collators // we use the config scheduled at the target_session_index - let new_assigned = - if T::ShouldRotateAllCollators::should_rotate_all_collators(target_session_index) { - log::debug!( - "Collator assignment: rotating collators. Session {:?}, Seed: {:?}", - current_session_index.encode(), - random_seed - ); + let full_rotation = + T::ShouldRotateAllCollators::should_rotate_all_collators(target_session_index); + if full_rotation { + log::info!( + "Collator assignment: rotating collators. Session {:?}, Seed: {:?}", + current_session_index.encode(), + random_seed + ); + } else { + log::info!( + "Collator assignment: keep old assigned. Session {:?}, Seed: {:?}", + current_session_index.encode(), + random_seed + ); + } - Self::deposit_event(Event::NewPendingAssignment { - random_seed, - full_rotation: true, - target_session: target_session_index, - }); - - Assignment::::assign_collators_rotate_all( - collators, - orchestrator_chain, - chains, - shuffle_collators, - ) - } else { - log::debug!( - "Collator assignment: keep old assigned. Session {:?}, Seed: {:?}", - current_session_index.encode(), - random_seed - ); + let full_rotation_mode = if full_rotation { + T::HostConfiguration::full_rotation_mode(target_session_index) + } else { + // On sessions where there is no rotation, we try to keep all collators assigned to the same chains + FullRotationModes::keep_all() + }; - Self::deposit_event(Event::NewPendingAssignment { - random_seed, - full_rotation: false, - target_session: target_session_index, - }); - - Assignment::::assign_collators_always_keep_old( - collators, - orchestrator_chain, - chains, - old_assigned.clone(), - shuffle_collators, - ) - }; + Self::deposit_event(Event::NewPendingAssignment { + random_seed, + full_rotation, + target_session: target_session_index, + full_rotation_mode: full_rotation_mode.clone(), + }); + + let new_assigned = Assignment::::assign_collators_always_keep_old( + collators, + orchestrator_chain, + chains, + old_assigned.clone(), + shuffle_collators, + full_rotation_mode, + ); let mut new_assigned = match new_assigned { Ok(x) => x, diff --git a/pallets/collator-assignment/src/mock.rs b/pallets/collator-assignment/src/mock.rs index f59e3ae4c..04136d76e 100644 --- a/pallets/collator-assignment/src/mock.rs +++ b/pallets/collator-assignment/src/mock.rs @@ -19,6 +19,7 @@ use { self as pallet_collator_assignment, pallet::CollatorContainerChain, CoreAllocationConfiguration, GetRandomnessForNextBlock, RotateCollatorsEveryNSessions, }, + dp_collator_assignment::AssignedCollators, frame_support::{ parameter_types, traits::{ConstBool, ConstU16, ConstU64, Hooks}, @@ -31,9 +32,12 @@ use { traits::{BlakeTwo256, IdentityLookup}, BuildStorage, Perbill, }, - sp_std::collections::{btree_map::BTreeMap, btree_set::BTreeSet}, + sp_std::{ + collections::{btree_map::BTreeMap, btree_set::BTreeSet}, + ops::Range, + }, tp_traits::{ - CollatorAssignmentTip, ParaId, ParaIdAssignmentHooks, ParathreadParams, + CollatorAssignmentTip, FullRotationModes, ParaId, ParaIdAssignmentHooks, ParathreadParams, RemoveInvulnerables, SessionContainerChains, }, tracing_subscriber::{layer::SubscriberExt, FmtSubscriber}, @@ -150,6 +154,7 @@ pub struct Mocks { pub chains_that_are_tipping: Vec, // None means 5 pub full_rotation_period: Option, + pub full_rotation_mode: FullRotationModes, pub apply_tip: bool, pub assignment_hook_errors: bool, } @@ -170,6 +175,7 @@ impl Default for Mocks { random_seed: Default::default(), chains_that_are_tipping: vec![1003.into(), 1004.into()], full_rotation_period: Default::default(), + full_rotation_mode: Default::default(), apply_tip: Default::default(), assignment_hook_errors: Default::default(), } @@ -215,6 +221,10 @@ impl pallet_collator_assignment::GetHostConfiguration for HostConfiguration None } + fn full_rotation_mode(_session_index: u32) -> FullRotationModes { + MockData::mock().full_rotation_mode + } + #[cfg(feature = "runtime-benchmarks")] fn set_host_configuration(_session_index: u32) { MockData::mutate(|mocks| { @@ -449,3 +459,88 @@ pub fn silence_logs R, R>(f: F) -> R { tracing::subscriber::with_default(no_logging_subscriber, f) } + +pub fn collect_assignment_history( + end_block: u64, + mut update_fn: F, +) -> BTreeMap> +where + F: FnMut(u64), +{ + let mut assignment_history = BTreeMap::new(); + + let start_block = System::block_number(); + + for n in start_block..end_block { + let block_number = System::block_number(); + + update_fn(block_number); + + let session_len = 5; + let session_index = (block_number / session_len) as u32; + assignment_history.insert(session_index, CollatorContainerChain::::get()); + + run_to_block(n); + } + + assignment_history +} + +/// Given an assignment history (map of session => AssignedCollators), computes the maximum number +/// of collators that rotate from one session to the next one. +/// +/// Examples: +/// * If collators never rotate, this will return 0 +/// * If all collators always rotate, this will return the number of collators +/// +/// Because of randomness, if is possible that the returned value if lower than expected, e.g. we +/// expect all collators to rotate but not all of them do. +pub fn compute_max_rotation( + assignment_history: &BTreeMap>, + extract_collators_fn: F, +) -> usize +where + F: Fn(&AssignedCollators) -> BTreeMap>, +{ + let mut max_rotation = 0; + let mut prev_assignments: BTreeMap> = BTreeMap::new(); + + if let Some(first_assignment) = assignment_history.values().next() { + prev_assignments = extract_collators_fn(first_assignment); + } + + for assignment in assignment_history.values().skip(1) { + let current_assignments = extract_collators_fn(assignment); + + for (chain_id, current_collators) in ¤t_assignments { + let empty_btreeset = BTreeSet::new(); + let prev_collators = prev_assignments.get(chain_id).unwrap_or(&empty_btreeset); + let new_collators = current_collators.difference(prev_collators).count(); + max_rotation = max_rotation.max(new_collators); + } + + prev_assignments = current_assignments; + } + + max_rotation +} + +/// Get the collator assignment for all parachains or all parathreads. +/// Use range 2000..3000 for parachains and 3000..4000 for parathreads. +pub fn extract_assignments_in_range( + assignment: &AssignedCollators, + range: Range, +) -> BTreeMap> { + assignment + .container_chains + .iter() + .filter_map(|(chain_id, collators)| { + let id = u32::from(*chain_id); + if range.contains(&id) { + Some((id, collators.iter().cloned().collect())) + } else { + None + } + }) + .collect() +} diff --git a/pallets/collator-assignment/src/tests.rs b/pallets/collator-assignment/src/tests.rs index e7dd4aa2f..7711c2750 100644 --- a/pallets/collator-assignment/src/tests.rs +++ b/pallets/collator-assignment/src/tests.rs @@ -17,10 +17,13 @@ use { crate::{mock::*, CollatorContainerChain, Event, PendingCollatorContainerChain}, dp_collator_assignment::AssignedCollators, + sp_runtime::Perbill, std::collections::BTreeMap, + tp_traits::{FullRotationMode, FullRotationModes}, }; mod assign_full; +mod keep_collator_subset; mod prioritize_invulnerables; mod select_chains; mod with_core_config; @@ -1078,6 +1081,7 @@ fn rotation_events() { random_seed: [0; 32], full_rotation: false, target_session: 1, + full_rotation_mode: FullRotationModes::keep_all(), } .into(), ); @@ -1091,6 +1095,7 @@ fn rotation_events() { random_seed: [0; 32], full_rotation: false, target_session: (i / 5) as u32 + 1, + full_rotation_mode: FullRotationModes::keep_all(), } .into(), ); @@ -1122,6 +1127,7 @@ fn rotation_events() { random_seed: [1; 32], full_rotation: false, target_session: (i / 5) as u32 + 1, + full_rotation_mode: FullRotationModes::keep_all(), } .into(), ); @@ -1132,6 +1138,7 @@ fn rotation_events() { random_seed: [1; 32], full_rotation: true, target_session: (i / 5) as u32 + 1, + full_rotation_mode: FullRotationModes::default(), } .into(), ); @@ -1370,3 +1377,63 @@ fn assign_collators_truncates_before_shuffling() { ); }); } + +#[test] +fn keep_subset_uses_correct_config() { + new_test_ext().execute_with(|| { + run_to_block(1); + + MockData::mutate(|m| { + m.collators_per_container = 2; + m.collators_per_parathread = 2; + m.min_orchestrator_chain_collators = 2; + m.max_orchestrator_chain_collators = 5; + // Add randomness to test shuffle + m.random_seed = [1; 32]; + // Rotate every session + m.full_rotation_period = Some(1); + m.full_rotation_mode = FullRotationModes { + orchestrator: FullRotationMode::RotateAll, + parachain: FullRotationMode::KeepCollators { keep: 2 }, + parathread: FullRotationMode::KeepPerbill { + percentage: Perbill::from_percent(50), + }, + }; + + m.collators = (1..50).collect(); + m.container_chains = (2001..2010).collect(); + m.parathreads = (3001..3010).collect(); + }); + assert_eq!(assigned_collators(), initial_collators(),); + run_to_block(11); + + // Collect assignment history + let assignment_history = collect_assignment_history(50, |n| { + // Update randomness for each block + MockData::mutate(|m| { + m.random_seed = [n as u8; 32]; + }); + }); + + // Check: there is at least one session in which all orchestrator collators rotate + let max_orchestrator_rotate = compute_max_rotation(&assignment_history, |assignment| { + let collators = assignment.orchestrator_chain.clone(); + let mut map = BTreeMap::new(); + map.insert(1000, collators.into_iter().collect()); + map + }); + assert_eq!(max_orchestrator_rotate, 5); + + // Check: parachain collators never rotate + let max_parachain_rotate = compute_max_rotation(&assignment_history, |assignment| { + extract_assignments_in_range(assignment, 2000..3000) + }); + assert_eq!(max_parachain_rotate, 0); + + // Check: at most one collator will rotate out of each parathread, never all 2 + let max_parathread_rotate = compute_max_rotation(&assignment_history, |assignment| { + extract_assignments_in_range(assignment, 3000..4000) + }); + assert_eq!(max_parathread_rotate, 1); + }); +} diff --git a/pallets/collator-assignment/src/tests/keep_collator_subset.rs b/pallets/collator-assignment/src/tests/keep_collator_subset.rs new file mode 100644 index 000000000..9f7fd4a29 --- /dev/null +++ b/pallets/collator-assignment/src/tests/keep_collator_subset.rs @@ -0,0 +1,163 @@ +// Copyright (C) Moondance Labs Ltd. +// This file is part of Tanssi. + +// Tanssi 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. + +// Tanssi 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 Tanssi. If not, see + +use { + crate::{assignment::Assignment, tests::Test}, + sp_runtime::Perbill, + tp_traits::FullRotationMode, +}; + +#[test] +fn keep_subset_keep_50_percent() { + let mut collators = vec![1, 2, 3, 4, 5]; + let mut shuffle_count = 0; + + let mut shuffle = |_collators: &mut Vec| { + shuffle_count += 1; + }; + + let full_rotation_mode = FullRotationMode::KeepPerbill { + percentage: Perbill::from_percent(50), + }; + let max_collators = 5; + Assignment::::keep_collator_subset( + Some(&mut collators), + full_rotation_mode, + max_collators, + Some(&mut shuffle), + ); + + // 50% of 5 is 2 + assert_eq!(collators.len(), 2); + assert_eq!(shuffle_count, 1); +} + +#[test] +fn keep_subset_keep_2_collators() { + let mut collators = vec![1, 2, 3, 4, 5]; + let mut shuffle_count = 0; + + let mut shuffle = |_collators: &mut Vec| { + shuffle_count += 1; + }; + + let full_rotation_mode = FullRotationMode::KeepCollators { keep: 2 }; + let max_collators = 5; + Assignment::::keep_collator_subset( + Some(&mut collators), + full_rotation_mode, + max_collators, + Some(&mut shuffle), + ); + + assert_eq!(collators.len(), 2); + assert_eq!(shuffle_count, 1); +} + +#[test] +fn keep_subset_rotate_all() { + let mut collators = vec![1, 2, 3, 4, 5]; + let mut shuffle_count = 0; + + let mut shuffle = |_collators: &mut Vec| { + shuffle_count += 1; + }; + + let full_rotation_mode = FullRotationMode::RotateAll; + let max_collators = 5; + Assignment::::keep_collator_subset( + Some(&mut collators), + full_rotation_mode, + max_collators, + Some(&mut shuffle), + ); + + assert_eq!(collators.len(), 0); + assert_eq!(shuffle_count, 0); +} + +#[test] +fn keep_subset_keep_all() { + let mut collators = vec![1, 2, 3, 4, 5]; + let mut shuffle_count = 0; + + let mut shuffle = |_collators: &mut Vec| { + shuffle_count += 1; + }; + + let full_rotation_mode = FullRotationMode::KeepAll; + let max_collators = 5; + Assignment::::keep_collator_subset( + Some(&mut collators), + full_rotation_mode, + max_collators, + Some(&mut shuffle), + ); + + assert_eq!(collators.len(), 5); + assert_eq!(shuffle_count, 0); +} + +#[test] +fn keep_subset_empty_collators() { + let mut collators = vec![]; + let mut shuffle_count = 0; + + let mut shuffle = |_collators: &mut Vec| { + shuffle_count += 1; + }; + + let full_rotation_mode = FullRotationMode::KeepCollators { keep: 2 }; + let max_collators = 5; + Assignment::::keep_collator_subset( + Some(&mut collators), + full_rotation_mode.clone(), + max_collators, + Some(&mut shuffle), + ); + assert_eq!(collators.len(), 0); + + // Calling this with None does not panic + Assignment::::keep_collator_subset( + None, + full_rotation_mode, + max_collators, + Some(&mut shuffle), + ); + assert_eq!(shuffle_count, 0); +} + +#[test] +fn keep_subset_keep_more_than_max() { + // Trying to keep more collators than the max keeps all of them and does not panic + let mut collators = vec![1, 2, 3, 4, 5]; + let mut shuffle_count = 0; + + let mut shuffle = |_collators: &mut Vec| { + shuffle_count += 1; + }; + + let full_rotation_mode = FullRotationMode::KeepCollators { keep: 200 }; + let max_collators = 5; + Assignment::::keep_collator_subset( + Some(&mut collators), + full_rotation_mode.clone(), + max_collators, + Some(&mut shuffle), + ); + assert_eq!(collators.len(), 5); + assert_eq!(shuffle_count, 0); +} diff --git a/pallets/collator-assignment/src/tests/prioritize_invulnerables.rs b/pallets/collator-assignment/src/tests/prioritize_invulnerables.rs index 4e13c69d4..ad009b440 100644 --- a/pallets/collator-assignment/src/tests/prioritize_invulnerables.rs +++ b/pallets/collator-assignment/src/tests/prioritize_invulnerables.rs @@ -29,6 +29,7 @@ fn invulnerable_priority_0_collators() { para_id: 1000.into(), min_collators: 2, max_collators: 5, + parathread: false, }; let mut old_assigned = BTreeMap::new(); @@ -48,6 +49,7 @@ fn invulnerable_priority_0_invulnerables() { para_id: 1000.into(), min_collators: 2, max_collators: 5, + parathread: false, }; let mut old_assigned = BTreeMap::from_iter(vec![(1000.into(), vec![1, 2])]); @@ -67,6 +69,7 @@ fn invulnerable_priority_1_invulnerable_orchestrator() { para_id: 1000.into(), min_collators: 2, max_collators: 5, + parathread: false, }; let mut old_assigned = BTreeMap::from_iter(vec![(1000.into(), vec![101])]); @@ -86,6 +89,7 @@ fn invulnerable_priority_1_invulnerable_not_assigned() { para_id: 1000.into(), min_collators: 2, max_collators: 5, + parathread: false, }; let mut old_assigned = BTreeMap::new(); @@ -105,6 +109,7 @@ fn invulnerable_priority_1_invulnerable_assigned_to_another_chain() { para_id: 1000.into(), min_collators: 2, max_collators: 5, + parathread: false, }; let mut old_assigned = BTreeMap::from_iter(vec![(1000.into(), vec![]), (2000.into(), vec![101])]); @@ -125,6 +130,7 @@ fn bug_same_invulnerable_selected_twice() { para_id: 1000.into(), min_collators: 2, max_collators: 5, + parathread: false, }; let mut old_assigned = BTreeMap::from_iter(vec![(1000.into(), vec![100])]); @@ -148,16 +154,19 @@ fn bug_not_using_assigned_invulnerables() { para_id: 1000.into(), min_collators: 2, max_collators: 5, + parathread: false, }, ChainNumCollators { para_id: 2000.into(), min_collators: 2, max_collators: 2, + parathread: false, }, ChainNumCollators { para_id: 2001.into(), min_collators: 2, max_collators: 2, + parathread: false, }, ]; let orchestrator_chain = container_chains[0]; diff --git a/pallets/collator-assignment/src/tests/select_chains.rs b/pallets/collator-assignment/src/tests/select_chains.rs index 24487dbc5..e2212fd39 100644 --- a/pallets/collator-assignment/src/tests/select_chains.rs +++ b/pallets/collator-assignment/src/tests/select_chains.rs @@ -27,16 +27,19 @@ fn select_chains_not_enough_to_reach_min_container() { para_id: 1000.into(), min_collators: 2, max_collators: 5, + parathread: false, }, ChainNumCollators { para_id: 2000.into(), min_collators: 10, max_collators: 10, + parathread: false, }, ChainNumCollators { para_id: 2001.into(), min_collators: 10, max_collators: 10, + parathread: false, }, ]; let new_assigned = Assignment::::select_chains_with_collators(10, &container_chains); @@ -50,6 +53,7 @@ fn select_chains_not_enough_to_reach_min_orchestrator() { para_id: 1000.into(), min_collators: 2, max_collators: 5, + parathread: false, }]; let new_assigned = Assignment::::select_chains_with_collators(1, &container_chains); assert_eq!(new_assigned, vec![(1000.into(), 1),]); @@ -64,16 +68,19 @@ fn select_chains_not_enough_for_all_min() { para_id: 1000.into(), min_collators: 2, max_collators: 5, + parathread: false, }, ChainNumCollators { para_id: 2000.into(), min_collators: 2, max_collators: 2, + parathread: false, }, ChainNumCollators { para_id: 2001.into(), min_collators: 2, max_collators: 2, + parathread: false, }, ]; let new_assigned = Assignment::::select_chains_with_collators(5, &container_chains); @@ -89,16 +96,19 @@ fn select_chains_not_enough_for_all_max() { para_id: 1000.into(), min_collators: 2, max_collators: 5, + parathread: false, }, ChainNumCollators { para_id: 2000.into(), min_collators: 2, max_collators: 5, + parathread: false, }, ChainNumCollators { para_id: 2001.into(), min_collators: 2, max_collators: 5, + parathread: false, }, ]; let new_assigned = Assignment::::select_chains_with_collators(7, &container_chains); @@ -131,16 +141,19 @@ fn select_chains_more_than_max() { para_id: 1000.into(), min_collators: 2, max_collators: 5, + parathread: false, }, ChainNumCollators { para_id: 2000.into(), min_collators: 2, max_collators: 5, + parathread: false, }, ChainNumCollators { para_id: 2001.into(), min_collators: 2, max_collators: 5, + parathread: false, }, ]; let new_assigned = Assignment::::select_chains_with_collators(20, &container_chains); @@ -159,16 +172,19 @@ fn select_chains_not_enough_to_reach_min_container_but_enough_for_parathread() { para_id: 1000.into(), min_collators: 2, max_collators: 5, + parathread: false, }, ChainNumCollators { para_id: 2000.into(), min_collators: 2, max_collators: 2, + parathread: false, }, ChainNumCollators { para_id: 3000.into(), min_collators: 1, max_collators: 1, + parathread: true, }, ]; let new_assigned = Assignment::::select_chains_with_collators(3, &container_chains); @@ -183,16 +199,19 @@ fn select_chains_solochain() { para_id: 1000.into(), min_collators: 0, max_collators: 0, + parathread: false, }, ChainNumCollators { para_id: 2000.into(), min_collators: 2, max_collators: 5, + parathread: false, }, ChainNumCollators { para_id: 2001.into(), min_collators: 2, max_collators: 5, + parathread: false, }, ]; let new_assigned = Assignment::::select_chains_with_collators(5, &container_chains); @@ -209,6 +228,7 @@ fn select_chains_solochain_zero_collators() { para_id: 1000.into(), min_collators: 0, max_collators: 0, + parathread: false, }]; let new_assigned = Assignment::::select_chains_with_collators(0, &container_chains); assert_eq!(new_assigned, vec![(1000.into(), 0)]); diff --git a/pallets/collator-assignment/src/tests/with_core_config.rs b/pallets/collator-assignment/src/tests/with_core_config.rs index 59f73afb2..6b07bfb19 100644 --- a/pallets/collator-assignment/src/tests/with_core_config.rs +++ b/pallets/collator-assignment/src/tests/with_core_config.rs @@ -25,6 +25,7 @@ fn create_blank_chain_num_collator(id: u32) -> ChainNumCollators { para_id: ParaId::new(id), min_collators: 0, max_collators: 0, + parathread: false, } } diff --git a/pallets/configuration/src/lib.rs b/pallets/configuration/src/lib.rs index 6e79da558..8b25a4ff8 100644 --- a/pallets/configuration/src/lib.rs +++ b/pallets/configuration/src/lib.rs @@ -42,6 +42,7 @@ pub use weights::WeightInfo; mod benchmarks; pub use pallet::*; +use tp_traits::FullRotationModes; use { frame_support::pallet_prelude::*, frame_system::pallet_prelude::*, @@ -88,6 +89,8 @@ pub struct HostConfiguration { pub target_container_chain_fullness: Perbill, /// Maximum number of cores that can be allocated to parachains (only applicable for solo chain) pub max_parachain_cores_percentage: Option, + /// Full rotation mode + pub full_rotation_mode: FullRotationModes, } impl Default for HostConfiguration { @@ -102,6 +105,7 @@ impl Default for HostConfiguration { parathreads_per_collator: 1, target_container_chain_fullness: Perbill::from_percent(80), max_parachain_cores_percentage: None, + full_rotation_mode: Default::default(), } } } @@ -161,7 +165,7 @@ impl HostConfiguration { #[frame_support::pallet] pub mod pallet { - use tp_traits::GetHostConfiguration; + use tp_traits::{FullRotationMode, GetHostConfiguration}; use super::*; @@ -195,7 +199,7 @@ pub mod pallet { /// The active configuration for the current session. #[pallet::storage] - pub(crate) type ActiveConfig = StorageValue<_, HostConfiguration, ValueQuery>; + pub type ActiveConfig = StorageValue<_, HostConfiguration, ValueQuery>; /// Pending configuration changes. /// @@ -209,7 +213,7 @@ pub mod pallet { // since it can have at most 2 items anyway. But the upstream pallet doesn't do that so low // priority. #[pallet::unbounded] - pub(crate) type PendingConfigs = + pub type PendingConfigs = StorageValue<_, Vec<(T::SessionIndex, HostConfiguration)>, ValueQuery>; /// If this is set, then the configuration setters will bypass the consistency checks. This @@ -356,6 +360,31 @@ pub mod pallet { }) } + #[pallet::call_index(9)] + #[pallet::weight(( + T::WeightInfo::set_config_with_u32(), + DispatchClass::Operational, + ))] + pub fn set_full_rotation_mode( + origin: OriginFor, + orchestrator: Option, + parachain: Option, + parathread: Option, + ) -> DispatchResult { + ensure_root(origin)?; + Self::schedule_config_update(|config| { + if let Some(orchestrator) = orchestrator { + config.full_rotation_mode.orchestrator = orchestrator; + } + if let Some(parachain) = parachain { + config.full_rotation_mode.parachain = parachain; + } + if let Some(parathread) = parathread { + config.full_rotation_mode.parathread = parathread; + } + }) + } + /// Setting this to true will disable consistency checks for the configuration setters. /// Use with caution. #[pallet::call_index(44)] @@ -599,5 +628,9 @@ pub mod pallet { fn max_parachain_cores_percentage(session_index: T::SessionIndex) -> Option { Self::config_at_session(session_index).max_parachain_cores_percentage } + + fn full_rotation_mode(session_index: T::SessionIndex) -> FullRotationModes { + Self::config_at_session(session_index).full_rotation_mode + } } } diff --git a/primitives/traits/src/lib.rs b/primitives/traits/src/lib.rs index 3be563c6d..d0c8315dd 100644 --- a/primitives/traits/src/lib.rs +++ b/primitives/traits/src/lib.rs @@ -239,6 +239,7 @@ pub trait GetHostConfiguration { fn collators_per_parathread(session_index: SessionIndex) -> u32; fn target_container_chain_fullness(session_index: SessionIndex) -> Perbill; fn max_parachain_cores_percentage(session_index: SessionIndex) -> Option; + fn full_rotation_mode(session_index: SessionIndex) -> FullRotationModes; #[cfg(feature = "runtime-benchmarks")] fn set_host_configuration(_session_index: SessionIndex) {} } @@ -515,3 +516,63 @@ impl OnEraEnd for Tuple { for_tuples!( #( Tuple::on_era_end(era_index); )* ); } } + +/// Strategy to use when rotating collators. Default: rotate all of them. Allows to rotate only a random subset. +#[derive( + Clone, + Debug, + Default, + Encode, + Decode, + scale_info::TypeInfo, + PartialEq, + Eq, + Serialize, + Deserialize, + MaxEncodedLen, +)] +pub enum FullRotationMode { + #[default] + RotateAll, + KeepAll, + /// Keep this many collators + KeepCollators { + keep: u32, + }, + /// Keep a ratio of collators wrt to max collators. + /// If max collators changes, the number of collators kept also changes. + KeepPerbill { + percentage: Perbill, + }, +} + +/// Allow to set a different [FullRotationMode] for each kind of chain. Default: rotate all. +#[derive( + Clone, + Debug, + Default, + Encode, + Decode, + scale_info::TypeInfo, + PartialEq, + Eq, + Serialize, + Deserialize, + MaxEncodedLen, +)] +pub struct FullRotationModes { + pub orchestrator: FullRotationMode, + pub parachain: FullRotationMode, + pub parathread: FullRotationMode, +} + +impl FullRotationModes { + /// Keep all collators assigned to their current chain if possible. This is equivalent to disabling rotation. + pub fn keep_all() -> Self { + Self { + orchestrator: FullRotationMode::KeepAll, + parachain: FullRotationMode::KeepAll, + parathread: FullRotationMode::KeepAll, + } + } +} diff --git a/runtime/common/src/migrations.rs b/runtime/common/src/migrations.rs index 1eb5138b1..940be3532 100644 --- a/runtime/common/src/migrations.rs +++ b/runtime/common/src/migrations.rs @@ -34,13 +34,10 @@ //! This module acts as a registry where each migration is defined. Each migration should implement //! the "Migration" trait declared in the pallet-migrations crate. -#[cfg(feature = "try-runtime")] -use frame_support::ensure; -use frame_support::migration::move_pallet; use { cumulus_primitives_core::ParaId, frame_support::{ - migration::{clear_storage_prefix, storage_key_iter}, + migration::{clear_storage_prefix, move_pallet, storage_key_iter}, pallet_prelude::GetStorageVersion, traits::{ fungible::MutateHold, OnRuntimeUpgrade, PalletInfoAccess, ReservableCurrency, @@ -57,6 +54,8 @@ use { sp_runtime::Perbill, sp_std::{collections::btree_set::BTreeSet, marker::PhantomData, prelude::*}, }; +#[cfg(feature = "try-runtime")] +use {frame_support::ensure, parity_scale_codec::DecodeAll}; #[derive( Default, @@ -67,7 +66,7 @@ use { sp_core::RuntimeDebug, scale_info::TypeInfo, )] -pub struct HostConfigurationV2 { +pub struct HostConfigurationV3 { pub max_collators: u32, pub min_orchestrator_collators: u32, pub max_orchestrator_collators: u32, @@ -76,28 +75,26 @@ pub struct HostConfigurationV2 { pub collators_per_parathread: u32, pub parathreads_per_collator: u32, pub target_container_chain_fullness: Perbill, + pub max_parachain_cores_percentage: Option, } -pub struct MigrateConfigurationAddParachainPercentage(pub PhantomData); -impl Migration for MigrateConfigurationAddParachainPercentage +pub struct MigrateConfigurationAddFullRotationMode(pub PhantomData); +impl Migration for MigrateConfigurationAddFullRotationMode where T: pallet_configuration::Config, { fn friendly_name(&self) -> &str { - "TM_MigrateConfigurationAddParachainPercentage" + "TM_MigrateConfigurationAddFullRotationMode" } fn migrate(&self, _available_weight: Weight) -> Weight { - const CONFIGURATION_ACTIVE_CONFIG_KEY: &[u8] = - &hex_literal::hex!("06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385"); - const CONFIGURATION_PENDING_CONFIGS_KEY: &[u8] = - &hex_literal::hex!("06de3d8a54d27e44a9d5ce189618f22d53b4123b2e186e07fb7bad5dda5f55c0"); let default_config = HostConfiguration::default(); // Modify active config - let old_config: HostConfigurationV2 = - frame_support::storage::unhashed::get(CONFIGURATION_ACTIVE_CONFIG_KEY) - .expect("configuration.activeConfig should have value"); + let old_config: HostConfigurationV3 = frame_support::storage::unhashed::get( + &pallet_configuration::ActiveConfig::::hashed_key(), + ) + .expect("configuration.activeConfig should have value"); let new_config = HostConfiguration { max_collators: old_config.max_collators, min_orchestrator_collators: old_config.min_orchestrator_collators, @@ -107,14 +104,20 @@ where collators_per_parathread: old_config.collators_per_parathread, parathreads_per_collator: old_config.parathreads_per_collator, target_container_chain_fullness: old_config.target_container_chain_fullness, - max_parachain_cores_percentage: default_config.max_parachain_cores_percentage, + max_parachain_cores_percentage: old_config.max_parachain_cores_percentage, + full_rotation_mode: default_config.full_rotation_mode.clone(), }; - frame_support::storage::unhashed::put(CONFIGURATION_ACTIVE_CONFIG_KEY, &new_config); + frame_support::storage::unhashed::put( + &pallet_configuration::ActiveConfig::::hashed_key(), + &new_config, + ); // Modify pending configs, if any - let old_pending_configs: Vec<(u32, HostConfigurationV2)> = - frame_support::storage::unhashed::get(CONFIGURATION_PENDING_CONFIGS_KEY) - .unwrap_or_default(); + let old_pending_configs: Vec<(u32, HostConfigurationV3)> = + frame_support::storage::unhashed::get( + &pallet_configuration::PendingConfigs::::hashed_key(), + ) + .unwrap_or_default(); let mut new_pending_configs: Vec<(u32, HostConfiguration)> = vec![]; for (session_index, old_config) in old_pending_configs { @@ -127,14 +130,15 @@ where collators_per_parathread: old_config.collators_per_parathread, parathreads_per_collator: old_config.parathreads_per_collator, target_container_chain_fullness: old_config.target_container_chain_fullness, - max_parachain_cores_percentage: default_config.max_parachain_cores_percentage, + max_parachain_cores_percentage: old_config.max_parachain_cores_percentage, + full_rotation_mode: default_config.full_rotation_mode.clone(), }; new_pending_configs.push((session_index, new_config)); } if !new_pending_configs.is_empty() { frame_support::storage::unhashed::put( - CONFIGURATION_PENDING_CONFIGS_KEY, + &pallet_configuration::PendingConfigs::::hashed_key(), &new_pending_configs, ); } @@ -145,20 +149,19 @@ where /// Run a standard pre-runtime test. This works the same way as in a normal runtime upgrade. #[cfg(feature = "try-runtime")] fn pre_upgrade(&self) -> Result, sp_runtime::DispatchError> { - const CONFIGURATION_ACTIVE_CONFIG_KEY: &[u8] = - &hex_literal::hex!("06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385"); + let old_config_bytes = frame_support::storage::unhashed::get_raw( + &pallet_configuration::ActiveConfig::::hashed_key(), + ) + .unwrap(); + let old_config: Result = + DecodeAll::decode_all(&mut old_config_bytes.as_ref()); + let new_config: Result = + DecodeAll::decode_all(&mut old_config_bytes.as_ref()); - let old_config_bytes = - frame_support::storage::unhashed::get_raw(CONFIGURATION_ACTIVE_CONFIG_KEY) - .expect("configuration.activeConfig should have value"); - // This works because there is no enum in the v2 - assert_eq!( - old_config_bytes.len(), - HostConfigurationV2::default().encoded_size() - ); + assert!(old_config.is_ok()); + assert!(new_config.is_err()); - use parity_scale_codec::Encode; - Ok((old_config_bytes).encode()) + Ok(vec![]) } /// Run a standard post-runtime test. This works the same way as in a normal runtime upgrade. @@ -167,132 +170,24 @@ where &self, _number_of_invulnerables: Vec, ) -> Result<(), sp_runtime::DispatchError> { - let new_config = pallet_configuration::Pallet::::config(); - let default_config = HostConfiguration::default(); - assert_eq!( - new_config.max_parachain_cores_percentage, - default_config.max_parachain_cores_percentage - ); - Ok(()) - } -} - -#[derive( - Clone, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - PartialEq, - sp_core::RuntimeDebug, - scale_info::TypeInfo, -)] -struct HostConfigurationV1 { - pub max_collators: u32, - pub min_orchestrator_collators: u32, - pub max_orchestrator_collators: u32, - pub collators_per_container: u32, - pub full_rotation_period: u32, -} - -pub struct MigrateConfigurationParathreads(pub PhantomData); -impl Migration for MigrateConfigurationParathreads -where - T: pallet_configuration::Config, -{ - fn friendly_name(&self) -> &str { - "TM_MigrateConfigurationParathreads" - } - - fn migrate(&self, _available_weight: Weight) -> Weight { - const CONFIGURATION_ACTIVE_CONFIG_KEY: &[u8] = - &hex_literal::hex!("06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385"); - const CONFIGURATION_PENDING_CONFIGS_KEY: &[u8] = - &hex_literal::hex!("06de3d8a54d27e44a9d5ce189618f22d53b4123b2e186e07fb7bad5dda5f55c0"); - let default_config = HostConfiguration::default(); - - // Modify active config - let old_config: HostConfigurationV1 = - frame_support::storage::unhashed::get(CONFIGURATION_ACTIVE_CONFIG_KEY) - .expect("configuration.activeConfig should have value"); - let new_config = HostConfiguration { - max_collators: old_config.max_collators, - min_orchestrator_collators: old_config.min_orchestrator_collators, - max_orchestrator_collators: old_config.max_orchestrator_collators, - collators_per_container: old_config.collators_per_container, - full_rotation_period: old_config.full_rotation_period, - collators_per_parathread: default_config.collators_per_parathread, - parathreads_per_collator: default_config.parathreads_per_collator, - target_container_chain_fullness: default_config.target_container_chain_fullness, - max_parachain_cores_percentage: default_config.max_parachain_cores_percentage, - }; - frame_support::storage::unhashed::put(CONFIGURATION_ACTIVE_CONFIG_KEY, &new_config); - - // Modify pending configs, if any - let old_pending_configs: Vec<(u32, HostConfigurationV1)> = - frame_support::storage::unhashed::get(CONFIGURATION_PENDING_CONFIGS_KEY) - .unwrap_or_default(); - let mut new_pending_configs: Vec<(u32, HostConfiguration)> = vec![]; - - for (session_index, old_config) in old_pending_configs { - let new_config = HostConfiguration { - max_collators: old_config.max_collators, - min_orchestrator_collators: old_config.min_orchestrator_collators, - max_orchestrator_collators: old_config.max_orchestrator_collators, - collators_per_container: old_config.collators_per_container, - full_rotation_period: old_config.full_rotation_period, - collators_per_parathread: default_config.collators_per_parathread, - parathreads_per_collator: default_config.parathreads_per_collator, - target_container_chain_fullness: default_config.target_container_chain_fullness, - max_parachain_cores_percentage: default_config.max_parachain_cores_percentage, - }; - new_pending_configs.push((session_index, new_config)); - } - - if !new_pending_configs.is_empty() { - frame_support::storage::unhashed::put( - CONFIGURATION_PENDING_CONFIGS_KEY, - &new_pending_configs, - ); - } - - ::WeightInfo::set_config_with_u32() - } - - /// Run a standard pre-runtime test. This works the same way as in a normal runtime upgrade. - #[cfg(feature = "try-runtime")] - fn pre_upgrade(&self) -> Result, sp_runtime::DispatchError> { - const CONFIGURATION_ACTIVE_CONFIG_KEY: &[u8] = - &hex_literal::hex!("06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385"); - - let old_config_bytes = - frame_support::storage::unhashed::get_raw(CONFIGURATION_ACTIVE_CONFIG_KEY) - .expect("configuration.activeConfig should have value"); - assert_eq!(old_config_bytes.len(), 20); + let new_config_bytes = frame_support::storage::unhashed::get_raw( + &pallet_configuration::ActiveConfig::::hashed_key(), + ) + .unwrap(); + let old_config: Result = + DecodeAll::decode_all(&mut new_config_bytes.as_ref()); + let new_config: Result = + DecodeAll::decode_all(&mut new_config_bytes.as_ref()); - use parity_scale_codec::Encode; - Ok((old_config_bytes).encode()) - } + assert!(old_config.is_err()); + assert!(new_config.is_ok()); - /// Run a standard post-runtime test. This works the same way as in a normal runtime upgrade. - #[cfg(feature = "try-runtime")] - fn post_upgrade( - &self, - _number_of_invulnerables: Vec, - ) -> Result<(), sp_runtime::DispatchError> { let new_config = pallet_configuration::Pallet::::config(); let default_config = HostConfiguration::default(); assert_eq!( - new_config.collators_per_parathread, - default_config.collators_per_parathread + new_config.full_rotation_mode, + default_config.full_rotation_mode ); - assert_eq!( - new_config.parathreads_per_collator, - default_config.collators_per_parathread - ); - assert_eq!( - new_config.target_container_chain_fullness, - default_config.target_container_chain_fullness - ); - Ok(()) } } @@ -961,19 +856,20 @@ where //let migrate_services_payment = // MigrateServicesPaymentAddCredits::(Default::default()); //let migrate_boot_nodes = MigrateBootNodes::(Default::default()); - let migrate_config_parathread_params = - MigrateConfigurationParathreads::(Default::default()); - - let migrate_add_collator_assignment_credits = - MigrateServicesPaymentAddCollatorAssignmentCredits::(Default::default()); - let migrate_registrar_pending_verification = - RegistrarPendingVerificationValueToMap::(Default::default()); - let migrate_registrar_manager = - RegistrarParaManagerMigration::(Default::default()); - let migrate_data_preservers_assignments = - DataPreserversAssignmentsMigration::(Default::default()); - let migrate_registrar_reserves = RegistrarReserveToHoldMigration::(Default::default()); - let migrate_config_max_parachain_percentage = MigrateConfigurationAddParachainPercentage::(Default::default()); + //let migrate_config_parathread_params = + // MigrateConfigurationParathreads::(Default::default()); + + //let migrate_add_collator_assignment_credits = + // MigrateServicesPaymentAddCollatorAssignmentCredits::(Default::default()); + //let migrate_registrar_pending_verification = + // RegistrarPendingVerificationValueToMap::(Default::default()); + //let migrate_registrar_manager = + // RegistrarParaManagerMigration::(Default::default()); + //let migrate_data_preservers_assignments = + // DataPreserversAssignmentsMigration::(Default::default()); + //let migrate_registrar_reserves = RegistrarReserveToHoldMigration::(Default::default()); + //let migrate_config_max_parachain_percentage = MigrateConfigurationAddParachainPercentage::(Default::default()); + let migrate_config_full_rotation_mode = MigrateConfigurationAddFullRotationMode::(Default::default()); vec![ // Applied in runtime 400 @@ -981,13 +877,20 @@ where // Applied in runtime 400 //Box::new(migrate_boot_nodes), // Applied in runtime 400 - Box::new(migrate_config_parathread_params), - Box::new(migrate_add_collator_assignment_credits), - Box::new(migrate_registrar_pending_verification), - Box::new(migrate_registrar_manager), - Box::new(migrate_data_preservers_assignments), - Box::new(migrate_registrar_reserves), - Box::new(migrate_config_max_parachain_percentage), + //Box::new(migrate_config_parathread_params), + // Applied in runtime 500 + //Box::new(migrate_add_collator_assignment_credits), + // Applied in runtime 700 + //Box::new(migrate_registrar_pending_verification), + // Applied in runtime 700 + //Box::new(migrate_registrar_manager), + // Applied in runtime 700 + //Box::new(migrate_data_preservers_assignments), + // Applied in runtime 800 + //Box::new(migrate_registrar_reserves), + // Applied in runtime 900 + //Box::new(migrate_config_max_parachain_percentage), + Box::new(migrate_config_full_rotation_mode), ] } } @@ -1027,23 +930,23 @@ where // let migrate_hold_reason_runtime_enum = // MigrateHoldReasonRuntimeEnum::(Default::default()); - let migrate_config_parathread_params = - MigrateConfigurationParathreads::(Default::default()); - let migrate_add_collator_assignment_credits = - MigrateServicesPaymentAddCollatorAssignmentCredits::(Default::default()); - let migrate_xcmp_queue_v4 = XcmpQueueMigrationV4::(Default::default()); - let migrate_registrar_pending_verification = - RegistrarPendingVerificationValueToMap::(Default::default()); - let migrate_registrar_manager = - RegistrarParaManagerMigration::(Default::default()); - let migrate_data_preservers_assignments = - DataPreserversAssignmentsMigration::(Default::default()); - - let migrate_pallet_xcm_v4 = MigrateToLatestXcmVersion::(Default::default()); - let foreign_asset_creator_migration = - ForeignAssetCreatorMigration::(Default::default()); - let migrate_registrar_reserves = RegistrarReserveToHoldMigration::(Default::default()); - let migrate_config_max_parachain_percentage = MigrateConfigurationAddParachainPercentage::(Default::default()); + //let migrate_config_parathread_params = + // MigrateConfigurationParathreads::(Default::default()); + //let migrate_add_collator_assignment_credits = + // MigrateServicesPaymentAddCollatorAssignmentCredits::(Default::default()); + //let migrate_xcmp_queue_v4 = XcmpQueueMigrationV4::(Default::default()); + //let migrate_registrar_pending_verification = + // RegistrarPendingVerificationValueToMap::(Default::default()); + //let migrate_registrar_manager = + // RegistrarParaManagerMigration::(Default::default()); + //let migrate_data_preservers_assignments = + // DataPreserversAssignmentsMigration::(Default::default()); + + //let migrate_pallet_xcm_v4 = MigrateToLatestXcmVersion::(Default::default()); + //let foreign_asset_creator_migration = + // ForeignAssetCreatorMigration::(Default::default()); + //let migrate_registrar_reserves = RegistrarReserveToHoldMigration::(Default::default()); + let migrate_config_full_rotation_mode = MigrateConfigurationAddFullRotationMode::(Default::default()); vec![ // Applied in runtime 200 @@ -1062,16 +965,27 @@ where //Box::new(migrate_hold_reason_runtime_enum), // Applied in runtime 400 //Box::new(migrate_boot_nodes), - Box::new(migrate_config_parathread_params), - Box::new(migrate_add_collator_assignment_credits), - Box::new(migrate_xcmp_queue_v4), - Box::new(migrate_registrar_pending_verification), - Box::new(migrate_registrar_manager), - Box::new(migrate_pallet_xcm_v4), - Box::new(foreign_asset_creator_migration), - Box::new(migrate_data_preservers_assignments), - Box::new(migrate_registrar_reserves), - Box::new(migrate_config_max_parachain_percentage) + // Applied in runtime 500 + //Box::new(migrate_config_parathread_params), + // Applied in runtime 500 + //Box::new(migrate_add_collator_assignment_credits), + // Applied in runtime 500 + //Box::new(migrate_xcmp_queue_v4), + // Applied in runtime 700 + //Box::new(migrate_registrar_pending_verification), + // Applied in runtime 700 + //Box::new(migrate_registrar_manager), + // Applied in runtime 700 + //Box::new(migrate_pallet_xcm_v4), + // Applied in runtime 700 + //Box::new(foreign_asset_creator_migration), + // Applied in runtime 700 + //Box::new(migrate_data_preservers_assignments), + // Applied in runtime 800 + //Box::new(migrate_registrar_reserves), + // Applied in runtime 900 + //Box::new(migrate_config_max_parachain_percentage), + Box::new(migrate_config_full_rotation_mode), ] } } @@ -1116,6 +1030,7 @@ impl GetMigrations for DancelightMigrations where Runtime: frame_system::Config, Runtime: pallet_external_validators::Config, + Runtime: pallet_configuration::Config, Runtime: pallet_session::Config< ValidatorId = ::ValidatorId, >, @@ -1124,10 +1039,13 @@ where let migrate_mmr_leaf_pallet = MigrateMMRLeafPallet::(Default::default()); let migrate_external_validators = ExternalValidatorsInitialMigration::(Default::default()); + let migrate_config_full_rotation_mode = + MigrateConfigurationAddFullRotationMode::(Default::default()); vec![ Box::new(migrate_mmr_leaf_pallet), Box::new(migrate_external_validators), + Box::new(migrate_config_full_rotation_mode), ] } } diff --git a/runtime/dancebox/src/tests/integration_test.rs b/runtime/dancebox/src/tests/integration_test.rs index 4083a6963..64e43b3dc 100644 --- a/runtime/dancebox/src/tests/integration_test.rs +++ b/runtime/dancebox/src/tests/integration_test.rs @@ -60,8 +60,7 @@ use { }, std::marker::PhantomData, tanssi_runtime_common::migrations::{ - ForeignAssetCreatorMigration, HostConfigurationV2, - MigrateConfigurationAddParachainPercentage, MigrateConfigurationParathreads, + ForeignAssetCreatorMigration, HostConfigurationV3, MigrateConfigurationAddFullRotationMode, MigrateServicesPaymentAddCollatorAssignmentCredits, RegistrarPendingVerificationValueToMap, }, test_relay_sproof_builder::{HeaderAs, ParaHeaderSproofBuilder, ParaHeaderSproofBuilderItem}, @@ -3898,7 +3897,7 @@ fn test_reward_to_invulnerable_with_key_change() { } #[test] -fn test_migration_config_add_parachain_percentage() { +fn test_migration_config_add_full_rotation_mode() { ExtBuilder::default().build().execute_with(|| { const CONFIGURATION_ACTIVE_CONFIG_KEY: &[u8] = &hex_literal::hex!("06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385"); @@ -3908,7 +3907,7 @@ fn test_migration_config_add_parachain_percentage() { // Modify active config frame_support::storage::unhashed::put_raw( CONFIGURATION_ACTIVE_CONFIG_KEY, - &HostConfigurationV2 { + &HostConfigurationV3 { max_collators: 5, min_orchestrator_collators: 2, max_orchestrator_collators: 1, @@ -3917,6 +3916,7 @@ fn test_migration_config_add_parachain_percentage() { collators_per_parathread: 2, parathreads_per_collator: 1, target_container_chain_fullness: Perbill::from_percent(45), + max_parachain_cores_percentage: Some(Perbill::from_percent(75)), } .encode(), ); @@ -3926,7 +3926,7 @@ fn test_migration_config_add_parachain_percentage() { &vec![ ( 1234u32, - HostConfigurationV2 { + HostConfigurationV3 { max_collators: 1, min_orchestrator_collators: 4, max_orchestrator_collators: 45, @@ -3935,11 +3935,12 @@ fn test_migration_config_add_parachain_percentage() { collators_per_parathread: 1, parathreads_per_collator: 1, target_container_chain_fullness: Perbill::from_percent(65), + max_parachain_cores_percentage: Some(Perbill::from_percent(75)), }, ), ( 5678u32, - HostConfigurationV2 { + HostConfigurationV3 { max_collators: 1, min_orchestrator_collators: 4, max_orchestrator_collators: 45, @@ -3948,13 +3949,14 @@ fn test_migration_config_add_parachain_percentage() { collators_per_parathread: 1, parathreads_per_collator: 1, target_container_chain_fullness: Perbill::from_percent(65), + max_parachain_cores_percentage: Some(Perbill::from_percent(75)), }, ), ] .encode(), ); - let migration = MigrateConfigurationAddParachainPercentage::(Default::default()); + let migration = MigrateConfigurationAddFullRotationMode::(Default::default()); migration.migrate(Default::default()); let expected_active = pallet_configuration::HostConfiguration { @@ -3966,6 +3968,7 @@ fn test_migration_config_add_parachain_percentage() { collators_per_parathread: 2, parathreads_per_collator: 1, target_container_chain_fullness: Perbill::from_percent(45), + max_parachain_cores_percentage: Some(Perbill::from_percent(75)), ..Default::default() }; assert_eq!(Configuration::config(), expected_active); @@ -3982,6 +3985,7 @@ fn test_migration_config_add_parachain_percentage() { collators_per_parathread: 1, parathreads_per_collator: 1, target_container_chain_fullness: Perbill::from_percent(65), + max_parachain_cores_percentage: Some(Perbill::from_percent(75)), ..Default::default() }, ), @@ -3996,6 +4000,7 @@ fn test_migration_config_add_parachain_percentage() { collators_per_parathread: 1, parathreads_per_collator: 1, target_container_chain_fullness: Perbill::from_percent(65), + max_parachain_cores_percentage: Some(Perbill::from_percent(75)), ..Default::default() }, ), @@ -4004,62 +4009,6 @@ fn test_migration_config_add_parachain_percentage() { }); } -#[test] -fn test_migration_config_full_rotation_period() { - ExtBuilder::default() - .build() - .execute_with(|| { - const CONFIGURATION_ACTIVE_CONFIG_KEY: &[u8] = - &hex_literal::hex!("06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385"); - const CONFIGURATION_PENDING_CONFIGS_KEY: &[u8] = - &hex_literal::hex!("06de3d8a54d27e44a9d5ce189618f22d53b4123b2e186e07fb7bad5dda5f55c0"); - - // Modify active config - frame_support::storage::unhashed::put_raw(CONFIGURATION_ACTIVE_CONFIG_KEY, &hex_literal::hex!("6300000002000000050000000200000000000000")); - // Modify pending configs - frame_support::storage::unhashed::put_raw(CONFIGURATION_PENDING_CONFIGS_KEY, &hex_literal::hex!("08b10800006300000002000000050000000200000000000000b20800006400000002000000050000000200000000000000")); - - let migration = MigrateConfigurationParathreads::(Default::default()); - migration.migrate(Default::default()); - - let expected_active = pallet_configuration::HostConfiguration { - max_collators: 99, - min_orchestrator_collators: 2, - max_orchestrator_collators: 5, - collators_per_container: 2, - full_rotation_period: 0, - ..Default::default() - }; - assert_eq!(Configuration::config(), expected_active); - - let expected_pending = vec![ - ( - 2225, - pallet_configuration::HostConfiguration { - max_collators: 99, - min_orchestrator_collators: 2, - max_orchestrator_collators: 5, - collators_per_container: 2, - full_rotation_period: 0, - ..Default::default() - }, - ), - ( - 2226, - pallet_configuration::HostConfiguration { - max_collators: 100, - min_orchestrator_collators: 2, - max_orchestrator_collators: 5, - collators_per_container: 2, - full_rotation_period: 0, - ..Default::default() - }, - ), - ]; - assert_eq!(Configuration::pending_configs(), expected_pending); - }); -} - #[test] fn test_migration_registrar_pending_verification() { ExtBuilder::default().build().execute_with(|| { diff --git a/solo-chains/runtime/dancelight/src/tests/integration_test.rs b/solo-chains/runtime/dancelight/src/tests/integration_test.rs index 5018a8de3..cdab01507 100644 --- a/solo-chains/runtime/dancelight/src/tests/integration_test.rs +++ b/solo-chains/runtime/dancelight/src/tests/integration_test.rs @@ -24,10 +24,16 @@ use { cumulus_primitives_core::{relay_chain::HeadData, ParaId}, dancelight_runtime_constants::currency::EXISTENTIAL_DEPOSIT, frame_support::{assert_noop, assert_ok, BoundedVec}, + pallet_migrations::Migration, pallet_registrar_runtime_api::{ runtime_decl_for_registrar_api::RegistrarApi, ContainerChainGenesisData, }, + sp_arithmetic::Perbill, + sp_core::Encode, sp_std::vec, + tanssi_runtime_common::migrations::{ + HostConfigurationV3, MigrateConfigurationAddFullRotationMode, + }, }; #[test] @@ -354,3 +360,116 @@ fn test_container_deregister_unassign_data_preserver() { assert!(pallet_data_preservers::Assignments::::get(para_id).is_empty()); }); } + +#[test] +fn test_migration_config_add_full_rotation_mode() { + ExtBuilder::default().build().execute_with(|| { + const CONFIGURATION_ACTIVE_CONFIG_KEY: &[u8] = + &hex_literal::hex!("86e86c1d728ee2b18f76dd0e04d96cdbb4b49d95320d9021994c850f25b8e385"); + const CONFIGURATION_PENDING_CONFIGS_KEY: &[u8] = + &hex_literal::hex!("86e86c1d728ee2b18f76dd0e04d96cdb53b4123b2e186e07fb7bad5dda5f55c0"); + + // Modify active config + frame_support::storage::unhashed::put_raw( + CONFIGURATION_ACTIVE_CONFIG_KEY, + &HostConfigurationV3 { + max_collators: 5, + min_orchestrator_collators: 2, + max_orchestrator_collators: 1, + collators_per_container: 3, + full_rotation_period: 4, + collators_per_parathread: 2, + parathreads_per_collator: 1, + target_container_chain_fullness: Perbill::from_percent(45), + max_parachain_cores_percentage: Some(Perbill::from_percent(75)), + } + .encode(), + ); + // Modify pending configs + frame_support::storage::unhashed::put_raw( + CONFIGURATION_PENDING_CONFIGS_KEY, + &vec![ + ( + 1234u32, + HostConfigurationV3 { + max_collators: 1, + min_orchestrator_collators: 4, + max_orchestrator_collators: 45, + collators_per_container: 5, + full_rotation_period: 1, + collators_per_parathread: 1, + parathreads_per_collator: 1, + target_container_chain_fullness: Perbill::from_percent(65), + max_parachain_cores_percentage: Some(Perbill::from_percent(75)), + }, + ), + ( + 5678u32, + HostConfigurationV3 { + max_collators: 1, + min_orchestrator_collators: 4, + max_orchestrator_collators: 45, + collators_per_container: 5, + full_rotation_period: 1, + collators_per_parathread: 1, + parathreads_per_collator: 1, + target_container_chain_fullness: Perbill::from_percent(65), + max_parachain_cores_percentage: Some(Perbill::from_percent(75)), + }, + ), + ] + .encode(), + ); + + let migration = MigrateConfigurationAddFullRotationMode::(Default::default()); + migration.migrate(Default::default()); + + let expected_active = pallet_configuration::HostConfiguration { + max_collators: 5, + min_orchestrator_collators: 2, + max_orchestrator_collators: 1, + collators_per_container: 3, + full_rotation_period: 4, + collators_per_parathread: 2, + parathreads_per_collator: 1, + target_container_chain_fullness: Perbill::from_percent(45), + max_parachain_cores_percentage: Some(Perbill::from_percent(75)), + ..Default::default() + }; + assert_eq!(CollatorConfiguration::config(), expected_active); + + let expected_pending = vec![ + ( + 1234u32, + pallet_configuration::HostConfiguration { + max_collators: 1, + min_orchestrator_collators: 4, + max_orchestrator_collators: 45, + collators_per_container: 5, + full_rotation_period: 1, + collators_per_parathread: 1, + parathreads_per_collator: 1, + target_container_chain_fullness: Perbill::from_percent(65), + max_parachain_cores_percentage: Some(Perbill::from_percent(75)), + ..Default::default() + }, + ), + ( + 5678u32, + pallet_configuration::HostConfiguration { + max_collators: 1, + min_orchestrator_collators: 4, + max_orchestrator_collators: 45, + collators_per_container: 5, + full_rotation_period: 1, + collators_per_parathread: 1, + parathreads_per_collator: 1, + target_container_chain_fullness: Perbill::from_percent(65), + max_parachain_cores_percentage: Some(Perbill::from_percent(75)), + ..Default::default() + }, + ), + ]; + assert_eq!(CollatorConfiguration::pending_configs(), expected_pending); + }); +} diff --git a/solo-chains/runtime/dancelight/src/tests/mod.rs b/solo-chains/runtime/dancelight/src/tests/mod.rs index 9b6b57bee..35a6715c4 100644 --- a/solo-chains/runtime/dancelight/src/tests/mod.rs +++ b/solo-chains/runtime/dancelight/src/tests/mod.rs @@ -16,9 +16,10 @@ //! Tests for the Dancelight Runtime Configuration -use {crate::*, std::collections::HashSet}; - -use {frame_support::traits::WhitelistedStorageKeys, sp_core::hexdisplay::HexDisplay}; +use { + crate::*, frame_support::traits::WhitelistedStorageKeys, sp_core::hexdisplay::HexDisplay, + std::collections::HashSet, +}; mod author_noting_tests; mod beefy; diff --git a/test/suites/dev-tanssi/collator-assignment/test-full-rotation-mode-parathreads.ts b/test/suites/dev-tanssi/collator-assignment/test-full-rotation-mode-parathreads.ts new file mode 100644 index 000000000..bab2a25b9 --- /dev/null +++ b/test/suites/dev-tanssi/collator-assignment/test-full-rotation-mode-parathreads.ts @@ -0,0 +1,275 @@ +import "@tanssi/api-augment"; +import { describeSuite, expect, beforeAll, customDevRpcRequest } from "@moonwall/cli"; +import { ApiPromise } from "@polkadot/api"; +import { jumpBlocks, jumpSessions, jumpToSession } from "util/block"; +import { filterAndApply, generateKeyringPair } from "@moonwall/util"; +import { EventRecord } from "@polkadot/types/interfaces"; +import { bool, u32, u8, Vec } from "@polkadot/types-codec"; + +describeSuite({ + id: "DTR0304", + title: "Collator assignment tests", + foundationMethods: "dev", + + testCases: ({ it, context }) => { + let polkadotJs: ApiPromise; + let alice; + + beforeAll(async () => { + polkadotJs = context.polkadotJs(); + alice = context.keyring.alice; + + // Enable randomness for this test. + // Add a custom seed because with the default one this test fails because collators get assigned to the same + // chain again. + await customDevRpcRequest("mock_activateRandomness", [ + "4bbc1fee42ce06ff37f5a07744346c1e0b43c8a4130db8ec5ae41f3234f5c421", + ]); + }); + + it({ + id: "E01", + title: "Collator should rotate", + test: async function () { + const orchestrator = "RotateAll"; + const parachain = "KeepAll"; + const parathread = { KeepPerbill: { percentage: 500_000_000n } }; // 50% + const tx = context + .polkadotJs() + .tx.configuration.setFullRotationMode(orchestrator, parachain, parathread); + await context.createBlock(polkadotJs.tx.sudo.sudo(tx).signAsync(alice)); + const tx2 = context.polkadotJs().tx.configuration.setCollatorsPerParathread(2); + await context.createBlock(polkadotJs.tx.sudo.sudo(tx2).signAsync(alice)); + + // Add 4 collators more + // Use random accounts + let aliceNonce = (await polkadotJs.query.system.account(alice.address)).nonce.toNumber(); + const randomAccounts = []; + + for (let i = 0; i < 4; i++) { + const randomAccount = generateKeyringPair("sr25519"); + randomAccounts.push(randomAccount); + } + + // First block, send some balance to each account. This needs to go first because `.signAndSend(randomAccount)` + // given an error if the account has no balance, even though we send some balance and it's pending. + for (const randomAccount of randomAccounts) { + const value = 100_000_000_000n; + await polkadotJs.tx.balances + .transferAllowDeath(randomAccount.address, value) + .signAndSend(alice, { nonce: aliceNonce++ }); + } + + await context.createBlock(); + + // Second block, add keys and register them as invulnerables + for (const randomAccount of randomAccounts) { + const newKey1 = await polkadotJs.rpc.author.rotateKeys(); + await polkadotJs.tx.session.setKeys(newKey1, []).signAndSend(randomAccount); + + await polkadotJs.tx.sudo + .sudo(polkadotJs.tx.invulnerables.addInvulnerable(randomAccount.address)) + .signAndSend(alice, { nonce: aliceNonce++ }); + } + await context.createBlock(); + + // Deregister container chains and register parathreads instead + await deregisterAll(context); + await registerParathreads(context); + + // Collators are registered, wait 2 sessions for them to be assigned + await jumpSessions(context, 1); + + const fullRotationPeriod = (await polkadotJs.query.configuration.activeConfig())[ + "fullRotationPeriod" + ].toString(); + const sessionIndex = (await polkadotJs.query.session.currentIndex()).toNumber(); + // Calculate the remaining sessions for next full rotation + // This is a workaround for running moonwall in run mode + // as it runs all tests in the same chain instance + const remainingSessionsForRotation = + sessionIndex > fullRotationPeriod ? sessionIndex % fullRotationPeriod : fullRotationPeriod; + + await jumpToSession(context, remainingSessionsForRotation - 2); + + const initialAssignment = (await polkadotJs.query.collatorAssignment.collatorContainerChain()).toJSON(); + + expect(initialAssignment.containerChains[2002].length).to.eq(2); + expect((await polkadotJs.query.collatorAssignment.pendingCollatorContainerChain()).isNone); + + // remainingSessionsForRotation - 1 + await jumpSessions(context, 1); + const rotationEndAssignment = ( + await polkadotJs.query.collatorAssignment.collatorContainerChain() + ).toJSON(); + + expect((await polkadotJs.query.collatorAssignment.pendingCollatorContainerChain()).isSome); + // Assignment shouldn't have changed yet + expect(initialAssignment.containerChains[2002].toSorted()).to.deep.eq( + rotationEndAssignment.containerChains[2002].toSorted() + ); + + // In dev-tanssi, randomness depends only on the block number so it is actually deterministic. + // First, check that the event has randomness + const events = await polkadotJs.query.system.events(); + const filteredEvents = filterAndApply( + events, + "collatorAssignment", + ["NewPendingAssignment"], + ({ event }: EventRecord) => + event.data as unknown as { randomSeed: Vec; fullRotation: bool; targetSession: u32 } + ); + expect(filteredEvents[0].fullRotation.toJSON()).toBe(true); + // In dev mode randomness is deterministic so the seed should not change, but we only want to check that + // it's not 0x0000..., so it doesn't matter if it changes. + expect(filteredEvents[0].randomSeed.toHex()).to.deep.eq( + "0x8b145bb9825b580a7a571099151e7ac459b83103abec71bc4d322bcd5bef153f" + ); + + // Check that the randomness is set in CollatorAssignment the + // block previous to the full rotation + const sessionDuration = 10; + await jumpBlocks(context, sessionDuration - 1); + + const assignmentRandomness = await polkadotJs.query.collatorAssignment.randomness(); + expect(assignmentRandomness.isEmpty).toBe(false); + + // Start session 5, with the new random assignment + await jumpSessions(context, 1); + + const newAssignment = (await polkadotJs.query.collatorAssignment.collatorContainerChain()).toJSON(); + + // Assignment should have changed + expect(newAssignment).to.not.deep.eq(initialAssignment); + + // Orchestrator collators should change + // But they don't change because they are invulnerables, and invulnerables that were previously assigned have priority. + expect(newAssignment.orchestratorChain).to.not.eq(initialAssignment.orchestratorChain); + + const arrayIntersection = (arr1, arr2) => { + const set2 = new Set(arr2); + return arr1.filter((item) => set2.has(item)); + }; + + // Parathread collators should keep 1 and rotate the other one + expect(newAssignment.containerChains["2002"].length).toBe(2); + const sameCollators2002 = arrayIntersection( + newAssignment.containerChains["2002"], + initialAssignment.containerChains["2002"] + ); + expect(sameCollators2002.length).toBe(1); + expect(newAssignment.containerChains["2003"].length).toBe(2); + const sameCollators2003 = arrayIntersection( + newAssignment.containerChains["2003"], + initialAssignment.containerChains["2003"] + ); + expect(sameCollators2003.length).toBe(1); + }, + }); + }, +}); + +async function deregisterAll(context) { + const polkadotJs = context.polkadotJs(); + const alice = context.keyring.alice; + const parasRegistered = (await polkadotJs.query.registrar.registeredParaIds()).toJSON(); + + const txs = []; + + for (const paraId of parasRegistered) { + const tx = polkadotJs.tx.registrar.deregister(paraId); + txs.push(tx); + } + + await context.createBlock([await polkadotJs.tx.sudo.sudo(polkadotJs.tx.utility.batchAll(txs)).signAsync(alice)]); +} + +async function registerParathreads(context) { + const polkadotJs = context.polkadotJs(); + const alice = context.keyring.alice; + await context.createBlock(); + + const currentSesssion = await polkadotJs.query.session.currentIndex(); + const sessionDelay = await polkadotJs.consts.registrar.sessionDelay; + const expectedScheduledOnboarding = BigInt(currentSesssion.toString()) + BigInt(sessionDelay.toString()); + + const slotFrequency = polkadotJs.createType("TpTraitsSlotFrequency", { + min: 1, + max: 1, + }); + const emptyGenesisData = () => { + const g = polkadotJs.createType("DpContainerChainGenesisDataContainerChainGenesisData", { + storage: [ + { + key: "0x636f6465", + value: "0x010203040506", + }, + ], + name: "0x436f6e7461696e657220436861696e2032303030", + id: "0x636f6e7461696e65722d636861696e2d32303030", + forkId: null, + extensions: "0x", + properties: { + tokenMetadata: { + tokenSymbol: "0x61626364", + ss58Format: 42, + tokenDecimals: 12, + }, + isEthereum: false, + }, + }); + return g; + }; + + const containerChainGenesisData = emptyGenesisData(); + + for (const paraId of [2002, 2003]) { + const tx = polkadotJs.tx.registrar.registerParathread(paraId, slotFrequency, containerChainGenesisData, null); + + const profileId = await polkadotJs.query.dataPreservers.nextProfileId(); + const tx2 = polkadotJs.tx.dataPreservers.createProfile({ + url: "/ip4/127.0.0.1/tcp/33051/ws/p2p/12D3KooWSDsmAa7iFbHdQW4X8B2KbeRYPDLarK6EbevUSYfGkeQw", + paraIds: "AnyParaId", + mode: "Bootnode", + assignmentRequest: "Free", + }); + + const tx3 = polkadotJs.tx.dataPreservers.startAssignment(profileId, paraId, "Free"); + const tx4 = polkadotJs.tx.registrar.markValidForCollating(paraId); + const nonce = await polkadotJs.rpc.system.accountNextIndex(alice.publicKey); + await context.createBlock([ + await tx.signAsync(alice, { nonce }), + await tx2.signAsync(alice, { nonce: nonce.addn(1) }), + await tx3.signAsync(alice, { nonce: nonce.addn(2) }), + await polkadotJs.tx.sudo.sudo(tx4).signAsync(alice, { nonce: nonce.addn(3) }), + ]); + } + + const pendingParas = await polkadotJs.query.registrar.pendingParaIds(); + expect(pendingParas.length).to.be.eq(1); + const sessionScheduling = pendingParas[0][0]; + const parasScheduled = pendingParas[0][1]; + + expect(sessionScheduling.toBigInt()).to.be.eq(expectedScheduledOnboarding); + + // These will be the paras in session 2 + // TODO: fix once we have types + expect(parasScheduled.toJSON()).to.deep.equal([2002, 2003]); + + // Check that the on chain genesis data is set correctly + const onChainGenesisData = await polkadotJs.query.registrar.paraGenesisData(2002); + // TODO: fix once we have types + expect(emptyGenesisData().toJSON()).to.deep.equal(onChainGenesisData.toJSON()); + + // Check the para id has been given some free credits + const credits = (await polkadotJs.query.servicesPayment.blockProductionCredits(2002)).toJSON(); + expect(credits, "Container chain 2002 should have been given credits").toBeGreaterThan(0); + + // Checking that in session 2 paras are registered + await jumpSessions(context, 2); + + // Expect now paraIds to be registered + const parasRegistered = await polkadotJs.query.registrar.registeredParaIds(); + // TODO: fix once we have types + expect(parasRegistered.toJSON()).to.deep.equal([2002, 2003]); +} diff --git a/test/suites/dev-tanssi/collator-assignment/test-full-rotation-mode.ts b/test/suites/dev-tanssi/collator-assignment/test-full-rotation-mode.ts new file mode 100644 index 000000000..35f93a494 --- /dev/null +++ b/test/suites/dev-tanssi/collator-assignment/test-full-rotation-mode.ts @@ -0,0 +1,159 @@ +import "@tanssi/api-augment"; +import { describeSuite, expect, beforeAll, customDevRpcRequest } from "@moonwall/cli"; +import { ApiPromise } from "@polkadot/api"; +import { jumpBlocks, jumpSessions, jumpToSession } from "util/block"; +import { filterAndApply, generateKeyringPair } from "@moonwall/util"; +import { EventRecord } from "@polkadot/types/interfaces"; +import { bool, u32, u8, Vec } from "@polkadot/types-codec"; + +describeSuite({ + id: "DTR0303", + title: "Collator assignment tests", + foundationMethods: "dev", + + testCases: ({ it, context }) => { + let polkadotJs: ApiPromise; + let alice; + + beforeAll(async () => { + polkadotJs = context.polkadotJs(); + alice = context.keyring.alice; + + // Enable randomness for this test + await customDevRpcRequest("mock_activateRandomness", []); + }); + + it({ + id: "E01", + title: "Collator should rotate", + test: async function () { + const orchestrator = "KeepAll"; + const parachain = { KeepCollators: { keep: 1 } }; + const parathread = "RotateAll"; + const tx = context + .polkadotJs() + .tx.configuration.setFullRotationMode(orchestrator, parachain, parathread); + await context.createBlock(polkadotJs.tx.sudo.sudo(tx).signAsync(alice)); + + // Add 4 collators more + // Use random accounts + let aliceNonce = (await polkadotJs.query.system.account(alice.address)).nonce.toNumber(); + const randomAccounts = []; + + for (let i = 0; i < 4; i++) { + const randomAccount = generateKeyringPair("sr25519"); + randomAccounts.push(randomAccount); + } + + // First block, send some balance to each account. This needs to go first because `.signAndSend(randomAccount)` + // given an error if the account has no balance, even though we send some balance and it's pending. + for (const randomAccount of randomAccounts) { + const value = 100_000_000_000n; + await polkadotJs.tx.balances + .transferAllowDeath(randomAccount.address, value) + .signAndSend(alice, { nonce: aliceNonce++ }); + } + + await context.createBlock(); + + // Second block, add keys and register them as invulnerables + for (const randomAccount of randomAccounts) { + const newKey1 = await polkadotJs.rpc.author.rotateKeys(); + await polkadotJs.tx.session.setKeys(newKey1, []).signAndSend(randomAccount); + + await polkadotJs.tx.sudo + .sudo(polkadotJs.tx.invulnerables.addInvulnerable(randomAccount.address)) + .signAndSend(alice, { nonce: aliceNonce++ }); + } + await context.createBlock(); + + // Collators are registered, wait 2 sessions for them to be assigned + await jumpSessions(context, 2); + + const fullRotationPeriod = (await polkadotJs.query.configuration.activeConfig())[ + "fullRotationPeriod" + ].toString(); + const sessionIndex = (await polkadotJs.query.session.currentIndex()).toNumber(); + // Calculate the remaining sessions for next full rotation + // This is a workaround for running moonwall in run mode + // as it runs all tests in the same chain instance + const remainingSessionsForRotation = + sessionIndex > fullRotationPeriod ? sessionIndex % fullRotationPeriod : fullRotationPeriod; + + await jumpToSession(context, remainingSessionsForRotation - 2); + + const initialAssignment = (await polkadotJs.query.collatorAssignment.collatorContainerChain()).toJSON(); + + expect(initialAssignment.containerChains[2000].length).to.eq(2); + expect((await polkadotJs.query.collatorAssignment.pendingCollatorContainerChain()).isNone); + + // remainingSessionsForRotation - 1 + await jumpSessions(context, 1); + const rotationEndAssignment = ( + await polkadotJs.query.collatorAssignment.collatorContainerChain() + ).toJSON(); + + expect((await polkadotJs.query.collatorAssignment.pendingCollatorContainerChain()).isSome); + // Assignment shouldn't have changed yet + expect(initialAssignment.containerChains[2000].toSorted()).to.deep.eq( + rotationEndAssignment.containerChains[2000].toSorted() + ); + + // In dev-tanssi, randomness depends only on the block number so it is actually deterministic. + // First, check that the event has randomness + const events = await polkadotJs.query.system.events(); + const filteredEvents = filterAndApply( + events, + "collatorAssignment", + ["NewPendingAssignment"], + ({ event }: EventRecord) => + event.data as unknown as { randomSeed: Vec; fullRotation: bool; targetSession: u32 } + ); + expect(filteredEvents[0].fullRotation.toJSON()).toBe(true); + // Randomness is deterministic so the seed should not change, but we only want to check that it's not 0x0000..., + // so it doesn't matter if it changes. + expect(filteredEvents[0].randomSeed.toHex()).to.deep.eq( + "0xf497424c947d1b548a64ce4697f8fa8f84c6d73b7ceedf4d4f9cb65665fb9cc1" + ); + + // Check that the randomness is set in CollatorAssignment the + // block previous to the full rotation + const sessionDuration = 10; + await jumpBlocks(context, sessionDuration - 1); + + const assignmentRandomness = await polkadotJs.query.collatorAssignment.randomness(); + expect(assignmentRandomness.isEmpty).toBe(false); + + // Start session 5, with the new random assignment + await jumpSessions(context, 1); + + const newAssignment = (await polkadotJs.query.collatorAssignment.collatorContainerChain()).toJSON(); + + // Assignment should have changed + expect(newAssignment).to.not.deep.eq(initialAssignment); + + // Orchestrator collators should not change + expect(newAssignment.orchestratorChain).to.deep.eq(initialAssignment.orchestratorChain); + + const arrayIntersection = (arr1, arr2) => { + const set2 = new Set(arr2); + return arr1.filter((item) => set2.has(item)); + }; + + // Parachain collators should keep 1 and rotate the other one + expect(newAssignment.containerChains["2000"].length).toBe(2); + const sameCollators2000 = arrayIntersection( + newAssignment.containerChains["2000"], + initialAssignment.containerChains["2000"] + ); + expect(sameCollators2000.length).toBe(1); + expect(newAssignment.containerChains["2001"].length).toBe(2); + const sameCollators2001 = arrayIntersection( + newAssignment.containerChains["2001"], + initialAssignment.containerChains["2001"] + ); + expect(sameCollators2001.length).toBe(1); + }, + }); + }, +}); diff --git a/typescript-api/src/dancebox/interfaces/augment-api-events.ts b/typescript-api/src/dancebox/interfaces/augment-api-events.ts index ccdfeb8d4..f270aa92d 100644 --- a/typescript-api/src/dancebox/interfaces/augment-api-events.ts +++ b/typescript-api/src/dancebox/interfaces/augment-api-events.ts @@ -27,6 +27,7 @@ import type { StagingXcmV4Response, StagingXcmV4TraitsOutcome, StagingXcmV4Xcm, + TpTraitsFullRotationModes, XcmV3TraitsError, XcmVersionedAssets, XcmVersionedLocation, @@ -139,8 +140,18 @@ declare module "@polkadot/api-base/types/events" { collatorAssignment: { NewPendingAssignment: AugmentedEvent< ApiType, - [randomSeed: U8aFixed, fullRotation: bool, targetSession: u32], - { randomSeed: U8aFixed; fullRotation: bool; targetSession: u32 } + [ + randomSeed: U8aFixed, + fullRotation: bool, + targetSession: u32, + fullRotationMode: TpTraitsFullRotationModes, + ], + { + randomSeed: U8aFixed; + fullRotation: bool; + targetSession: u32; + fullRotationMode: TpTraitsFullRotationModes; + } >; /** Generic event */ [key: string]: AugmentedEvent; diff --git a/typescript-api/src/dancebox/interfaces/augment-api-tx.ts b/typescript-api/src/dancebox/interfaces/augment-api-tx.ts index 3d243c7b1..d6aeee376 100644 --- a/typescript-api/src/dancebox/interfaces/augment-api-tx.ts +++ b/typescript-api/src/dancebox/interfaces/augment-api-tx.ts @@ -46,6 +46,7 @@ import type { StagingXcmV4Location, StagingXcmV4Response, TpAuthorNotingInherentOwnParachainInherentData, + TpTraitsFullRotationMode, TpTraitsParathreadParams, TpTraitsSlotFrequency, TpXcmCoreBuyerBuyCoreCollatorProof, @@ -351,6 +352,41 @@ declare module "@polkadot/api-base/types/submittable" { (updated: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [u32] >; + setFullRotationMode: AugmentedSubmittable< + ( + orchestrator: + | Option + | null + | Uint8Array + | TpTraitsFullRotationMode + | { RotateAll: any } + | { KeepAll: any } + | { KeepCollators: any } + | { KeepPerbill: any } + | string, + parachain: + | Option + | null + | Uint8Array + | TpTraitsFullRotationMode + | { RotateAll: any } + | { KeepAll: any } + | { KeepCollators: any } + | { KeepPerbill: any } + | string, + parathread: + | Option + | null + | Uint8Array + | TpTraitsFullRotationMode + | { RotateAll: any } + | { KeepAll: any } + | { KeepCollators: any } + | { KeepPerbill: any } + | string + ) => SubmittableExtrinsic, + [Option, Option, Option] + >; setFullRotationPeriod: AugmentedSubmittable< (updated: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [u32] diff --git a/typescript-api/src/dancebox/interfaces/lookup.ts b/typescript-api/src/dancebox/interfaces/lookup.ts index be7b56b6c..0812edb90 100644 --- a/typescript-api/src/dancebox/interfaces/lookup.ts +++ b/typescript-api/src/dancebox/interfaces/lookup.ts @@ -604,10 +604,30 @@ export default { randomSeed: "[u8;32]", fullRotation: "bool", targetSession: "u32", + fullRotationMode: "TpTraitsFullRotationModes", }, }, }, - /** Lookup63: pallet_author_noting::pallet::Event */ + /** Lookup63: tp_traits::FullRotationModes */ + TpTraitsFullRotationModes: { + orchestrator: "TpTraitsFullRotationMode", + parachain: "TpTraitsFullRotationMode", + parathread: "TpTraitsFullRotationMode", + }, + /** Lookup64: tp_traits::FullRotationMode */ + TpTraitsFullRotationMode: { + _enum: { + RotateAll: "Null", + KeepAll: "Null", + KeepCollators: { + keep: "u32", + }, + KeepPerbill: { + percentage: "Perbill", + }, + }, + }, + /** Lookup66: pallet_author_noting::pallet::Event */ PalletAuthorNotingEvent: { _enum: { LatestAuthorChanged: { @@ -621,7 +641,7 @@ export default { }, }, }, - /** Lookup65: pallet_services_payment::pallet::Event */ + /** Lookup68: pallet_services_payment::pallet::Event */ PalletServicesPaymentEvent: { _enum: { CreditsPurchased: { @@ -660,7 +680,7 @@ export default { }, }, }, - /** Lookup67: pallet_data_preservers::pallet::Event */ + /** Lookup70: pallet_data_preservers::pallet::Event */ PalletDataPreserversEvent: { _enum: { BootNodesChanged: { @@ -690,7 +710,7 @@ export default { }, }, }, - /** Lookup68: pallet_invulnerables::pallet::Event */ + /** Lookup71: pallet_invulnerables::pallet::Event */ PalletInvulnerablesEvent: { _enum: { InvulnerableAdded: { @@ -701,7 +721,7 @@ export default { }, }, }, - /** Lookup69: pallet_session::pallet::Event */ + /** Lookup72: pallet_session::pallet::Event */ PalletSessionEvent: { _enum: { NewSession: { @@ -709,7 +729,7 @@ export default { }, }, }, - /** Lookup70: pallet_pooled_staking::pallet::Event */ + /** Lookup73: pallet_pooled_staking::pallet::Event */ PalletPooledStakingEvent: { _enum: { UpdatedCandidatePosition: { @@ -804,11 +824,11 @@ export default { }, }, }, - /** Lookup72: pallet_pooled_staking::pallet::TargetPool */ + /** Lookup75: pallet_pooled_staking::pallet::TargetPool */ PalletPooledStakingTargetPool: { _enum: ["AutoCompounding", "ManualRewards"], }, - /** Lookup73: pallet_inflation_rewards::pallet::Event */ + /** Lookup76: pallet_inflation_rewards::pallet::Event */ PalletInflationRewardsEvent: { _enum: { RewardedOrchestrator: { @@ -822,7 +842,7 @@ export default { }, }, }, - /** Lookup74: pallet_treasury::pallet::Event */ + /** Lookup77: pallet_treasury::pallet::Event */ PalletTreasuryEvent: { _enum: { Spending: { @@ -875,7 +895,7 @@ export default { }, }, }, - /** Lookup75: cumulus_pallet_xcmp_queue::pallet::Event */ + /** Lookup78: cumulus_pallet_xcmp_queue::pallet::Event */ CumulusPalletXcmpQueueEvent: { _enum: { XcmpMessageSent: { @@ -883,7 +903,7 @@ export default { }, }, }, - /** Lookup76: cumulus_pallet_xcm::pallet::Event */ + /** Lookup79: cumulus_pallet_xcm::pallet::Event */ CumulusPalletXcmEvent: { _enum: { InvalidFormat: "[u8;32]", @@ -891,7 +911,7 @@ export default { ExecutedDownward: "([u8;32],StagingXcmV4TraitsOutcome)", }, }, - /** Lookup77: staging_xcm::v4::traits::Outcome */ + /** Lookup80: staging_xcm::v4::traits::Outcome */ StagingXcmV4TraitsOutcome: { _enum: { Complete: { @@ -906,7 +926,7 @@ export default { }, }, }, - /** Lookup78: xcm::v3::traits::Error */ + /** Lookup81: xcm::v3::traits::Error */ XcmV3TraitsError: { _enum: { Overflow: "Null", @@ -951,7 +971,7 @@ export default { ExceedsStackLimit: "Null", }, }, - /** Lookup79: pallet_xcm::pallet::Event */ + /** Lookup82: pallet_xcm::pallet::Event */ PalletXcmEvent: { _enum: { Attempted: { @@ -1074,26 +1094,26 @@ export default { }, }, }, - /** Lookup80: staging_xcm::v4::location::Location */ + /** Lookup83: staging_xcm::v4::location::Location */ StagingXcmV4Location: { parents: "u8", interior: "StagingXcmV4Junctions", }, - /** Lookup81: staging_xcm::v4::junctions::Junctions */ + /** Lookup84: staging_xcm::v4::junctions::Junctions */ StagingXcmV4Junctions: { _enum: { Here: "Null", - X1: "[Lookup83;1]", - X2: "[Lookup83;2]", - X3: "[Lookup83;3]", - X4: "[Lookup83;4]", - X5: "[Lookup83;5]", - X6: "[Lookup83;6]", - X7: "[Lookup83;7]", - X8: "[Lookup83;8]", + X1: "[Lookup86;1]", + X2: "[Lookup86;2]", + X3: "[Lookup86;3]", + X4: "[Lookup86;4]", + X5: "[Lookup86;5]", + X6: "[Lookup86;6]", + X7: "[Lookup86;7]", + X8: "[Lookup86;8]", }, }, - /** Lookup83: staging_xcm::v4::junction::Junction */ + /** Lookup86: staging_xcm::v4::junction::Junction */ StagingXcmV4Junction: { _enum: { Parachain: "Compact", @@ -1123,7 +1143,7 @@ export default { GlobalConsensus: "StagingXcmV4JunctionNetworkId", }, }, - /** Lookup86: staging_xcm::v4::junction::NetworkId */ + /** Lookup89: staging_xcm::v4::junction::NetworkId */ StagingXcmV4JunctionNetworkId: { _enum: { ByGenesis: "[u8;32]", @@ -1144,7 +1164,7 @@ export default { PolkadotBulletin: "Null", }, }, - /** Lookup89: xcm::v3::junction::BodyId */ + /** Lookup92: xcm::v3::junction::BodyId */ XcmV3JunctionBodyId: { _enum: { Unit: "Null", @@ -1159,7 +1179,7 @@ export default { Treasury: "Null", }, }, - /** Lookup90: xcm::v3::junction::BodyPart */ + /** Lookup93: xcm::v3::junction::BodyPart */ XcmV3JunctionBodyPart: { _enum: { Voice: "Null", @@ -1180,9 +1200,9 @@ export default { }, }, }, - /** Lookup98: staging_xcm::v4::Xcm */ + /** Lookup101: staging_xcm::v4::Xcm */ StagingXcmV4Xcm: "Vec", - /** Lookup100: staging_xcm::v4::Instruction */ + /** Lookup103: staging_xcm::v4::Instruction */ StagingXcmV4Instruction: { _enum: { WithdrawAsset: "StagingXcmV4AssetAssets", @@ -1322,23 +1342,23 @@ export default { }, }, }, - /** Lookup101: staging_xcm::v4::asset::Assets */ + /** Lookup104: staging_xcm::v4::asset::Assets */ StagingXcmV4AssetAssets: "Vec", - /** Lookup103: staging_xcm::v4::asset::Asset */ + /** Lookup106: staging_xcm::v4::asset::Asset */ StagingXcmV4Asset: { id: "StagingXcmV4AssetAssetId", fun: "StagingXcmV4AssetFungibility", }, - /** Lookup104: staging_xcm::v4::asset::AssetId */ + /** Lookup107: staging_xcm::v4::asset::AssetId */ StagingXcmV4AssetAssetId: "StagingXcmV4Location", - /** Lookup105: staging_xcm::v4::asset::Fungibility */ + /** Lookup108: staging_xcm::v4::asset::Fungibility */ StagingXcmV4AssetFungibility: { _enum: { Fungible: "Compact", NonFungible: "StagingXcmV4AssetAssetInstance", }, }, - /** Lookup106: staging_xcm::v4::asset::AssetInstance */ + /** Lookup109: staging_xcm::v4::asset::AssetInstance */ StagingXcmV4AssetAssetInstance: { _enum: { Undefined: "Null", @@ -1349,7 +1369,7 @@ export default { Array32: "[u8;32]", }, }, - /** Lookup109: staging_xcm::v4::Response */ + /** Lookup112: staging_xcm::v4::Response */ StagingXcmV4Response: { _enum: { Null: "Null", @@ -1360,7 +1380,7 @@ export default { DispatchResult: "XcmV3MaybeErrorCode", }, }, - /** Lookup113: staging_xcm::v4::PalletInfo */ + /** Lookup116: staging_xcm::v4::PalletInfo */ StagingXcmV4PalletInfo: { index: "Compact", name: "Bytes", @@ -1369,7 +1389,7 @@ export default { minor: "Compact", patch: "Compact", }, - /** Lookup116: xcm::v3::MaybeErrorCode */ + /** Lookup119: xcm::v3::MaybeErrorCode */ XcmV3MaybeErrorCode: { _enum: { Success: "Null", @@ -1377,28 +1397,28 @@ export default { TruncatedError: "Bytes", }, }, - /** Lookup119: xcm::v3::OriginKind */ + /** Lookup122: xcm::v3::OriginKind */ XcmV3OriginKind: { _enum: ["Native", "SovereignAccount", "Superuser", "Xcm"], }, - /** Lookup120: xcm::double_encoded::DoubleEncoded */ + /** Lookup123: xcm::double_encoded::DoubleEncoded */ XcmDoubleEncoded: { encoded: "Bytes", }, - /** Lookup121: staging_xcm::v4::QueryResponseInfo */ + /** Lookup124: staging_xcm::v4::QueryResponseInfo */ StagingXcmV4QueryResponseInfo: { destination: "StagingXcmV4Location", queryId: "Compact", maxWeight: "SpWeightsWeightV2Weight", }, - /** Lookup122: staging_xcm::v4::asset::AssetFilter */ + /** Lookup125: staging_xcm::v4::asset::AssetFilter */ StagingXcmV4AssetAssetFilter: { _enum: { Definite: "StagingXcmV4AssetAssets", Wild: "StagingXcmV4AssetWildAsset", }, }, - /** Lookup123: staging_xcm::v4::asset::WildAsset */ + /** Lookup126: staging_xcm::v4::asset::WildAsset */ StagingXcmV4AssetWildAsset: { _enum: { All: "Null", @@ -1414,18 +1434,18 @@ export default { }, }, }, - /** Lookup124: staging_xcm::v4::asset::WildFungibility */ + /** Lookup127: staging_xcm::v4::asset::WildFungibility */ StagingXcmV4AssetWildFungibility: { _enum: ["Fungible", "NonFungible"], }, - /** Lookup125: xcm::v3::WeightLimit */ + /** Lookup128: xcm::v3::WeightLimit */ XcmV3WeightLimit: { _enum: { Unlimited: "Null", Limited: "SpWeightsWeightV2Weight", }, }, - /** Lookup126: xcm::VersionedAssets */ + /** Lookup129: xcm::VersionedAssets */ XcmVersionedAssets: { _enum: { __Unused0: "Null", @@ -1435,26 +1455,26 @@ export default { V4: "StagingXcmV4AssetAssets", }, }, - /** Lookup127: xcm::v2::multiasset::MultiAssets */ + /** Lookup130: xcm::v2::multiasset::MultiAssets */ XcmV2MultiassetMultiAssets: "Vec", - /** Lookup129: xcm::v2::multiasset::MultiAsset */ + /** Lookup132: xcm::v2::multiasset::MultiAsset */ XcmV2MultiAsset: { id: "XcmV2MultiassetAssetId", fun: "XcmV2MultiassetFungibility", }, - /** Lookup130: xcm::v2::multiasset::AssetId */ + /** Lookup133: xcm::v2::multiasset::AssetId */ XcmV2MultiassetAssetId: { _enum: { Concrete: "XcmV2MultiLocation", Abstract: "Bytes", }, }, - /** Lookup131: xcm::v2::multilocation::MultiLocation */ + /** Lookup134: xcm::v2::multilocation::MultiLocation */ XcmV2MultiLocation: { parents: "u8", interior: "XcmV2MultilocationJunctions", }, - /** Lookup132: xcm::v2::multilocation::Junctions */ + /** Lookup135: xcm::v2::multilocation::Junctions */ XcmV2MultilocationJunctions: { _enum: { Here: "Null", @@ -1468,7 +1488,7 @@ export default { X8: "(XcmV2Junction,XcmV2Junction,XcmV2Junction,XcmV2Junction,XcmV2Junction,XcmV2Junction,XcmV2Junction,XcmV2Junction)", }, }, - /** Lookup133: xcm::v2::junction::Junction */ + /** Lookup136: xcm::v2::junction::Junction */ XcmV2Junction: { _enum: { Parachain: "Compact", @@ -1494,7 +1514,7 @@ export default { }, }, }, - /** Lookup134: xcm::v2::NetworkId */ + /** Lookup137: xcm::v2::NetworkId */ XcmV2NetworkId: { _enum: { Any: "Null", @@ -1503,7 +1523,7 @@ export default { Kusama: "Null", }, }, - /** Lookup136: xcm::v2::BodyId */ + /** Lookup139: xcm::v2::BodyId */ XcmV2BodyId: { _enum: { Unit: "Null", @@ -1518,7 +1538,7 @@ export default { Treasury: "Null", }, }, - /** Lookup137: xcm::v2::BodyPart */ + /** Lookup140: xcm::v2::BodyPart */ XcmV2BodyPart: { _enum: { Voice: "Null", @@ -1539,14 +1559,14 @@ export default { }, }, }, - /** Lookup138: xcm::v2::multiasset::Fungibility */ + /** Lookup141: xcm::v2::multiasset::Fungibility */ XcmV2MultiassetFungibility: { _enum: { Fungible: "Compact", NonFungible: "XcmV2MultiassetAssetInstance", }, }, - /** Lookup139: xcm::v2::multiasset::AssetInstance */ + /** Lookup142: xcm::v2::multiasset::AssetInstance */ XcmV2MultiassetAssetInstance: { _enum: { Undefined: "Null", @@ -1558,26 +1578,26 @@ export default { Blob: "Bytes", }, }, - /** Lookup140: xcm::v3::multiasset::MultiAssets */ + /** Lookup143: xcm::v3::multiasset::MultiAssets */ XcmV3MultiassetMultiAssets: "Vec", - /** Lookup142: xcm::v3::multiasset::MultiAsset */ + /** Lookup145: xcm::v3::multiasset::MultiAsset */ XcmV3MultiAsset: { id: "XcmV3MultiassetAssetId", fun: "XcmV3MultiassetFungibility", }, - /** Lookup143: xcm::v3::multiasset::AssetId */ + /** Lookup146: xcm::v3::multiasset::AssetId */ XcmV3MultiassetAssetId: { _enum: { Concrete: "StagingXcmV3MultiLocation", Abstract: "[u8;32]", }, }, - /** Lookup144: staging_xcm::v3::multilocation::MultiLocation */ + /** Lookup147: staging_xcm::v3::multilocation::MultiLocation */ StagingXcmV3MultiLocation: { parents: "u8", interior: "XcmV3Junctions", }, - /** Lookup145: xcm::v3::junctions::Junctions */ + /** Lookup148: xcm::v3::junctions::Junctions */ XcmV3Junctions: { _enum: { Here: "Null", @@ -1591,7 +1611,7 @@ export default { X8: "(XcmV3Junction,XcmV3Junction,XcmV3Junction,XcmV3Junction,XcmV3Junction,XcmV3Junction,XcmV3Junction,XcmV3Junction)", }, }, - /** Lookup146: xcm::v3::junction::Junction */ + /** Lookup149: xcm::v3::junction::Junction */ XcmV3Junction: { _enum: { Parachain: "Compact", @@ -1621,7 +1641,7 @@ export default { GlobalConsensus: "XcmV3JunctionNetworkId", }, }, - /** Lookup148: xcm::v3::junction::NetworkId */ + /** Lookup151: xcm::v3::junction::NetworkId */ XcmV3JunctionNetworkId: { _enum: { ByGenesis: "[u8;32]", @@ -1642,14 +1662,14 @@ export default { PolkadotBulletin: "Null", }, }, - /** Lookup149: xcm::v3::multiasset::Fungibility */ + /** Lookup152: xcm::v3::multiasset::Fungibility */ XcmV3MultiassetFungibility: { _enum: { Fungible: "Compact", NonFungible: "XcmV3MultiassetAssetInstance", }, }, - /** Lookup150: xcm::v3::multiasset::AssetInstance */ + /** Lookup153: xcm::v3::multiasset::AssetInstance */ XcmV3MultiassetAssetInstance: { _enum: { Undefined: "Null", @@ -1660,7 +1680,7 @@ export default { Array32: "[u8;32]", }, }, - /** Lookup151: xcm::VersionedLocation */ + /** Lookup154: xcm::VersionedLocation */ XcmVersionedLocation: { _enum: { __Unused0: "Null", @@ -1670,7 +1690,7 @@ export default { V4: "StagingXcmV4Location", }, }, - /** Lookup152: pallet_assets::pallet::Event */ + /** Lookup155: pallet_assets::pallet::Event */ PalletAssetsEvent: { _enum: { Created: { @@ -1794,7 +1814,7 @@ export default { }, }, }, - /** Lookup153: pallet_foreign_asset_creator::pallet::Event */ + /** Lookup156: pallet_foreign_asset_creator::pallet::Event */ PalletForeignAssetCreatorEvent: { _enum: { ForeignAssetCreated: { @@ -1815,7 +1835,7 @@ export default { }, }, }, - /** Lookup154: pallet_asset_rate::pallet::Event */ + /** Lookup157: pallet_asset_rate::pallet::Event */ PalletAssetRateEvent: { _enum: { AssetRateCreated: { @@ -1835,7 +1855,7 @@ export default { }, }, }, - /** Lookup156: pallet_message_queue::pallet::Event */ + /** Lookup159: pallet_message_queue::pallet::Event */ PalletMessageQueueEvent: { _enum: { ProcessingFailed: { @@ -1861,7 +1881,7 @@ export default { }, }, }, - /** Lookup157: cumulus_primitives_core::AggregateMessageOrigin */ + /** Lookup160: cumulus_primitives_core::AggregateMessageOrigin */ CumulusPrimitivesCoreAggregateMessageOrigin: { _enum: { Here: "Null", @@ -1869,7 +1889,7 @@ export default { Sibling: "u32", }, }, - /** Lookup158: frame_support::traits::messages::ProcessMessageError */ + /** Lookup161: frame_support::traits::messages::ProcessMessageError */ FrameSupportMessagesProcessMessageError: { _enum: { BadFormat: "Null", @@ -1880,7 +1900,7 @@ export default { StackLimitReached: "Null", }, }, - /** Lookup159: pallet_xcm_core_buyer::pallet::Event */ + /** Lookup162: pallet_xcm_core_buyer::pallet::Event */ PalletXcmCoreBuyerEvent: { _enum: { BuyCoreXcmSent: { @@ -1899,11 +1919,11 @@ export default { }, }, }, - /** Lookup161: pallet_root_testing::pallet::Event */ + /** Lookup164: pallet_root_testing::pallet::Event */ PalletRootTestingEvent: { _enum: ["DefensiveTestCall"], }, - /** Lookup162: frame_system::Phase */ + /** Lookup165: frame_system::Phase */ FrameSystemPhase: { _enum: { ApplyExtrinsic: "u32", @@ -1911,17 +1931,17 @@ export default { Initialization: "Null", }, }, - /** Lookup166: frame_system::LastRuntimeUpgradeInfo */ + /** Lookup169: frame_system::LastRuntimeUpgradeInfo */ FrameSystemLastRuntimeUpgradeInfo: { specVersion: "Compact", specName: "Text", }, - /** Lookup168: frame_system::CodeUpgradeAuthorization */ + /** Lookup171: frame_system::CodeUpgradeAuthorization */ FrameSystemCodeUpgradeAuthorization: { codeHash: "H256", checkVersion: "bool", }, - /** Lookup169: frame_system::pallet::Call */ + /** Lookup172: frame_system::pallet::Call */ FrameSystemCall: { _enum: { remark: { @@ -1964,41 +1984,41 @@ export default { }, }, }, - /** Lookup173: frame_system::limits::BlockWeights */ + /** Lookup176: frame_system::limits::BlockWeights */ FrameSystemLimitsBlockWeights: { baseBlock: "SpWeightsWeightV2Weight", maxBlock: "SpWeightsWeightV2Weight", perClass: "FrameSupportDispatchPerDispatchClassWeightsPerClass", }, - /** Lookup174: frame_support::dispatch::PerDispatchClass */ + /** Lookup177: frame_support::dispatch::PerDispatchClass */ FrameSupportDispatchPerDispatchClassWeightsPerClass: { normal: "FrameSystemLimitsWeightsPerClass", operational: "FrameSystemLimitsWeightsPerClass", mandatory: "FrameSystemLimitsWeightsPerClass", }, - /** Lookup175: frame_system::limits::WeightsPerClass */ + /** Lookup178: frame_system::limits::WeightsPerClass */ FrameSystemLimitsWeightsPerClass: { baseExtrinsic: "SpWeightsWeightV2Weight", maxExtrinsic: "Option", maxTotal: "Option", reserved: "Option", }, - /** Lookup177: frame_system::limits::BlockLength */ + /** Lookup180: frame_system::limits::BlockLength */ FrameSystemLimitsBlockLength: { max: "FrameSupportDispatchPerDispatchClassU32", }, - /** Lookup178: frame_support::dispatch::PerDispatchClass */ + /** Lookup181: frame_support::dispatch::PerDispatchClass */ FrameSupportDispatchPerDispatchClassU32: { normal: "u32", operational: "u32", mandatory: "u32", }, - /** Lookup179: sp_weights::RuntimeDbWeight */ + /** Lookup182: sp_weights::RuntimeDbWeight */ SpWeightsRuntimeDbWeight: { read: "u64", write: "u64", }, - /** Lookup180: sp_version::RuntimeVersion */ + /** Lookup183: sp_version::RuntimeVersion */ SpVersionRuntimeVersion: { specName: "Text", implName: "Text", @@ -2009,7 +2029,7 @@ export default { transactionVersion: "u32", stateVersion: "u8", }, - /** Lookup184: frame_system::pallet::Error */ + /** Lookup187: frame_system::pallet::Error */ FrameSystemError: { _enum: [ "InvalidSpecName", @@ -2023,49 +2043,49 @@ export default { "Unauthorized", ], }, - /** Lookup186: cumulus_pallet_parachain_system::unincluded_segment::Ancestor */ + /** Lookup189: cumulus_pallet_parachain_system::unincluded_segment::Ancestor */ CumulusPalletParachainSystemUnincludedSegmentAncestor: { usedBandwidth: "CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth", paraHeadHash: "Option", consumedGoAheadSignal: "Option", }, - /** Lookup187: cumulus_pallet_parachain_system::unincluded_segment::UsedBandwidth */ + /** Lookup190: cumulus_pallet_parachain_system::unincluded_segment::UsedBandwidth */ CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth: { umpMsgCount: "u32", umpTotalBytes: "u32", hrmpOutgoing: "BTreeMap", }, - /** Lookup189: cumulus_pallet_parachain_system::unincluded_segment::HrmpChannelUpdate */ + /** Lookup192: cumulus_pallet_parachain_system::unincluded_segment::HrmpChannelUpdate */ CumulusPalletParachainSystemUnincludedSegmentHrmpChannelUpdate: { msgCount: "u32", totalBytes: "u32", }, - /** Lookup194: polkadot_primitives::v8::UpgradeGoAhead */ + /** Lookup197: polkadot_primitives::v8::UpgradeGoAhead */ PolkadotPrimitivesV8UpgradeGoAhead: { _enum: ["Abort", "GoAhead"], }, - /** Lookup195: cumulus_pallet_parachain_system::unincluded_segment::SegmentTracker */ + /** Lookup198: cumulus_pallet_parachain_system::unincluded_segment::SegmentTracker */ CumulusPalletParachainSystemUnincludedSegmentSegmentTracker: { usedBandwidth: "CumulusPalletParachainSystemUnincludedSegmentUsedBandwidth", hrmpWatermark: "Option", consumedGoAheadSignal: "Option", }, - /** Lookup196: polkadot_primitives::v8::PersistedValidationData */ + /** Lookup199: polkadot_primitives::v8::PersistedValidationData */ PolkadotPrimitivesV8PersistedValidationData: { parentHead: "Bytes", relayParentNumber: "u32", relayParentStorageRoot: "H256", maxPovSize: "u32", }, - /** Lookup199: polkadot_primitives::v8::UpgradeRestriction */ + /** Lookup202: polkadot_primitives::v8::UpgradeRestriction */ PolkadotPrimitivesV8UpgradeRestriction: { _enum: ["Present"], }, - /** Lookup200: sp_trie::storage_proof::StorageProof */ + /** Lookup203: sp_trie::storage_proof::StorageProof */ SpTrieStorageProof: { trieNodes: "BTreeSet", }, - /** Lookup202: cumulus_pallet_parachain_system::relay_state_snapshot::MessagingStateSnapshot */ + /** Lookup205: cumulus_pallet_parachain_system::relay_state_snapshot::MessagingStateSnapshot */ CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot: { dmqMqcHead: "H256", relayDispatchQueueRemainingCapacity: @@ -2073,12 +2093,12 @@ export default { ingressChannels: "Vec<(u32,PolkadotPrimitivesV8AbridgedHrmpChannel)>", egressChannels: "Vec<(u32,PolkadotPrimitivesV8AbridgedHrmpChannel)>", }, - /** Lookup203: cumulus_pallet_parachain_system::relay_state_snapshot::RelayDispatchQueueRemainingCapacity */ + /** Lookup206: cumulus_pallet_parachain_system::relay_state_snapshot::RelayDispatchQueueRemainingCapacity */ CumulusPalletParachainSystemRelayStateSnapshotRelayDispatchQueueRemainingCapacity: { remainingCount: "u32", remainingSize: "u32", }, - /** Lookup206: polkadot_primitives::v8::AbridgedHrmpChannel */ + /** Lookup209: polkadot_primitives::v8::AbridgedHrmpChannel */ PolkadotPrimitivesV8AbridgedHrmpChannel: { maxCapacity: "u32", maxTotalSize: "u32", @@ -2087,7 +2107,7 @@ export default { totalSize: "u32", mqcHead: "Option", }, - /** Lookup207: polkadot_primitives::v8::AbridgedHostConfiguration */ + /** Lookup210: polkadot_primitives::v8::AbridgedHostConfiguration */ PolkadotPrimitivesV8AbridgedHostConfiguration: { maxCodeSize: "u32", maxHeadDataSize: "u32", @@ -2100,17 +2120,17 @@ export default { validationUpgradeDelay: "u32", asyncBackingParams: "PolkadotPrimitivesV8AsyncBackingAsyncBackingParams", }, - /** Lookup208: polkadot_primitives::v8::async_backing::AsyncBackingParams */ + /** Lookup211: polkadot_primitives::v8::async_backing::AsyncBackingParams */ PolkadotPrimitivesV8AsyncBackingAsyncBackingParams: { maxCandidateDepth: "u32", allowedAncestryLen: "u32", }, - /** Lookup214: polkadot_core_primitives::OutboundHrmpMessage */ + /** Lookup217: polkadot_core_primitives::OutboundHrmpMessage */ PolkadotCorePrimitivesOutboundHrmpMessage: { recipient: "u32", data: "Bytes", }, - /** Lookup215: cumulus_pallet_parachain_system::pallet::Call */ + /** Lookup218: cumulus_pallet_parachain_system::pallet::Call */ CumulusPalletParachainSystemCall: { _enum: { set_validation_data: { @@ -2121,24 +2141,24 @@ export default { }, }, }, - /** Lookup216: cumulus_primitives_parachain_inherent::ParachainInherentData */ + /** Lookup219: cumulus_primitives_parachain_inherent::ParachainInherentData */ CumulusPrimitivesParachainInherentParachainInherentData: { validationData: "PolkadotPrimitivesV8PersistedValidationData", relayChainState: "SpTrieStorageProof", downwardMessages: "Vec", horizontalMessages: "BTreeMap>", }, - /** Lookup218: polkadot_core_primitives::InboundDownwardMessage */ + /** Lookup221: polkadot_core_primitives::InboundDownwardMessage */ PolkadotCorePrimitivesInboundDownwardMessage: { sentAt: "u32", msg: "Bytes", }, - /** Lookup221: polkadot_core_primitives::InboundHrmpMessage */ + /** Lookup224: polkadot_core_primitives::InboundHrmpMessage */ PolkadotCorePrimitivesInboundHrmpMessage: { sentAt: "u32", data: "Bytes", }, - /** Lookup224: cumulus_pallet_parachain_system::pallet::Error */ + /** Lookup227: cumulus_pallet_parachain_system::pallet::Error */ CumulusPalletParachainSystemError: { _enum: [ "OverlappingUpgrades", @@ -2151,7 +2171,7 @@ export default { "Unauthorized", ], }, - /** Lookup225: pallet_timestamp::pallet::Call */ + /** Lookup228: pallet_timestamp::pallet::Call */ PalletTimestampCall: { _enum: { set: { @@ -2159,9 +2179,9 @@ export default { }, }, }, - /** Lookup226: staging_parachain_info::pallet::Call */ + /** Lookup229: staging_parachain_info::pallet::Call */ StagingParachainInfoCall: "Null", - /** Lookup227: pallet_sudo::pallet::Call */ + /** Lookup230: pallet_sudo::pallet::Call */ PalletSudoCall: { _enum: { sudo: { @@ -2184,7 +2204,7 @@ export default { remove_key: "Null", }, }, - /** Lookup229: pallet_utility::pallet::Call */ + /** Lookup232: pallet_utility::pallet::Call */ PalletUtilityCall: { _enum: { batch: { @@ -2210,7 +2230,7 @@ export default { }, }, }, - /** Lookup231: dancebox_runtime::OriginCaller */ + /** Lookup234: dancebox_runtime::OriginCaller */ DanceboxRuntimeOriginCaller: { _enum: { system: "FrameSupportDispatchRawOrigin", @@ -2269,7 +2289,7 @@ export default { PolkadotXcm: "PalletXcmOrigin", }, }, - /** Lookup232: frame_support::dispatch::RawOrigin */ + /** Lookup235: frame_support::dispatch::RawOrigin */ FrameSupportDispatchRawOrigin: { _enum: { Root: "Null", @@ -2277,23 +2297,23 @@ export default { None: "Null", }, }, - /** Lookup233: cumulus_pallet_xcm::pallet::Origin */ + /** Lookup236: cumulus_pallet_xcm::pallet::Origin */ CumulusPalletXcmOrigin: { _enum: { Relay: "Null", SiblingParachain: "u32", }, }, - /** Lookup234: pallet_xcm::pallet::Origin */ + /** Lookup237: pallet_xcm::pallet::Origin */ PalletXcmOrigin: { _enum: { Xcm: "StagingXcmV4Location", Response: "StagingXcmV4Location", }, }, - /** Lookup235: sp_core::Void */ + /** Lookup238: sp_core::Void */ SpCoreVoid: "Null", - /** Lookup236: pallet_proxy::pallet::Call */ + /** Lookup239: pallet_proxy::pallet::Call */ PalletProxyCall: { _enum: { proxy: { @@ -2344,11 +2364,11 @@ export default { }, }, }, - /** Lookup240: pallet_maintenance_mode::pallet::Call */ + /** Lookup243: pallet_maintenance_mode::pallet::Call */ PalletMaintenanceModeCall: { _enum: ["enter_maintenance_mode", "resume_normal_operation"], }, - /** Lookup241: pallet_tx_pause::pallet::Call */ + /** Lookup244: pallet_tx_pause::pallet::Call */ PalletTxPauseCall: { _enum: { pause: { @@ -2359,7 +2379,7 @@ export default { }, }, }, - /** Lookup242: pallet_balances::pallet::Call */ + /** Lookup245: pallet_balances::pallet::Call */ PalletBalancesCall: { _enum: { transfer_allow_death: { @@ -2402,11 +2422,11 @@ export default { }, }, }, - /** Lookup244: pallet_balances::types::AdjustmentDirection */ + /** Lookup247: pallet_balances::types::AdjustmentDirection */ PalletBalancesAdjustmentDirection: { _enum: ["Increase", "Decrease"], }, - /** Lookup245: pallet_stream_payment::pallet::Call */ + /** Lookup248: pallet_stream_payment::pallet::Call */ PalletStreamPaymentCall: { _enum: { open_stream: { @@ -2441,7 +2461,7 @@ export default { }, }, }, - /** Lookup246: pallet_stream_payment::pallet::ChangeKind