feat: initialize Kurdistan SDK - independent fork of Polkadot SDK

This commit is contained in:
2025-12-13 15:44:15 +03:00
commit e4778b4576
6838 changed files with 1847450 additions and 0 deletions
+82
View File
@@ -0,0 +1,82 @@
[package]
name = "kitchensink-runtime"
version = "3.0.0-dev"
authors.workspace = true
description = "Substrate node kitchensink runtime."
edition.workspace = true
build = "build.rs"
license = "Apache-2.0"
homepage.workspace = true
repository.workspace = true
publish = false
[lints]
workspace = true
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
# third-party dependencies
array-bytes = { workspace = true }
codec = { features = ["derive", "max-encoded-len"], workspace = true }
log = { workspace = true }
rand = { workspace = true, optional = true }
rand_pcg = { workspace = true, optional = true }
scale-info = { features = ["derive", "serde"], workspace = true }
serde_json = { features = ["alloc", "arbitrary_precision"], workspace = true }
sp-debug-derive = { workspace = true, features = ["force-debug"] }
static_assertions = { workspace = true, default-features = true }
# pallet-asset-conversion: turn on "num-traits" feature
primitive-types = { features = [
"codec",
"num-traits",
"scale-info",
], workspace = true }
pezkuwi-sdk = { features = ["runtime-full", "tuples-96"], workspace = true }
# shared code between runtime and node
node-primitives = { workspace = true }
# Example pallets that are not published:
pallet-example-mbm = { workspace = true }
pallet-example-tasks = { workspace = true }
[build-dependencies]
substrate-wasm-builder = { optional = true, workspace = true, default-features = true }
[features]
default = ["std"]
with-tracing = ["pezkuwi-sdk/with-tracing"]
std = [
"codec/std",
"log/std",
"node-primitives/std",
"pallet-example-mbm/std",
"pallet-example-tasks/std",
"pezkuwi-sdk/std",
"primitive-types/std",
"rand?/std",
"scale-info/std",
"serde_json/std",
"sp-debug-derive/std",
"substrate-wasm-builder",
]
runtime-benchmarks = [
"node-primitives/runtime-benchmarks",
"pallet-example-mbm/runtime-benchmarks",
"pallet-example-tasks/runtime-benchmarks",
"pezkuwi-sdk/runtime-benchmarks",
"rand",
"rand_pcg",
"substrate-wasm-builder?/runtime-benchmarks",
]
try-runtime = [
"pallet-example-mbm/try-runtime",
"pallet-example-tasks/try-runtime",
"pezkuwi-sdk/try-runtime",
]
experimental = ["pallet-example-tasks/experimental"]
metadata-hash = ["substrate-wasm-builder/metadata-hash"]
+31
View File
@@ -0,0 +1,31 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#[cfg(all(feature = "std", not(feature = "metadata-hash")))]
fn main() {
substrate_wasm_builder::WasmBuilder::build_using_defaults()
}
#[cfg(all(feature = "std", feature = "metadata-hash"))]
fn main() {
substrate_wasm_builder::WasmBuilder::init_with_defaults()
.enable_metadata_hash("Test", 14)
.build()
}
#[cfg(not(feature = "std"))]
fn main() {}
@@ -0,0 +1,35 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Runtime API definition for assets.
use pezkuwi_sdk::*;
use alloc::vec::Vec;
use codec::Codec;
sp_api::decl_runtime_apis! {
pub trait AssetsApi<AccountId, AssetBalance, AssetId>
where
AccountId: Codec,
AssetBalance: Codec,
AssetId: Codec,
{
/// Returns the list of `AssetId`s and corresponding balance that an `AccountId` has.
fn account_balances(account: AccountId) -> Vec<(AssetId, AssetBalance)>;
}
}
@@ -0,0 +1,77 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! A set of constant values used in substrate runtime.
/// Money matters.
pub mod currency {
use node_primitives::Balance;
pub const MILLICENTS: Balance = 1_000_000_000;
pub const CENTS: Balance = 1_000 * MILLICENTS; // assume this is worth about a cent.
pub const DOLLARS: Balance = 100 * CENTS;
pub const fn deposit(items: u32, bytes: u32) -> Balance {
items as Balance * 15 * CENTS + (bytes as Balance) * 6 * CENTS
}
}
/// Time.
pub mod time {
use node_primitives::{BlockNumber, Moment};
/// Since BABE is probabilistic this is the average expected block time that
/// we are targeting. Blocks will be produced at a minimum duration defined
/// by `SLOT_DURATION`, but some slots will not be allocated to any
/// authority and hence no block will be produced. We expect to have this
/// block time on average following the defined slot duration and the value
/// of `c` configured for BABE (where `1 - c` represents the probability of
/// a slot being empty).
/// This value is only used indirectly to define the unit constants below
/// that are expressed in blocks. The rest of the code should use
/// `SLOT_DURATION` instead (like the Timestamp pallet for calculating the
/// minimum period).
///
/// If using BABE with secondary slots (default) then all of the slots will
/// always be assigned, in which case `MILLISECS_PER_BLOCK` and
/// `SLOT_DURATION` should have the same value.
///
/// <https://research.web3.foundation/Polkadot/protocols/block-production/Babe#6-practical-results>
pub const MILLISECS_PER_BLOCK: Moment = 3000;
pub const SECS_PER_BLOCK: Moment = MILLISECS_PER_BLOCK / 1000;
// NOTE: Currently it is not possible to change the slot duration after the chain has started.
// Attempting to do so will brick block production.
pub const SLOT_DURATION: Moment = MILLISECS_PER_BLOCK;
// 1 in 4 blocks (on average, not counting collisions) will be primary BABE blocks.
pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4);
// NOTE: Currently it is not possible to change the epoch duration after the chain has started.
// Attempting to do so will brick block production.
pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 10 * MINUTES;
pub const EPOCH_DURATION_IN_SLOTS: u64 = {
const SLOT_FILL_RATE: f64 = MILLISECS_PER_BLOCK as f64 / SLOT_DURATION as f64;
(EPOCH_DURATION_IN_BLOCKS as f64 * SLOT_FILL_RATE) as u64
};
// These time units are defined in number of blocks.
pub const MINUTES: BlockNumber = 60 / (SECS_PER_BLOCK as BlockNumber);
pub const HOURS: BlockNumber = MINUTES * 60;
pub const DAYS: BlockNumber = HOURS * 24;
}
@@ -0,0 +1,222 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Genesis Presets for the Kitchensink Runtime
use pezkuwi_sdk::*;
use crate::{
constants::currency::*, frame_support::build_struct_json_patch, AccountId, AssetsConfig,
BabeConfig, Balance, BalancesConfig, ElectionsConfig, NominationPoolsConfig, ReviveConfig,
RuntimeGenesisConfig, SessionConfig, SessionKeys, SocietyConfig, StakerStatus, StakingConfig,
SudoConfig, TechnicalCommitteeConfig, BABE_GENESIS_EPOCH_CONFIG,
};
use alloc::{vec, vec::Vec};
use pallet_im_online::sr25519::AuthorityId as ImOnlineId;
use pallet_revive::is_eth_derived;
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
use sp_consensus_babe::AuthorityId as BabeId;
use sp_consensus_beefy::ecdsa_crypto::AuthorityId as BeefyId;
use sp_consensus_grandpa::AuthorityId as GrandpaId;
use sp_core::{crypto::get_public_from_string_or_panic, sr25519};
use sp_genesis_builder::PresetId;
use sp_keyring::Sr25519Keyring;
use sp_mixnet::types::AuthorityId as MixnetId;
use sp_runtime::Perbill;
pub const ENDOWMENT: Balance = 10_000_000 * DOLLARS;
pub const STASH: Balance = ENDOWMENT / 1000;
/// The staker type as supplied ot the Staking config.
pub type Staker = (AccountId, AccountId, Balance, StakerStatus<AccountId>);
/// Helper function to create RuntimeGenesisConfig json patch for testing.
pub fn kitchensink_genesis(
initial_authorities: Vec<(AccountId, AccountId, SessionKeys)>,
root_key: AccountId,
endowed_accounts: Vec<AccountId>,
stakers: Vec<Staker>,
) -> serde_json::Value {
let validator_count = initial_authorities.len() as u32;
let minimum_validator_count = validator_count;
let collective = collective(&endowed_accounts);
build_struct_json_patch!(RuntimeGenesisConfig {
balances: BalancesConfig {
balances: endowed_accounts.iter().cloned().map(|x| (x, ENDOWMENT)).collect(),
..Default::default()
},
session: SessionConfig {
keys: initial_authorities
.iter()
.map(|x| { (x.0.clone(), x.1.clone(), x.2.clone()) })
.collect(),
},
staking: StakingConfig {
validator_count,
minimum_validator_count,
invulnerables: initial_authorities
.iter()
.map(|x| x.0.clone())
.collect::<Vec<_>>()
.try_into()
.expect("Too many invulnerable validators: upper limit is MaxInvulnerables from pallet staking config"),
slash_reward_fraction: Perbill::from_percent(10),
stakers,
},
elections: ElectionsConfig {
members: collective.iter().cloned().map(|member| (member, STASH)).collect(),
},
technical_committee: TechnicalCommitteeConfig { members: collective },
sudo: SudoConfig { key: Some(root_key) },
babe: BabeConfig { epoch_config: BABE_GENESIS_EPOCH_CONFIG },
society: SocietyConfig { pot: 0 },
assets: AssetsConfig {
// This asset is used by the NIS pallet as counterpart currency.
assets: vec![(9, Sr25519Keyring::Alice.to_account_id(), true, 1)],
..Default::default()
},
nomination_pools: NominationPoolsConfig {
min_create_bond: 10 * DOLLARS,
min_join_bond: 1 * DOLLARS,
},
revive: ReviveConfig {
mapped_accounts: endowed_accounts.iter().filter(|x| ! is_eth_derived(x)).cloned().collect(),
},
})
}
/// Provides the JSON representation of predefined genesis config for given `id`.
pub fn get_preset(id: &PresetId) -> Option<Vec<u8>> {
// Note: Can't use `Sr25519Keyring::Alice.to_seed()` because the seed comes with `//`.
let (alice_stash, alice, alice_session_keys) = authority_keys_from_seed("Alice");
let (bob_stash, _bob, bob_session_keys) = authority_keys_from_seed("Bob");
let endowed = well_known_including_eth_accounts();
let patch = match id.as_ref() {
sp_genesis_builder::DEV_RUNTIME_PRESET => kitchensink_genesis(
// Use stash as controller account, otherwise grandpa can't load the authority set at
// genesis.
vec![(alice_stash.clone(), alice_stash.clone(), alice_session_keys)],
alice.clone(),
endowed,
vec![validator(alice_stash.clone())],
),
sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET => kitchensink_genesis(
vec![
// Use stash as controller account, otherwise grandpa can't load the authority set
// at genesis.
(alice_stash.clone(), alice_stash.clone(), alice_session_keys),
(bob_stash.clone(), bob_stash.clone(), bob_session_keys),
],
alice,
endowed,
vec![validator(alice_stash), validator(bob_stash)],
),
_ => return None,
};
Some(
serde_json::to_string(&patch)
.expect("serialization to json is expected to work. qed.")
.into_bytes(),
)
}
/// List of supported presets.
pub fn preset_names() -> Vec<PresetId> {
vec![
PresetId::from(sp_genesis_builder::DEV_RUNTIME_PRESET),
PresetId::from(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET),
]
}
/// Sets up the `account` to be a staker of validator variant as supplied to the
/// staking config.
pub fn validator(account: AccountId) -> Staker {
// validator, controller, stash, staker status
(account.clone(), account, STASH, StakerStatus::Validator)
}
/// Extract some accounts from endowed to be put into the collective.
fn collective(endowed: &[AccountId]) -> Vec<AccountId> {
const MAX_COLLECTIVE_SIZE: usize = 50;
let endowed_accounts_count = endowed.len();
endowed
.iter()
.take((endowed_accounts_count.div_ceil(2)).min(MAX_COLLECTIVE_SIZE))
.cloned()
.collect()
}
/// The Keyring's wellknown accounts + Alith and Baltathar.
///
/// Some integration tests require these ETH accounts.
pub fn well_known_including_eth_accounts() -> Vec<AccountId> {
Sr25519Keyring::well_known()
.map(|k| k.to_account_id())
.chain([
// subxt_signer::eth::dev::alith()
array_bytes::hex_n_into_unchecked(
"f24ff3a9cf04c71dbc94d0b566f7a27b94566caceeeeeeeeeeeeeeeeeeeeeeee",
),
// subxt_signer::eth::dev::baltathar()
array_bytes::hex_n_into_unchecked(
"3cd0a705a2dc65e5b1e1205896baa2be8a07c6e0eeeeeeeeeeeeeeeeeeeeeeee",
),
])
.collect::<Vec<_>>()
}
/// Helper function to generate stash, controller and session key from seed.
///
/// Note: `//` is prepended internally.
pub fn authority_keys_from_seed(seed: &str) -> (AccountId, AccountId, SessionKeys) {
(
get_public_from_string_or_panic::<sr25519::Public>(&alloc::format!("{seed}//stash")).into(),
get_public_from_string_or_panic::<sr25519::Public>(seed).into(),
session_keys_from_seed(seed),
)
}
pub fn session_keys(
grandpa: GrandpaId,
babe: BabeId,
im_online: ImOnlineId,
authority_discovery: AuthorityDiscoveryId,
mixnet: MixnetId,
beefy: BeefyId,
) -> SessionKeys {
SessionKeys { grandpa, babe, im_online, authority_discovery, mixnet, beefy }
}
/// We have this method as there is no straight forward way to convert the
/// account keyring into these ids.
///
/// Note: `//` is prepended internally.
pub fn session_keys_from_seed(seed: &str) -> SessionKeys {
session_keys(
get_public_from_string_or_panic::<GrandpaId>(seed),
get_public_from_string_or_panic::<BabeId>(seed),
get_public_from_string_or_panic::<ImOnlineId>(seed),
get_public_from_string_or_panic::<AuthorityDiscoveryId>(seed),
get_public_from_string_or_panic::<MixnetId>(seed),
get_public_from_string_or_panic::<BeefyId>(seed),
)
}
+493
View File
@@ -0,0 +1,493 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Some configurable implementations as associated type for the substrate runtime.
use alloc::boxed::Box;
use frame_support::{
pallet_prelude::*,
traits::{
fungibles::{Balanced, Credit},
Currency, OnUnbalanced,
},
};
use pallet_alliance::{IdentityVerifier, ProposalIndex, ProposalProvider};
use pallet_asset_tx_payment::HandleCredit;
use pallet_identity::legacy::IdentityField;
use pezkuwi_sdk::*;
use crate::{
AccountId, AllianceCollective, AllianceMotion, Assets, Authorship, Balances, Hash,
NegativeImbalance, Runtime, RuntimeCall,
};
pub struct Author;
impl OnUnbalanced<NegativeImbalance> for Author {
fn on_nonzero_unbalanced(amount: NegativeImbalance) {
if let Some(author) = Authorship::author() {
Balances::resolve_creating(&author, amount);
}
}
}
/// A `HandleCredit` implementation that naively transfers the fees to the block author.
/// Will drop and burn the assets in case the transfer fails.
pub struct CreditToBlockAuthor;
impl HandleCredit<AccountId, Assets> for CreditToBlockAuthor {
fn handle_credit(credit: Credit<AccountId, Assets>) {
if let Some(author) = pallet_authorship::Pallet::<Runtime>::author() {
// Drop the result which will trigger the `OnDrop` of the imbalance in case of error.
let _ = Assets::resolve(&author, credit);
}
}
}
pub struct AllianceIdentityVerifier;
impl IdentityVerifier<AccountId> for AllianceIdentityVerifier {
fn has_required_identities(who: &AccountId) -> bool {
crate::Identity::has_identity(who, (IdentityField::Display | IdentityField::Web).bits())
}
fn has_good_judgement(who: &AccountId) -> bool {
use pallet_identity::{IdentityOf, Judgement};
IdentityOf::<Runtime>::get(who)
.map(|registration| registration.judgements)
.map_or(false, |judgements| {
judgements
.iter()
.any(|(_, j)| matches!(j, Judgement::KnownGood | Judgement::Reasonable))
})
}
fn super_account_id(who: &AccountId) -> Option<AccountId> {
use pallet_identity::SuperOf;
SuperOf::<Runtime>::get(who).map(|parent| parent.0)
}
}
pub struct AllianceProposalProvider;
impl ProposalProvider<AccountId, Hash, RuntimeCall> for AllianceProposalProvider {
fn propose_proposal(
who: AccountId,
threshold: u32,
proposal: Box<RuntimeCall>,
length_bound: u32,
) -> Result<(u32, u32), DispatchError> {
AllianceMotion::do_propose_proposed(who, threshold, proposal, length_bound)
}
fn vote_proposal(
who: AccountId,
proposal: Hash,
index: ProposalIndex,
approve: bool,
) -> Result<bool, DispatchError> {
AllianceMotion::do_vote(who, proposal, index, approve)
}
fn close_proposal(
proposal_hash: Hash,
proposal_index: ProposalIndex,
proposal_weight_bound: Weight,
length_bound: u32,
) -> DispatchResultWithPostInfo {
AllianceMotion::do_close(proposal_hash, proposal_index, proposal_weight_bound, length_bound)
}
fn proposal_of(proposal_hash: Hash) -> Option<RuntimeCall> {
pallet_collective::ProposalOf::<Runtime, AllianceCollective>::get(proposal_hash)
}
}
#[cfg(test)]
mod multiplier_tests {
use frame_support::{
dispatch::DispatchClass,
weights::{Weight, WeightToFee},
};
use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment};
use pezkuwi_sdk::*;
use sp_runtime::{
assert_eq_error_rate,
traits::{Convert, One, Zero},
BuildStorage, FixedPointNumber,
};
use crate::{
constants::{currency::*, time::*},
AdjustmentVariable, MaximumMultiplier, MinimumMultiplier, Runtime,
RuntimeBlockWeights as BlockWeights, System, TargetBlockFullness, TransactionPayment,
};
fn max_normal() -> Weight {
BlockWeights::get()
.get(DispatchClass::Normal)
.max_total
.unwrap_or_else(|| BlockWeights::get().max_block)
}
fn min_multiplier() -> Multiplier {
MinimumMultiplier::get()
}
fn target() -> Weight {
TargetBlockFullness::get() * max_normal()
}
// update based on runtime impl.
fn runtime_multiplier_update(fm: Multiplier) -> Multiplier {
TargetedFeeAdjustment::<
Runtime,
TargetBlockFullness,
AdjustmentVariable,
MinimumMultiplier,
MaximumMultiplier,
>::convert(fm)
}
// update based on reference impl.
fn truth_value_update(block_weight: Weight, previous: Multiplier) -> Multiplier {
let accuracy = Multiplier::accuracy() as f64;
let previous_float = previous.into_inner() as f64 / accuracy;
// bump if it is zero.
let previous_float = previous_float.max(min_multiplier().into_inner() as f64 / accuracy);
let max_normal = max_normal();
let target_weight = target();
let normalized_weight_dimensions = (
block_weight.ref_time() as f64 / max_normal.ref_time() as f64,
block_weight.proof_size() as f64 / max_normal.proof_size() as f64,
);
let (normal, max, target) =
if normalized_weight_dimensions.0 < normalized_weight_dimensions.1 {
(block_weight.proof_size(), max_normal.proof_size(), target_weight.proof_size())
} else {
(block_weight.ref_time(), max_normal.ref_time(), target_weight.ref_time())
};
// maximum tx weight
let m = max as f64;
// block weight always truncated to max weight
let block_weight = (normal as f64).min(m);
let v: f64 = AdjustmentVariable::get().to_float();
// Ideal saturation in terms of weight
let ss = target as f64;
// Current saturation in terms of weight
let s = block_weight;
let t1 = v * (s / m - ss / m);
let t2 = v.powi(2) * (s / m - ss / m).powi(2) / 2.0;
let next_float = previous_float * (1.0 + t1 + t2);
Multiplier::from_float(next_float)
}
fn run_with_system_weight<F>(w: Weight, assertions: F)
where
F: Fn() -> (),
{
let mut t: sp_io::TestExternalities = frame_system::GenesisConfig::<Runtime>::default()
.build_storage()
.unwrap()
.into();
t.execute_with(|| {
System::set_block_consumed_resources(w, 0);
assertions()
});
}
#[test]
fn truth_value_update_poc_works() {
let fm = Multiplier::saturating_from_rational(1, 2);
let test_set = vec![
(Weight::zero(), fm),
(Weight::from_parts(100, 0), fm),
(Weight::from_parts(1000, 0), fm),
(target(), fm),
(max_normal() / 2, fm),
(max_normal(), fm),
];
test_set.into_iter().for_each(|(w, fm)| {
run_with_system_weight(w, || {
assert_eq_error_rate!(
truth_value_update(w, fm),
runtime_multiplier_update(fm),
// Error is only 1 in 100^18
Multiplier::from_inner(100),
);
})
})
}
#[test]
fn multiplier_can_grow_from_zero() {
// if the min is too small, then this will not change, and we are doomed forever.
// the block ref time is 1/100th bigger than target.
run_with_system_weight(target().set_ref_time(target().ref_time() * 101 / 100), || {
let next = runtime_multiplier_update(min_multiplier());
assert!(next > min_multiplier(), "{:?} !> {:?}", next, min_multiplier());
});
// the block proof size is 1/100th bigger than target.
run_with_system_weight(target().set_proof_size((target().proof_size() / 100) * 101), || {
let next = runtime_multiplier_update(min_multiplier());
assert!(next > min_multiplier(), "{:?} !> {:?}", next, min_multiplier());
})
}
#[test]
fn multiplier_cannot_go_below_limit() {
// will not go any further below even if block is empty.
run_with_system_weight(Weight::zero(), || {
let next = runtime_multiplier_update(min_multiplier());
assert_eq!(next, min_multiplier());
})
}
#[test]
fn time_to_reach_zero() {
// blocks per 24h in substrate-node: 28,800 (k)
// s* = 0.1875
// The bound from the research in an empty chain is:
// v <~ (p / k(0 - s*))
// p > v * k * -0.1875
// to get p == -1 we'd need
// -1 > 0.00001 * k * -0.1875
// 1 < 0.00001 * k * 0.1875
// 10^9 / 1875 < k
// k > 533_333 ~ 18,5 days.
run_with_system_weight(Weight::zero(), || {
// start from 1, the default.
let mut fm = Multiplier::one();
let mut iterations: u64 = 0;
loop {
let next = runtime_multiplier_update(fm);
fm = next;
if fm == min_multiplier() {
break;
}
iterations += 1;
}
assert!(iterations > 533_333);
})
}
#[test]
fn min_change_per_day() {
run_with_system_weight(max_normal(), || {
let mut fm = Multiplier::one();
// See the example in the doc of `TargetedFeeAdjustment`. are at least 0.234, hence
// `fm > 1.234`.
for _ in 0..DAYS {
let next = runtime_multiplier_update(fm);
fm = next;
}
assert!(fm > Multiplier::saturating_from_rational(1234, 1000));
})
}
#[test]
#[ignore]
fn congested_chain_simulation() {
// `cargo test congested_chain_simulation -- --nocapture` to get some insight.
// almost full. The entire quota of normal transactions is taken.
let block_weight = BlockWeights::get().get(DispatchClass::Normal).max_total.unwrap() -
Weight::from_parts(100, 0);
// Default substrate weight.
let tx_weight = frame_support::weights::constants::ExtrinsicBaseWeight::get();
run_with_system_weight(block_weight, || {
// initial value configured on module
let mut fm = Multiplier::one();
assert_eq!(fm, TransactionPayment::next_fee_multiplier());
let mut iterations: u64 = 0;
loop {
let next = runtime_multiplier_update(fm);
// if no change, panic. This should never happen in this case.
if fm == next {
panic!("The fee should ever increase");
}
fm = next;
iterations += 1;
let fee =
<Runtime as pallet_transaction_payment::Config>::WeightToFee::weight_to_fee(
&tx_weight,
);
let adjusted_fee = fm.saturating_mul_acc_int(fee);
println!(
"iteration {}, new fm = {:?}. Fee at this point is: {} units / {} millicents, \
{} cents, {} dollars",
iterations,
fm,
adjusted_fee,
adjusted_fee / MILLICENTS,
adjusted_fee / CENTS,
adjusted_fee / DOLLARS,
);
}
});
}
#[test]
fn stateless_weight_mul() {
let fm = Multiplier::saturating_from_rational(1, 2);
run_with_system_weight(target() / 4, || {
let next = runtime_multiplier_update(fm);
assert_eq_error_rate!(
next,
truth_value_update(target() / 4, fm),
Multiplier::from_inner(100),
);
// Light block. Multiplier is reduced a little.
assert!(next < fm);
});
run_with_system_weight(target() / 2, || {
let next = runtime_multiplier_update(fm);
assert_eq_error_rate!(
next,
truth_value_update(target() / 2, fm),
Multiplier::from_inner(100),
);
// Light block. Multiplier is reduced a little.
assert!(next < fm);
});
run_with_system_weight(target(), || {
let next = runtime_multiplier_update(fm);
assert_eq_error_rate!(
next,
truth_value_update(target(), fm),
Multiplier::from_inner(100),
);
// ideal. No changes.
assert_eq!(next, fm)
});
run_with_system_weight(target() * 2, || {
// More than ideal. Fee is increased.
let next = runtime_multiplier_update(fm);
assert_eq_error_rate!(
next,
truth_value_update(target() * 2, fm),
Multiplier::from_inner(100),
);
// Heavy block. Fee is increased a little.
assert!(next > fm);
});
}
#[test]
fn weight_mul_grow_on_big_block() {
run_with_system_weight(target() * 2, || {
let mut original = Multiplier::zero();
let mut next = Multiplier::default();
(0..1_000).for_each(|_| {
next = runtime_multiplier_update(original);
assert_eq_error_rate!(
next,
truth_value_update(target() * 2, original),
Multiplier::from_inner(100),
);
// must always increase
assert!(next > original, "{:?} !>= {:?}", next, original);
original = next;
});
});
}
#[test]
fn weight_mul_decrease_on_small_block() {
run_with_system_weight(target() / 2, || {
let mut original = Multiplier::saturating_from_rational(1, 2);
let mut next;
for _ in 0..100 {
// decreases
next = runtime_multiplier_update(original);
assert!(next < original, "{:?} !<= {:?}", next, original);
original = next;
}
})
}
#[test]
fn weight_to_fee_should_not_overflow_on_large_weights() {
let kb_time = Weight::from_parts(1024, 0);
let kb_size = Weight::from_parts(0, 1024);
let mb_time = 1024u64 * kb_time;
let max_fm = Multiplier::saturating_from_integer(i128::MAX);
// check that for all values it can compute, correctly.
vec![
Weight::zero(),
// testcases ignoring proof size part of the weight.
Weight::from_parts(1, 0),
Weight::from_parts(10, 0),
Weight::from_parts(1000, 0),
kb_time,
10u64 * kb_time,
100u64 * kb_time,
mb_time,
10u64 * mb_time,
Weight::from_parts(2147483647, 0),
Weight::from_parts(4294967295, 0),
// testcases ignoring ref time part of the weight.
Weight::from_parts(0, 100000000000),
1000000u64 * kb_size,
1000000000u64 * kb_size,
Weight::from_parts(0, 18014398509481983),
Weight::from_parts(0, 9223372036854775807),
// test cases with both parts of the weight.
BlockWeights::get().max_block / 1024,
BlockWeights::get().max_block / 2,
BlockWeights::get().max_block,
Weight::MAX / 2,
Weight::MAX,
]
.into_iter()
.for_each(|i| {
run_with_system_weight(i, || {
let next = runtime_multiplier_update(Multiplier::one());
let truth = truth_value_update(i, Multiplier::one());
assert_eq_error_rate!(truth, next, Multiplier::from_inner(50_000_000));
});
});
// Some values that are all above the target and will cause an increase.
let t = target();
vec![
t + Weight::from_parts(100, 0),
t + Weight::from_parts(0, t.proof_size() * 2),
t * 2,
t * 4,
]
.into_iter()
.for_each(|i| {
run_with_system_weight(i, || {
let fm = runtime_multiplier_update(max_fm);
// won't grow. The convert saturates everything.
assert_eq!(fm, max_fm);
})
});
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,238 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Autogenerated bag thresholds.
//!
//! Generated on 2022-08-15T19:26:59.939787+00:00
//! Arguments
//! Total issuance: 100000000000000
//! Minimum balance: 100000000000000
//! for the node runtime.
/// Existential weight for this runtime.
#[cfg(any(test, feature = "std"))]
#[allow(unused)]
pub const EXISTENTIAL_WEIGHT: u64 = 100_000_000_000_000;
/// Constant ratio between bags for this runtime.
#[cfg(any(test, feature = "std"))]
#[allow(unused)]
pub const CONSTANT_RATIO: f64 = 1.0628253590743408;
/// Upper thresholds delimiting the bag list.
pub const THRESHOLDS: [u64; 200] = [
100_000_000_000_000,
106_282_535_907_434,
112_959_774_389_150,
120_056_512_776_105,
127_599_106_300_477,
135_615_565_971_369,
144_135_662_599_590,
153_191_037_357_827,
162_815_319_286_803,
173_044_250_183_800,
183_915_817_337_347,
195_470_394_601_017,
207_750_892_330_229,
220_802_916_738_890,
234_674_939_267_673,
249_418_476_592_914,
265_088_281_944_639,
281_742_548_444_211,
299_443_125_216_738,
318_255_747_080_822,
338_250_278_668_647,
359_500_973_883_001,
382_086_751_654_776,
406_091_489_025_036,
431_604_332_640_068,
458_720_029_816_222,
487_539_280_404_019,
518_169_110_758_247,
550_723_271_202_866,
585_322_658_466_782,
622_095_764_659_305,
661_179_154_452_653,
702_717_972_243_610,
746_866_481_177_808,
793_788_636_038_393,
843_658_692_126_636,
896_661_852_395_681,
952_994_955_240_703,
1_012_867_205_499_736,
1_076_500_951_379_881,
1_144_132_510_194_192,
1_216_013_045_975_769,
1_292_409_502_228_280,
1_373_605_593_276_862,
1_459_902_857_901_004,
1_551_621_779_162_291,
1_649_102_974_585_730,
1_752_708_461_114_642,
1_862_822_999_536_805,
1_979_855_523_374_646,
2_104_240_657_545_975,
2_236_440_332_435_128,
2_376_945_499_368_703,
2_526_277_953_866_680,
2_684_992_273_439_945,
2_853_677_877_130_641,
3_032_961_214_443_876,
3_223_508_091_799_862,
3_426_026_145_146_232,
3_641_267_467_913_124,
3_870_031_404_070_482,
4_113_167_516_660_186,
4_371_578_742_827_277,
4_646_224_747_067_156,
4_938_125_485_141_739,
5_248_364_991_899_922,
5_578_095_407_069_235,
5_928_541_253_969_291,
6_301_003_987_036_955,
6_696_866_825_051_405,
7_117_599_888_008_300,
7_564_765_656_719_910,
8_040_024_775_416_580,
8_545_142_218_898_723,
9_081_993_847_142_344,
9_652_573_371_700_016,
10_258_999_759_768_490,
10_903_525_103_419_522,
11_588_542_983_217_942,
12_316_597_357_287_042,
13_090_392_008_832_678,
13_912_800_587_211_472,
14_786_877_279_832_732,
15_715_868_154_526_436,
16_703_223_214_499_558,
17_752_609_210_649_358,
18_867_923_258_814_856,
20_053_307_312_537_008,
21_313_163_545_075_252,
22_652_170_697_804_756,
24_075_301_455_707_600,
25_587_840_914_485_432,
27_195_406_207_875_088,
28_903_967_368_057_400,
30_719_869_496_628_636,
32_649_856_328_471_220,
34_701_095_276_033_064,
36_881_204_047_022_752,
39_198_278_934_370_992,
41_660_924_883_519_016,
44_278_287_448_695_240,
47_060_086_756_856_400,
50_016_653_605_425_536,
53_158_967_827_883_320,
56_498_699_069_691_424,
60_048_250_125_977_912,
63_820_803_001_928_304,
67_830_367_866_937_216,
72_091_835_084_322_176,
76_621_030_509_822_880,
81_434_774_264_248_528,
86_550_943_198_537_824,
91_988_537_283_208_848,
97_767_750_168_749_840,
103_910_044_178_992_000,
110_438_230_015_967_792,
117_376_551_472_255_616,
124_750_775_465_407_920,
132_588_287_728_824_640,
140_918_194_514_440_064,
149_771_430_684_917_568,
159_180_874_596_775_264,
169_181_470_201_085_280,
179_810_356_815_193_344,
191_107_007_047_393_216,
203_113_373_386_768_288,
215_874_044_002_592_672,
229_436_408_331_885_600,
243_850_833_070_063_392,
259_170_849_218_267_264,
275_453_350_882_006_752,
292_758_806_559_399_232,
311_151_483_703_668_992,
330_699_687_393_865_920,
351_476_014_000_157_824,
373_557_620_785_735_808,
397_026_512_446_556_096,
421_969_845_653_044_224,
448_480_252_724_740_928,
476_656_185_639_923_904,
506_602_281_657_757_760,
538_429_751_910_786_752,
572_256_794_410_890_176,
608_209_033_002_485_632,
646_419_983_893_124_352,
687_031_551_494_039_552,
730_194_555_412_054_016,
776_069_290_549_944_960,
824_826_122_395_314_176,
876_646_119_708_695_936,
931_721_726_960_522_368,
990_257_479_014_182_144,
1_052_470_760_709_299_712,
1_118_592_614_166_106_112,
1_188_868_596_808_997_376,
1_263_559_693_295_730_432,
1_342_943_284_738_898_688,
1_427_314_178_819_094_784,
1_516_985_704_615_302_400,
1_612_290_876_218_400_768,
1_713_583_629_449_105_408,
1_821_240_136_273_157_632,
1_935_660_201_795_120_128,
2_057_268_749_018_809_600,
2_186_517_396_888_336_384,
2_323_886_137_470_138_880,
2_469_885_118_504_583_168,
2_625_056_537_947_004_416,
2_789_976_657_533_970_944,
2_965_257_942_852_572_160,
3_151_551_337_860_326_400,
3_349_548_682_302_620_672,
3_559_985_281_005_267_968,
3_783_642_634_583_792_128,
4_021_351_341_710_503_936,
4_273_994_183_717_548_544,
4_542_509_402_991_247_872,
4_827_894_187_332_742_144,
5_131_208_373_224_844_288,
5_453_578_381_757_959_168,
5_796_201_401_831_965_696,
6_160_349_836_169_256_960,
6_547_376_026_650_146_816,
6_958_717_276_519_173_120,
7_395_901_188_113_309_696,
7_860_551_335_934_872_576,
8_354_393_296_137_270_272,
8_879_261_054_815_360_000,
9_437_103_818_898_946_048,
10_029_993_254_943_105_024,
10_660_131_182_698_121_216,
11_329_857_752_030_707_712,
12_041_660_133_563_240_448,
12_798_181_755_305_525_248,
13_602_232_119_581_272_064,
14_456_797_236_706_498_560,
15_365_050_714_167_523_328,
16_330_365_542_480_556_032,
17_356_326_621_502_140_416,
18_446_744_073_709_551_615,
];