Skip to content

Commit

Permalink
Add pallet services payment to runtime (#314)
Browse files Browse the repository at this point in the history
* Add services payment pallet to runtime, using mock impl

* Burn one credit when a container chain has a new highest block

Will always burn at most 1 credit per tanssi block, even if the
container chain has created more than 1 block in that time.

* Do not assign collators to container chains with no credits

* Add migration that gives credits to existing parachains

* Set MaxCreditsStored to 60 days worth of blocks

* Add benchmarks to pallet_services_payment

* Add set_credits extrinsic for root, and unit tests

* Fix collator-assignment benchmark and weights

* Fix collator assignment new_session weight hint

* impl AuthorNotingHook for tuples
  • Loading branch information
tmpolaczyk authored Nov 15, 2023
1 parent e3cf7de commit 94cc02d
Show file tree
Hide file tree
Showing 29 changed files with 1,860 additions and 601 deletions.
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pallet-invulnerables = { path = "pallets/invulnerables", default-features = fals
pallet-pooled-staking = { path = "pallets/pooled-staking", default-features = false }
pallet-registrar = { path = "pallets/registrar", default-features = false }
pallet-registrar-runtime-api = { path = "pallets/registrar/rpc/runtime-api", default-features = false }
pallet-services-payment = { path = "pallets/services-payment", default-features = false }

ccp-authorities-noting-inherent = { path = "container-chains/primitives/authorities-noting-inherent", default-features = false }
ccp-xcm = { path = "container-chains/primitives/xcm", default-features = false }
Expand Down Expand Up @@ -226,6 +227,7 @@ log = { version = "0.4.17", default-features = false }
serde = { version = "1.0.152", default-features = false }
smallvec = "1.10.0"
rand_chacha = { version = "0.3.1", default-features = false }
impl-trait-for-tuples = "0.2.2"

# General (client)
async-io = "1.3"
Expand Down
43 changes: 24 additions & 19 deletions node/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use {
cumulus_primitives_core::ParaId,
dancebox_runtime::{
prod_or_fast, AccountId, MaintenanceModeConfig, MigrationsConfig, PolkadotXcmConfig,
RegistrarConfig, Signature, SudoConfig,
RegistrarConfig, ServicesPaymentConfig, Signature, SudoConfig,
},
nimbus_primitives::NimbusId,
pallet_configuration::HostConfiguration,
Expand Down Expand Up @@ -293,6 +293,27 @@ fn testnet_genesis(
mock_container_chains: &[ParaId],
configuration: pallet_configuration::GenesisConfig<dancebox_runtime::Runtime>,
) -> dancebox_runtime::RuntimeGenesisConfig {
let para_ids: Vec<_> = container_chains
.iter()
.map(|x| {
container_chain_genesis_data_from_path(x).unwrap_or_else(|e| {
panic!(
"Failed to build genesis data for container chain {:?}: {}",
x, e
)
})
})
.chain(
mock_container_chains
.iter()
.map(|x| (*x, mock_container_chain_genesis_data(*x), vec![])),
)
.collect();
// Assign 1000 block credits to all container chains registered in genesis
let para_id_credits: Vec<_> = para_ids
.iter()
.map(|(para_id, _genesis_data, _boot_nodes)| (*para_id, 1000))
.collect();
let accounts_with_ed = vec![
dancebox_runtime::StakingAccount::get(),
dancebox_runtime::ParachainBondAccount::get(),
Expand Down Expand Up @@ -339,24 +360,8 @@ fn testnet_genesis(
},
parachain_system: Default::default(),
configuration,
registrar: RegistrarConfig {
para_ids: container_chains
.iter()
.map(|x| {
container_chain_genesis_data_from_path(x).unwrap_or_else(|e| {
panic!(
"Failed to build genesis data for container chain {:?}: {}",
x, e
)
})
})
.chain(
mock_container_chains
.iter()
.map(|x| (*x, mock_container_chain_genesis_data(*x), vec![])),
)
.collect(),
},
registrar: RegistrarConfig { para_ids },
services_payment: ServicesPaymentConfig { para_id_credits },
sudo: SudoConfig {
key: Some(root_key),
},
Expand Down
1 change: 1 addition & 0 deletions pallets/collator-assignment/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ mod benchmarks {
let container_chains: Vec<_> = (0..y).map(|para_id| ParaId::from(para_id)).collect();
let session_index = 0u32.into();
T::ContainerChains::set_session_container_chains(session_index, &container_chains);
T::RemoveParaIdsWithNoCredits::make_valid_para_ids(&container_chains);

// Assign random collators to test worst case: when collators need to be checked against existing collators
// In this case all of the old collators don't exist anymore
Expand Down
16 changes: 13 additions & 3 deletions pallets/collator-assignment/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ use {
tp_collator_assignment::AssignedCollators,
tp_traits::{
GetContainerChainAuthor, GetHostConfiguration, GetSessionContainerChains, ParaId,
RemoveInvulnerables, ShouldRotateAllCollators, Slot,
RemoveInvulnerables, RemoveParaIdsWithNoCredits, ShouldRotateAllCollators, Slot,
},
};

Expand Down Expand Up @@ -97,6 +97,7 @@ pub mod pallet {
type ShouldRotateAllCollators: ShouldRotateAllCollators<Self::SessionIndex>;
type GetRandomnessForNextBlock: GetRandomnessForNextBlock<BlockNumberFor<Self>>;
type RemoveInvulnerables: RemoveInvulnerables<Self::AccountId>;
type RemoveParaIdsWithNoCredits: RemoveParaIdsWithNoCredits;
/// The weight information of this pallet.
type WeightInfo: WeightInfo;
}
Expand Down Expand Up @@ -145,6 +146,8 @@ pub mod pallet {
pub active_assignment: AssignedCollators<T::AccountId>,
/// Next session active assignment.
pub next_assignment: AssignedCollators<T::AccountId>,
/// Total number of registered parachains before filtering them out, used as a weight hint
pub num_total_registered_paras: u32,
}

impl<T: Config> Pallet<T> {
Expand All @@ -161,6 +164,11 @@ pub mod pallet {
// We get the containerChains that we will have at the target session
let mut container_chain_ids =
T::ContainerChains::session_container_chains(target_session_index);
let num_total_registered_paras = container_chain_ids.len() as u32;
// Remove the containerChains that do not have enough credits for block production
T::RemoveParaIdsWithNoCredits::remove_para_ids_with_no_credits(
&mut container_chain_ids,
);

// If the random_seed is all zeros, we don't shuffle the list of collators nor the list
// of container chains.
Expand Down Expand Up @@ -248,12 +256,14 @@ pub mod pallet {
return SessionChangeOutcome {
active_assignment: new_assigned.clone(),
next_assignment: new_assigned,
num_total_registered_paras,
};
}

SessionChangeOutcome {
active_assignment: old_assigned,
next_assignment: new_assigned,
num_total_registered_paras,
}
}

Expand Down Expand Up @@ -400,10 +410,10 @@ pub mod pallet {
let random_seed = Randomness::<T>::take();
let num_collators = collators.len();
let assigned_collators = Self::assign_collators(session_index, random_seed, collators);
let num_parachains = assigned_collators.next_assignment.container_chains.len();
let num_total_registered_paras = assigned_collators.num_total_registered_paras;

frame_system::Pallet::<T>::register_extra_weight_unchecked(
T::WeightInfo::new_session(num_collators as u32, num_parachains as u32),
T::WeightInfo::new_session(num_collators as u32, num_total_registered_paras),
DispatchClass::Mandatory,
);

Expand Down
19 changes: 18 additions & 1 deletion pallets/collator-assignment/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use {
traits::{BlakeTwo256, IdentityLookup},
BuildStorage,
},
tp_traits::{ParaId, RemoveInvulnerables},
tp_traits::{ParaId, RemoveInvulnerables, RemoveParaIdsWithNoCredits},
};

type Block = frame_system::mocking::MockBlock<Test>;
Expand Down Expand Up @@ -193,6 +193,7 @@ impl pallet_collator_assignment::Config for Test {
type ShouldRotateAllCollators = RotateCollatorsEveryNSessions<CollatorRotationSessionPeriod>;
type GetRandomnessForNextBlock = MockGetRandomnessForNextBlock;
type RemoveInvulnerables = RemoveAccountIdsAbove100;
type RemoveParaIdsWithNoCredits = RemoveParaIdsAbove5000;
type WeightInfo = ();
}

Expand Down Expand Up @@ -247,3 +248,19 @@ impl RemoveInvulnerables<u64> for RemoveAccountIdsAbove100 {
invulnerables
}
}

/// Any ParaId >= 5000 will be considered to not have enough credits
pub struct RemoveParaIdsAbove5000;

impl RemoveParaIdsWithNoCredits for RemoveParaIdsAbove5000 {
fn remove_para_ids_with_no_credits(para_ids: &mut Vec<ParaId>) {
para_ids.retain(|para_id| *para_id <= ParaId::from(5000));
}

#[cfg(feature = "runtime-benchmarks")]
fn make_valid_para_ids(para_ids: &[ParaId]) {
for para_id in para_ids {
assert!(para_id > 5000.into(), "{}", para_id);
}
}
}
116 changes: 67 additions & 49 deletions pallets/collator-assignment/src/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
//! Autogenerated weights for pallet_collator_assignment
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-09-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! DATE: 2023-11-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `tomasz-XPS-15-9520`, CPU: `12th Gen Intel(R) Core(TM) i7-12700H`
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024
//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024

// Executed Command:
// ./target/release/tanssi-node
Expand All @@ -32,7 +32,7 @@
// --pallet
// pallet_collator_assignment
// --extrinsic
// new_session
// *
// --steps
// 50
// --repeat
Expand All @@ -58,64 +58,82 @@ pub trait WeightInfo {
/// Weights for pallet_collator_assignment using the Substrate node and recommended hardware.
pub struct SubstrateWeight<T>(PhantomData<T>);
impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
/// Storage: Registrar PendingParaIds (r:1 w:0)
/// Proof Skipped: Registrar PendingParaIds (max_values: Some(1), max_size: None, mode: Measured)
/// Storage: Registrar RegisteredParaIds (r:1 w:0)
/// Proof Skipped: Registrar RegisteredParaIds (max_values: Some(1), max_size: None, mode: Measured)
/// Storage: CollatorAssignment PendingCollatorContainerChain (r:1 w:1)
/// Proof Skipped: CollatorAssignment PendingCollatorContainerChain (max_values: Some(1), max_size: None, mode: Measured)
/// Storage: Configuration PendingConfigs (r:1 w:0)
/// Proof Skipped: Configuration PendingConfigs (max_values: Some(1), max_size: None, mode: Measured)
/// Storage: Configuration ActiveConfig (r:1 w:0)
/// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured)
/// Storage: CollatorAssignment CollatorContainerChain (r:0 w:1)
/// Proof Skipped: CollatorAssignment CollatorContainerChain (max_values: Some(1), max_size: None, mode: Measured)
/// Storage: `CollatorAssignment::Randomness` (r:1 w:1)
/// Proof: `CollatorAssignment::Randomness` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `Registrar::PendingParaIds` (r:1 w:0)
/// Proof: `Registrar::PendingParaIds` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `Registrar::RegisteredParaIds` (r:1 w:0)
/// Proof: `Registrar::RegisteredParaIds` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ServicesPayment::BlockProductionCredits` (r:20 w:0)
/// Proof: `ServicesPayment::BlockProductionCredits` (`max_values`: None, `max_size`: Some(24), added: 2499, mode: `MaxEncodedLen`)
/// Storage: `CollatorAssignment::PendingCollatorContainerChain` (r:1 w:1)
/// Proof: `CollatorAssignment::PendingCollatorContainerChain` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `Configuration::ActiveConfig` (r:1 w:0)
/// Proof: `Configuration::ActiveConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `Configuration::PendingConfigs` (r:1 w:0)
/// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `Invulnerables::Invulnerables` (r:1 w:0)
/// Proof: `Invulnerables::Invulnerables` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`)
/// Storage: `System::BlockWeight` (r:1 w:1)
/// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`)
/// Storage: `CollatorAssignment::CollatorContainerChain` (r:0 w:1)
/// Proof: `CollatorAssignment::CollatorContainerChain` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// The range of component `x` is `[1, 200]`.
/// The range of component `y` is `[1, 20]`.
fn new_session(x: u32, y: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `427 + y * (4 ±0)`
// Estimated: `1913 + y * (4 ±0)`
// Minimum execution time: 25_688_000 picoseconds.
Weight::from_parts(19_486_973, 1913)
// Standard Error: 874
.saturating_add(Weight::from_parts(39_428, 0).saturating_mul(x.into()))
// Standard Error: 8_900
.saturating_add(Weight::from_parts(706_995, 0).saturating_mul(y.into()))
.saturating_add(T::DbWeight::get().reads(5_u64))
.saturating_add(T::DbWeight::get().writes(2_u64))
.saturating_add(Weight::from_parts(0, 4).saturating_mul(y.into()))
// Measured: `766 + y * (32 ±0)`
// Estimated: `4687 + y * (2499 ±0)`
// Minimum execution time: 56_626_000 picoseconds.
Weight::from_parts(41_872_969, 4687)
// Standard Error: 1_156
.saturating_add(Weight::from_parts(76_061, 0).saturating_mul(x.into()))
// Standard Error: 11_776
.saturating_add(Weight::from_parts(2_758_758, 0).saturating_mul(y.into()))
.saturating_add(T::DbWeight::get().reads(8_u64))
.saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(y.into())))
.saturating_add(T::DbWeight::get().writes(4_u64))
.saturating_add(Weight::from_parts(0, 2499).saturating_mul(y.into()))
}
}

// For backwards compatibility and tests
impl WeightInfo for () {
/// Storage: Registrar PendingParaIds (r:1 w:0)
/// Proof Skipped: Registrar PendingParaIds (max_values: Some(1), max_size: None, mode: Measured)
/// Storage: Registrar RegisteredParaIds (r:1 w:0)
/// Proof Skipped: Registrar RegisteredParaIds (max_values: Some(1), max_size: None, mode: Measured)
/// Storage: CollatorAssignment PendingCollatorContainerChain (r:1 w:1)
/// Proof Skipped: CollatorAssignment PendingCollatorContainerChain (max_values: Some(1), max_size: None, mode: Measured)
/// Storage: Configuration PendingConfigs (r:1 w:0)
/// Proof Skipped: Configuration PendingConfigs (max_values: Some(1), max_size: None, mode: Measured)
/// Storage: Configuration ActiveConfig (r:1 w:0)
/// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured)
/// Storage: CollatorAssignment CollatorContainerChain (r:0 w:1)
/// Proof Skipped: CollatorAssignment CollatorContainerChain (max_values: Some(1), max_size: None, mode: Measured)
/// Storage: `CollatorAssignment::Randomness` (r:1 w:1)
/// Proof: `CollatorAssignment::Randomness` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `Registrar::PendingParaIds` (r:1 w:0)
/// Proof: `Registrar::PendingParaIds` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `Registrar::RegisteredParaIds` (r:1 w:0)
/// Proof: `Registrar::RegisteredParaIds` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ServicesPayment::BlockProductionCredits` (r:20 w:0)
/// Proof: `ServicesPayment::BlockProductionCredits` (`max_values`: None, `max_size`: Some(24), added: 2499, mode: `MaxEncodedLen`)
/// Storage: `CollatorAssignment::PendingCollatorContainerChain` (r:1 w:1)
/// Proof: `CollatorAssignment::PendingCollatorContainerChain` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `Configuration::ActiveConfig` (r:1 w:0)
/// Proof: `Configuration::ActiveConfig` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `Configuration::PendingConfigs` (r:1 w:0)
/// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `Invulnerables::Invulnerables` (r:1 w:0)
/// Proof: `Invulnerables::Invulnerables` (`max_values`: Some(1), `max_size`: Some(3202), added: 3697, mode: `MaxEncodedLen`)
/// Storage: `System::BlockWeight` (r:1 w:1)
/// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`)
/// Storage: `CollatorAssignment::CollatorContainerChain` (r:0 w:1)
/// Proof: `CollatorAssignment::CollatorContainerChain` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// The range of component `x` is `[1, 200]`.
/// The range of component `y` is `[1, 20]`.
fn new_session(x: u32, y: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `427 + y * (4 ±0)`
// Estimated: `1913 + y * (4 ±0)`
// Minimum execution time: 25_688_000 picoseconds.
Weight::from_parts(19_486_973, 1913)
// Standard Error: 874
.saturating_add(Weight::from_parts(39_428, 0).saturating_mul(x.into()))
// Standard Error: 8_900
.saturating_add(Weight::from_parts(706_995, 0).saturating_mul(y.into()))
.saturating_add(RocksDbWeight::get().reads(5_u64))
.saturating_add(RocksDbWeight::get().writes(2_u64))
.saturating_add(Weight::from_parts(0, 4).saturating_mul(y.into()))
// Measured: `766 + y * (32 ±0)`
// Estimated: `4687 + y * (2499 ±0)`
// Minimum execution time: 56_626_000 picoseconds.
Weight::from_parts(41_872_969, 4687)
// Standard Error: 1_156
.saturating_add(Weight::from_parts(76_061, 0).saturating_mul(x.into()))
// Standard Error: 11_776
.saturating_add(Weight::from_parts(2_758_758, 0).saturating_mul(y.into()))
.saturating_add(RocksDbWeight::get().reads(8_u64))
.saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(y.into())))
.saturating_add(RocksDbWeight::get().writes(4_u64))
.saturating_add(Weight::from_parts(0, 2499).saturating_mul(y.into()))
}
}
Loading

0 comments on commit 94cc02d

Please sign in to comment.