mirror of
https://github.com/pezkuwichain/pezkuwi-runtime-templates.git
synced 2026-06-14 15:31:00 +00:00
Fuzzer Integration (#109)
Fuzzer package created and docker setup for fuzzing added
This commit is contained in:
Generated
+725
-1525
File diff suppressed because it is too large
Load Diff
+9
-3
@@ -3,6 +3,7 @@ members = [
|
|||||||
"node",
|
"node",
|
||||||
"pallets/template",
|
"pallets/template",
|
||||||
"runtime",
|
"runtime",
|
||||||
|
"template-fuzzer",
|
||||||
]
|
]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
@@ -20,9 +21,7 @@ futures = "0.3.28"
|
|||||||
hex-literal = "0.4.1"
|
hex-literal = "0.4.1"
|
||||||
jsonrpsee = { version = "0.16.3", features = [ "server" ] }
|
jsonrpsee = { version = "0.16.3", features = [ "server" ] }
|
||||||
log = { version = "0.4.20", default-features = false }
|
log = { version = "0.4.20", default-features = false }
|
||||||
parity-scale-codec = { version = "3.0.0", default-features = false, features = [
|
parity-scale-codec = { version = "3.0.0", default-features = false, features = [ "derive", "max-encoded-len" ] }
|
||||||
"derive",
|
|
||||||
] }
|
|
||||||
scale-info = { version = "2.10.0", default-features = false }
|
scale-info = { version = "2.10.0", default-features = false }
|
||||||
serde = { version = "1.0.188", default-features = false }
|
serde = { version = "1.0.188", default-features = false }
|
||||||
serde_json = "1.0.108"
|
serde_json = "1.0.108"
|
||||||
@@ -82,6 +81,7 @@ sp-keystore = { git = "https://github.com/paritytech/polkadot-sdk", branch = "re
|
|||||||
sp-offchain = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
sp-offchain = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
||||||
sp-runtime = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
sp-runtime = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
||||||
sp-session = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
sp-session = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
||||||
|
sp-state-machine = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
||||||
sp-std = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
sp-std = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
||||||
sp-timestamp = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
sp-timestamp = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
||||||
sp-transaction-pool = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
sp-transaction-pool = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
||||||
@@ -120,10 +120,16 @@ cumulus-primitives-core = { git = "https://github.com/paritytech/polkadot-sdk",
|
|||||||
cumulus-primitives-parachain-inherent = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
cumulus-primitives-parachain-inherent = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
||||||
cumulus-primitives-utility = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
cumulus-primitives-utility = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
||||||
cumulus-relay-chain-interface = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
cumulus-relay-chain-interface = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
||||||
|
cumulus-test-relay-sproof-builder = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
||||||
pallet-collator-selection = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
pallet-collator-selection = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
||||||
parachain-info = { package = "staging-parachain-info", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
parachain-info = { package = "staging-parachain-info", git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
||||||
parachains-common = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
parachains-common = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.6.0", default-features = false }
|
||||||
|
|
||||||
|
# Fuzzer
|
||||||
|
substrate-runtime-fuzzer = { git = "https://github.com/srlabs/substrate-runtime-fuzzer.git", default-features = false }
|
||||||
|
ziggy = { version = "0.8", default-features = false }
|
||||||
|
|
||||||
|
|
||||||
[workspace.lints.clippy]
|
[workspace.lints.clippy]
|
||||||
large_enum_variant = "allow"
|
large_enum_variant = "allow"
|
||||||
too_many_arguments = "allow"
|
too_many_arguments = "allow"
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
[package]
|
||||||
|
name = "template-fuzzer"
|
||||||
|
version = "0.1.0"
|
||||||
|
[package.authors]
|
||||||
|
workspace = true
|
||||||
|
[package.description]
|
||||||
|
workspace = true
|
||||||
|
[package.edition]
|
||||||
|
workspace = true
|
||||||
|
[package.license]
|
||||||
|
workspace = true
|
||||||
|
[package.repository]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
substrate-runtime-fuzzer = { workspace = true }
|
||||||
|
ziggy = { workspace = true }
|
||||||
|
|
||||||
|
parachain-template-runtime = { path = "../runtime" }
|
||||||
|
parachains-common = { workspace = true }
|
||||||
|
|
||||||
|
parity-scale-codec = { workspace = true }
|
||||||
|
|
||||||
|
frame-support = { workspace = true }
|
||||||
|
frame-system = { workspace = true }
|
||||||
|
|
||||||
|
sp-consensus-aura = { workspace = true }
|
||||||
|
sp-runtime = { workspace = true }
|
||||||
|
sp-state-machine = { workspace = true }
|
||||||
|
|
||||||
|
pallet-balances = { workspace = true }
|
||||||
|
pallet-timestamp = { workspace = true }
|
||||||
|
|
||||||
|
cumulus-pallet-parachain-system = { workspace = true }
|
||||||
|
cumulus-primitives-core = { workspace = true }
|
||||||
|
cumulus-primitives-parachain-inherent = { workspace = true }
|
||||||
|
cumulus-test-relay-sproof-builder = { workspace = true }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = [ "std", "try-runtime" ]
|
||||||
|
std = [
|
||||||
|
"frame-support/std",
|
||||||
|
"pallet-timestamp/std",
|
||||||
|
"parachain-template-runtime/std",
|
||||||
|
"parity-scale-codec/std",
|
||||||
|
"sp-consensus-aura/std",
|
||||||
|
"sp-runtime/std",
|
||||||
|
]
|
||||||
|
try-runtime = [
|
||||||
|
"frame-support/try-runtime",
|
||||||
|
"frame-system/try-runtime",
|
||||||
|
"pallet-timestamp/try-runtime",
|
||||||
|
"parachain-template-runtime/try-runtime",
|
||||||
|
"sp-runtime/try-runtime",
|
||||||
|
]
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
FROM rust:1-buster
|
||||||
|
USER root
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get -y install protobuf-compiler libclang-dev clang binutils-dev libunwind-dev
|
||||||
|
|
||||||
|
RUN mkdir -p /fuzztest
|
||||||
|
|
||||||
|
ADD . /fuzztest/
|
||||||
|
|
||||||
|
WORKDIR /fuzztest/template-fuzzer
|
||||||
|
|
||||||
|
CMD ["/bin/bash", "/fuzztest/template-fuzzer/run-fuzzer.sh"]
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
## Template Fuzzer
|
||||||
|
|
||||||
|
This a fuzzer implementation for OpenZeppelin's runtime templates. Currently there is a single runtime (generic one) and a single fuzzer setup.
|
||||||
|
This code is highly experimental, if you notice any flaws consider creating an issue or a pull request.
|
||||||
|
|
||||||
|
### How to run the fuzzer
|
||||||
|
|
||||||
|
We have provided a docker packaging for the fuzzer, so that you can run it like this from the **repository root directory**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -t fuzzer -f template-fuzzer/Dockerfile .
|
||||||
|
docker run --mount source=output,target=/fuzztest/template-fuzzer/output fuzzer
|
||||||
|
```
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
rustup target add wasm32-unknown-unknown
|
||||||
|
rustup component add rust-src
|
||||||
|
cargo install ziggy cargo-afl honggfuzz grcov
|
||||||
|
AFL_SKIP_CPUFREQ=true AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=true cargo ziggy fuzz -t 20 -j 5
|
||||||
@@ -0,0 +1,288 @@
|
|||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
use cumulus_primitives_core::relay_chain::Slot;
|
||||||
|
use frame_support::{
|
||||||
|
dispatch::GetDispatchInfo,
|
||||||
|
pallet_prelude::Encode,
|
||||||
|
traits::{IntegrityTest, TryState, TryStateSelect},
|
||||||
|
weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight},
|
||||||
|
};
|
||||||
|
use parachain_template_runtime::{
|
||||||
|
AllPalletsWithSystem, Balance, Balances, BlockNumber, Executive, Runtime, RuntimeCall,
|
||||||
|
RuntimeOrigin, SudoConfig, UncheckedExtrinsic, SLOT_DURATION,
|
||||||
|
};
|
||||||
|
use parachains_common::AccountId;
|
||||||
|
use sp_consensus_aura::AURA_ENGINE_ID;
|
||||||
|
use sp_runtime::{
|
||||||
|
traits::{Dispatchable, Header},
|
||||||
|
Digest, DigestItem, Storage,
|
||||||
|
};
|
||||||
|
use substrate_runtime_fuzzer::{Data, INITIAL_TIMESTAMP, MAX_TIME_FOR_BLOCK};
|
||||||
|
|
||||||
|
pub type Externalities = sp_state_machine::BasicExternalities;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let endowed_accounts: Vec<AccountId> = (0..5).map(|i| [i; 32].into()).collect();
|
||||||
|
|
||||||
|
let genesis_storage: Storage = {
|
||||||
|
use parachain_template_runtime::{
|
||||||
|
BalancesConfig, CollatorSelectionConfig, RuntimeGenesisConfig, SessionConfig,
|
||||||
|
SessionKeys,
|
||||||
|
};
|
||||||
|
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
|
||||||
|
use sp_runtime::{app_crypto::ByteArray, BuildStorage};
|
||||||
|
|
||||||
|
let initial_authorities: Vec<(AccountId, AuraId)> =
|
||||||
|
vec![([0; 32].into(), AuraId::from_slice(&[0; 32]).unwrap())];
|
||||||
|
let root: AccountId = [0; 32].into();
|
||||||
|
|
||||||
|
RuntimeGenesisConfig {
|
||||||
|
system: Default::default(),
|
||||||
|
balances: BalancesConfig {
|
||||||
|
// Configure endowed accounts with initial balance of 1 << 60.
|
||||||
|
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(),
|
||||||
|
},
|
||||||
|
aura: Default::default(),
|
||||||
|
session: SessionConfig {
|
||||||
|
keys: initial_authorities
|
||||||
|
.iter()
|
||||||
|
.map(|x| (x.0.clone(), x.0.clone(), SessionKeys { aura: x.1.clone() }))
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
},
|
||||||
|
collator_selection: CollatorSelectionConfig {
|
||||||
|
invulnerables: initial_authorities.iter().map(|x| (x.0.clone())).collect(),
|
||||||
|
candidacy_bond: 1 << 57,
|
||||||
|
desired_candidates: 1,
|
||||||
|
},
|
||||||
|
aura_ext: Default::default(),
|
||||||
|
parachain_info: Default::default(),
|
||||||
|
parachain_system: Default::default(),
|
||||||
|
polkadot_xcm: Default::default(),
|
||||||
|
assets: Default::default(),
|
||||||
|
transaction_payment: Default::default(),
|
||||||
|
sudo: SudoConfig { key: Some(root) },
|
||||||
|
}
|
||||||
|
.build_storage()
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
ziggy::fuzz!(|data: &[u8]| {
|
||||||
|
let mut iteratable = Data::from_data(data);
|
||||||
|
|
||||||
|
// Max weight for a block.
|
||||||
|
let max_weight: Weight = Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND * 2, 0);
|
||||||
|
|
||||||
|
let extrinsics: Vec<(Option<u32>, usize, RuntimeCall)> =
|
||||||
|
iteratable.extract_extrinsics::<RuntimeCall>();
|
||||||
|
|
||||||
|
if extrinsics.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// `externalities` represents the state of our mock chain.
|
||||||
|
let mut externalities = Externalities::new(genesis_storage.clone());
|
||||||
|
|
||||||
|
let mut current_block: u32 = 1;
|
||||||
|
let mut current_weight: Weight = Weight::zero();
|
||||||
|
// let mut already_seen = 0; // This must be uncommented if you want to print events
|
||||||
|
let mut elapsed: Duration = Duration::ZERO;
|
||||||
|
|
||||||
|
let start_block = |block: u32, lapse: u32| {
|
||||||
|
#[cfg(not(fuzzing))]
|
||||||
|
println!("\ninitializing block {}", block + lapse);
|
||||||
|
|
||||||
|
let next_block = block + lapse;
|
||||||
|
let current_timestamp = INITIAL_TIMESTAMP + u64::from(next_block) * SLOT_DURATION;
|
||||||
|
let pre_digest = match current_timestamp {
|
||||||
|
INITIAL_TIMESTAMP => Default::default(),
|
||||||
|
_ => Digest {
|
||||||
|
logs: vec![DigestItem::PreRuntime(
|
||||||
|
AURA_ENGINE_ID,
|
||||||
|
Slot::from(current_timestamp / SLOT_DURATION).encode(),
|
||||||
|
)],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let prev_header = match next_block {
|
||||||
|
1 => None,
|
||||||
|
_ => Some(Executive::finalize_block()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let parent_header = &Header::new(
|
||||||
|
next_block + 1,
|
||||||
|
Default::default(),
|
||||||
|
Default::default(),
|
||||||
|
prev_header.clone().map(|x| x.hash()).unwrap_or_default(),
|
||||||
|
pre_digest,
|
||||||
|
);
|
||||||
|
Executive::initialize_block(parent_header);
|
||||||
|
|
||||||
|
// We apply the timestamp extrinsic for the current block.
|
||||||
|
Executive::apply_extrinsic(UncheckedExtrinsic::new_unsigned(RuntimeCall::Timestamp(
|
||||||
|
pallet_timestamp::Call::set { now: current_timestamp },
|
||||||
|
)))
|
||||||
|
.unwrap()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let parachain_validation_data = {
|
||||||
|
use cumulus_primitives_core::{relay_chain::HeadData, PersistedValidationData};
|
||||||
|
use cumulus_primitives_parachain_inherent::ParachainInherentData;
|
||||||
|
use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
|
||||||
|
|
||||||
|
let parent_head =
|
||||||
|
HeadData(prev_header.clone().unwrap_or(parent_header.clone()).encode());
|
||||||
|
let sproof_builder = RelayStateSproofBuilder {
|
||||||
|
para_id: 100.into(),
|
||||||
|
current_slot: Slot::from(2 * current_timestamp / SLOT_DURATION),
|
||||||
|
included_para_head: Some(parent_head.clone()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let (relay_parent_storage_root, relay_chain_state) =
|
||||||
|
sproof_builder.into_state_root_and_proof();
|
||||||
|
let data = ParachainInherentData {
|
||||||
|
validation_data: PersistedValidationData {
|
||||||
|
parent_head,
|
||||||
|
relay_parent_number: next_block,
|
||||||
|
relay_parent_storage_root,
|
||||||
|
max_pov_size: 1000,
|
||||||
|
},
|
||||||
|
relay_chain_state,
|
||||||
|
downward_messages: Default::default(),
|
||||||
|
horizontal_messages: Default::default(),
|
||||||
|
};
|
||||||
|
cumulus_pallet_parachain_system::Call::set_validation_data { data }
|
||||||
|
};
|
||||||
|
|
||||||
|
Executive::apply_extrinsic(UncheckedExtrinsic::new_unsigned(
|
||||||
|
RuntimeCall::ParachainSystem(parachain_validation_data),
|
||||||
|
))
|
||||||
|
.unwrap()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Calls that need to be called before each block starts (init_calls) go here
|
||||||
|
};
|
||||||
|
|
||||||
|
externalities.execute_with(|| start_block(current_block, 0));
|
||||||
|
|
||||||
|
for (maybe_lapse, origin, extrinsic) in extrinsics {
|
||||||
|
// If the lapse is in the range [0, MAX_BLOCK_LAPSE] we finalize the block and initialize
|
||||||
|
// a new one.
|
||||||
|
if let Some(lapse) = maybe_lapse {
|
||||||
|
// We update our state variables
|
||||||
|
current_weight = Weight::zero();
|
||||||
|
elapsed = Duration::ZERO;
|
||||||
|
|
||||||
|
// We start the next block
|
||||||
|
externalities.execute_with(|| start_block(current_block, lapse));
|
||||||
|
current_block += lapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We get the current time for timing purposes.
|
||||||
|
let now = Instant::now();
|
||||||
|
|
||||||
|
let mut call_weight = Weight::zero();
|
||||||
|
// We compute the weight to avoid overweight blocks.
|
||||||
|
externalities.execute_with(|| {
|
||||||
|
call_weight = extrinsic.get_dispatch_info().weight;
|
||||||
|
});
|
||||||
|
|
||||||
|
current_weight = current_weight.saturating_add(call_weight);
|
||||||
|
if current_weight.ref_time() >= max_weight.ref_time() {
|
||||||
|
#[cfg(not(fuzzing))]
|
||||||
|
println!("Skipping because of max weight {max_weight}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
externalities.execute_with(|| {
|
||||||
|
let origin_account = endowed_accounts[origin % endowed_accounts.len()].clone();
|
||||||
|
#[cfg(not(fuzzing))]
|
||||||
|
{
|
||||||
|
println!("\n origin: {origin_account:?}");
|
||||||
|
println!(" call: {extrinsic:?}");
|
||||||
|
}
|
||||||
|
let _res = extrinsic.clone().dispatch(RuntimeOrigin::signed(origin_account));
|
||||||
|
#[cfg(not(fuzzing))]
|
||||||
|
println!(" result: {_res:?}");
|
||||||
|
|
||||||
|
// Uncomment to print events for debugging purposes
|
||||||
|
/*
|
||||||
|
#[cfg(not(fuzzing))]
|
||||||
|
{
|
||||||
|
let all_events = statemine_runtime::System::events();
|
||||||
|
let events: Vec<_> = all_events.clone().into_iter().skip(already_seen).collect();
|
||||||
|
already_seen = all_events.len();
|
||||||
|
println!(" events: {:?}\n", events);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
});
|
||||||
|
|
||||||
|
elapsed += now.elapsed();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(fuzzing))]
|
||||||
|
println!("\n time spent: {elapsed:?}");
|
||||||
|
assert!(elapsed.as_secs() <= MAX_TIME_FOR_BLOCK, "block execution took too much time");
|
||||||
|
|
||||||
|
// We end the final block
|
||||||
|
externalities.execute_with(|| {
|
||||||
|
// Finilization
|
||||||
|
Executive::finalize_block();
|
||||||
|
// Invariants
|
||||||
|
#[cfg(not(fuzzing))]
|
||||||
|
println!("\ntesting invariants for block {current_block}");
|
||||||
|
<AllPalletsWithSystem as TryState<BlockNumber>>::try_state(
|
||||||
|
current_block,
|
||||||
|
TryStateSelect::All,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
// After execution of all blocks.
|
||||||
|
externalities.execute_with(|| {
|
||||||
|
// We keep track of the sum of balance of accounts
|
||||||
|
let mut counted_free = 0;
|
||||||
|
let mut counted_reserved = 0;
|
||||||
|
|
||||||
|
for acc in frame_system::Account::<Runtime>::iter() {
|
||||||
|
// Check that the consumer/provider state is valid.
|
||||||
|
let acc_consumers = acc.1.consumers;
|
||||||
|
let acc_providers = acc.1.providers;
|
||||||
|
assert!(!(acc_consumers > 0 && acc_providers == 0), "Invalid state");
|
||||||
|
|
||||||
|
// Increment our balance counts
|
||||||
|
counted_free += acc.1.data.free;
|
||||||
|
counted_reserved += acc.1.data.reserved;
|
||||||
|
// Check that locks and holds are valid.
|
||||||
|
let max_lock: Balance =
|
||||||
|
Balances::locks(&acc.0).iter().map(|l| l.amount).max().unwrap_or_default();
|
||||||
|
assert_eq!(
|
||||||
|
max_lock, acc.1.data.frozen,
|
||||||
|
"Max lock should be equal to frozen balance"
|
||||||
|
);
|
||||||
|
let sum_holds: Balance =
|
||||||
|
pallet_balances::Holds::<Runtime>::get(&acc.0).iter().map(|l| l.amount).sum();
|
||||||
|
assert!(
|
||||||
|
sum_holds <= acc.1.data.reserved,
|
||||||
|
"Sum of all holds ({sum_holds}) should be less than or equal to reserved \
|
||||||
|
balance {}",
|
||||||
|
acc.1.data.reserved
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let total_issuance = pallet_balances::TotalIssuance::<Runtime>::get();
|
||||||
|
let counted_issuance = counted_free + counted_reserved;
|
||||||
|
// The reason we do not simply use `!=` here is that some balance might be transfered to another chain via XCM.
|
||||||
|
// If we find some kind of workaround for this, we could replace `<` by `!=` here and make the check stronger.
|
||||||
|
assert!(
|
||||||
|
total_issuance <= counted_issuance,
|
||||||
|
"Inconsistent total issuance: {total_issuance} but counted {counted_issuance}"
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(not(fuzzing))]
|
||||||
|
println!("running integrity tests");
|
||||||
|
// We run all developer-defined integrity tests
|
||||||
|
<AllPalletsWithSystem as IntegrityTest>::integrity_test();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user