Add try_state and integrity_test to XCM simulator fuzzer (#3222)

This adds `try_state()` and `integrity_test()` to the four runtimes of
the XCM-simulator fuzzer.

With this, we are able to stress-test [message-queue's
try_state](https://github.com/paritytech/polkadot-sdk/blob/7df1ae3b8111d534cce108b2b405b6a33fcdedc3/substrate/frame/message-queue/src/lib.rs#L1245-L1347).

This also adds the `Transact` block-listing from #2424 to avoid
false-positives.

Thank you @ggwpez for the help with the runtime configurations.
This commit is contained in:
Louis Merlin
2024-02-08 14:05:00 +01:00
committed by GitHub
parent 2ea6bcf195
commit 84d89e379b
6 changed files with 93 additions and 59 deletions
Generated
+2
View File
@@ -22192,8 +22192,10 @@ name = "xcm-simulator-fuzzer"
version = "1.0.0"
dependencies = [
"arbitrary",
"frame-executive",
"frame-support",
"frame-system",
"frame-try-runtime",
"honggfuzz",
"pallet-balances",
"pallet-message-queue",
@@ -18,6 +18,8 @@ scale-info = { version = "2.10.0", features = ["derive"] }
frame-system = { path = "../../../../substrate/frame/system" }
frame-support = { path = "../../../../substrate/frame/support" }
frame-executive = { path = "../../../../substrate/frame/executive" }
frame-try-runtime = { path = "../../../../substrate/frame/try-runtime" }
pallet-balances = { path = "../../../../substrate/frame/balances" }
pallet-message-queue = { path = "../../../../substrate/frame/message-queue" }
sp-std = { path = "../../../../substrate/primitives/std" }
@@ -35,6 +37,17 @@ polkadot-runtime-parachains = { path = "../../../runtime/parachains" }
polkadot-parachain-primitives = { path = "../../../parachain" }
[features]
try-runtime = [
"frame-executive/try-runtime",
"frame-support/try-runtime",
"frame-system/try-runtime",
"frame-try-runtime/try-runtime",
"pallet-balances/try-runtime",
"pallet-message-queue/try-runtime",
"pallet-xcm/try-runtime",
"polkadot-runtime-parachains/try-runtime",
"sp-runtime/try-runtime",
]
runtime-benchmarks = [
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
+3 -3
View File
@@ -14,7 +14,7 @@ cargo install honggfuzz
In this directory, run this command:
```
cargo hfuzz run xcm-fuzzer
HFUZZ_BUILD_ARGS="--features=try-runtime" cargo hfuzz run xcm-fuzzer
```
## Run a single input
@@ -22,7 +22,7 @@ cargo hfuzz run xcm-fuzzer
In this directory, run this command:
```
cargo hfuzz run-debug xcm-fuzzer hfuzz_workspace/xcm-fuzzer/fuzzer_input_file
cargo run --features=try-runtime -- hfuzz_workspace/xcm-fuzzer/fuzzer_input_file
```
## Generate coverage
@@ -31,7 +31,7 @@ In this directory, run these four commands:
```
RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" \
CARGO_INCREMENTAL=0 SKIP_WASM_BUILD=1 CARGO_HOME=./cargo cargo build
CARGO_INCREMENTAL=0 SKIP_WASM_BUILD=1 CARGO_HOME=./cargo cargo build --features=try-runtime
../../../target/debug/xcm-fuzzer hfuzz_workspace/xcm-fuzzer/input/
zip -0 ccov.zip `find ../../../target/ \( -name "*.gc*" -o -name "test-*.gc*" \) -print`
grcov ccov.zip -s ../../../ -t html --llvm --branch --ignore-not-existing -o ./coverage
+39 -3
View File
@@ -23,7 +23,9 @@ use polkadot_parachain_primitives::primitives::Id as ParaId;
use sp_runtime::{traits::AccountIdConversion, BuildStorage};
use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt};
use frame_support::assert_ok;
#[cfg(feature = "try-runtime")]
use frame_support::traits::{TryState, TryStateSelect::All};
use frame_support::{assert_ok, traits::IntegrityTest};
use xcm::{latest::prelude::*, MAX_XCM_DECODE_DEPTH};
use arbitrary::{Arbitrary, Error, Unstructured};
@@ -98,7 +100,7 @@ impl<'a> Arbitrary<'a> for XcmMessage {
if let Ok(message) =
DecodeLimit::decode_with_depth_limit(MAX_XCM_DECODE_DEPTH, &mut encoded_message)
{
return Ok(XcmMessage { source, destination, message })
return Ok(XcmMessage { source, destination, message });
}
Err(Error::IncorrectFormat)
}
@@ -148,6 +150,21 @@ pub fn relay_ext() -> sp_io::TestExternalities {
pub type RelayChainPalletXcm = pallet_xcm::Pallet<relay_chain::Runtime>;
pub type ParachainPalletXcm = pallet_xcm::Pallet<parachain::Runtime>;
// We check XCM messages recursively for blocklisted messages
fn recursively_matches_blocklisted_messages(message: &Instruction<()>) -> bool {
match message {
DepositReserveAsset { xcm, .. } |
ExportMessage { xcm, .. } |
InitiateReserveWithdraw { xcm, .. } |
InitiateTeleport { xcm, .. } |
TransferReserveAsset { xcm, .. } |
SetErrorHandler(xcm) |
SetAppendix(xcm) => xcm.iter().any(recursively_matches_blocklisted_messages),
// The blocklisted message is the Transact instruction.
m => matches!(m, Transact { .. }),
}
}
fn run_input(xcm_messages: [XcmMessage; 5]) {
MockNet::reset();
@@ -155,6 +172,11 @@ fn run_input(xcm_messages: [XcmMessage; 5]) {
println!();
for xcm_message in xcm_messages {
if xcm_message.message.iter().any(recursively_matches_blocklisted_messages) {
println!(" skipping message\n");
continue;
}
if xcm_message.source % 4 == 0 {
// We get the destination for the message
let parachain_id = (xcm_message.destination % 3) + 1;
@@ -197,8 +219,22 @@ fn run_input(xcm_messages: [XcmMessage; 5]) {
}
#[cfg(not(fuzzing))]
println!();
// We run integrity tests and try_runtime invariants
[ParaA::execute_with, ParaB::execute_with, ParaC::execute_with].iter().for_each(
|execute_with| {
execute_with(|| {
#[cfg(feature = "try-runtime")]
parachain::AllPalletsWithSystem::try_state(Default::default(), All).unwrap();
parachain::AllPalletsWithSystem::integrity_test();
});
},
);
Relay::execute_with(|| {
#[cfg(feature = "try-runtime")]
relay_chain::AllPalletsWithSystem::try_state(Default::default(), All).unwrap();
relay_chain::AllPalletsWithSystem::integrity_test();
});
}
Relay::execute_with(|| {});
}
fn main() {
@@ -24,10 +24,11 @@ use frame_support::{
};
use frame_system::EnsureRoot;
use sp_core::{ConstU32, H256};
use sp_core::ConstU32;
use sp_runtime::{
traits::{Hash, IdentityLookup},
AccountId32,
generic,
traits::{AccountIdLookup, BlakeTwo256, Hash, IdentifyAccount, Verify},
MultiAddress, MultiSignature,
};
use sp_std::prelude::*;
@@ -47,38 +48,29 @@ use xcm_builder::{
};
use xcm_executor::{Config, XcmExecutor};
pub type AccountId = AccountId32;
pub type SignedExtra = (frame_system::CheckNonZeroSender<Runtime>,);
pub type BlockNumber = u64;
pub type Address = MultiAddress<AccountId, ()>;
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
pub type UncheckedExtrinsic =
generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>;
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
pub type Signature = MultiSignature;
pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
pub type Balance = u128;
parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const BlockHashCount: u32 = 250;
}
#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
impl frame_system::Config for Runtime {
type RuntimeOrigin = RuntimeOrigin;
type RuntimeCall = RuntimeCall;
type Nonce = u64;
type Hash = H256;
type Hashing = ::sp_runtime::traits::BlakeTwo256;
type AccountId = AccountId;
type Lookup = IdentityLookup<Self::AccountId>;
type Lookup = AccountIdLookup<AccountId, ()>;
type Block = Block;
type RuntimeEvent = RuntimeEvent;
type BlockHashCount = BlockHashCount;
type BlockWeights = ();
type BlockLength = ();
type Version = ();
type PalletInfo = PalletInfo;
type AccountData = pallet_balances::AccountData<Balance>;
type OnNewAccount = ();
type OnKilledAccount = ();
type DbWeight = ();
type BaseCallFilter = Everything;
type SystemWeightInfo = ();
type SS58Prefix = ();
type OnSetCode = ();
type MaxConsumers = frame_support::traits::ConstU32<16>;
}
parameter_types! {
@@ -356,8 +348,6 @@ impl pallet_xcm::Config for Runtime {
type AdminOrigin = EnsureRoot<AccountId>;
}
type Block = frame_system::mocking::MockBlock<Runtime>;
construct_runtime!(
pub enum Runtime
{
@@ -23,8 +23,12 @@ use frame_support::{
};
use frame_system::EnsureRoot;
use sp_core::{ConstU32, H256};
use sp_runtime::{traits::IdentityLookup, AccountId32};
use sp_core::ConstU32;
use sp_runtime::{
generic,
traits::{BlakeTwo256, IdentifyAccount, Verify},
MultiAddress, MultiSignature,
};
use polkadot_parachain_primitives::primitives::Id as ParaId;
use polkadot_runtime_parachains::{
@@ -43,38 +47,29 @@ use xcm_builder::{
};
use xcm_executor::{Config, XcmExecutor};
pub type AccountId = AccountId32;
pub type SignedExtra = (frame_system::CheckNonZeroSender<Runtime>,);
pub type BlockNumber = u64;
pub type Address = MultiAddress<AccountId, ()>;
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
pub type UncheckedExtrinsic =
generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>;
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
pub type Signature = MultiSignature;
pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
pub type Balance = u128;
parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const BlockHashCount: u32 = 250;
}
#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
impl frame_system::Config for Runtime {
type RuntimeOrigin = RuntimeOrigin;
type RuntimeCall = RuntimeCall;
type Nonce = u64;
type Hash = H256;
type Hashing = ::sp_runtime::traits::BlakeTwo256;
type AccountId = AccountId;
type Lookup = IdentityLookup<Self::AccountId>;
type Lookup = sp_runtime::traits::AccountIdLookup<AccountId, ()>;
type Block = Block;
type RuntimeEvent = RuntimeEvent;
type BlockHashCount = BlockHashCount;
type BlockWeights = ();
type BlockLength = ();
type Version = ();
type PalletInfo = PalletInfo;
type AccountData = pallet_balances::AccountData<Balance>;
type OnNewAccount = ();
type OnKilledAccount = ();
type DbWeight = ();
type BaseCallFilter = Everything;
type SystemWeightInfo = ();
type SS58Prefix = ();
type OnSetCode = ();
type MaxConsumers = ConstU32<16>;
}
parameter_types! {
@@ -202,8 +197,6 @@ parameter_types! {
impl origin::Config for Runtime {}
type Block = frame_system::mocking::MockBlock<Runtime>;
parameter_types! {
/// Amount of weight that can be spent per block to service messages.
pub MessageQueueServiceWeight: Weight = Weight::from_parts(1_000_000_000, 1_000_000);