feat: initialize Kurdistan SDK - independent fork of Polkadot SDK
This commit is contained in:
@@ -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"]
|
||||
@@ -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),
|
||||
)
|
||||
}
|
||||
@@ -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,
|
||||
];
|
||||
Reference in New Issue
Block a user