Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add try_state and integrity_test to XCM simulator fuzzer #3222

Merged
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.lock

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

16 changes: 16 additions & 0 deletions polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,16 @@ 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" }
sp-core = { path = "../../../../substrate/primitives/core" }
sp-runtime = { path = "../../../../substrate/primitives/runtime" }
sp-io = { path = "../../../../substrate/primitives/io" }
sp-api = { path = "../../../../substrate/primitives/api" }
sp-version = { path = "../../../../substrate/primitives/version" }

xcm = { package = "staging-xcm", path = "../.." }
xcm-simulator = { path = ".." }
Expand All @@ -35,6 +39,18 @@ polkadot-runtime-parachains = { path = "../../../runtime/parachains" }
polkadot-parachain-primitives = { path = "../../../parachain" }

[features]
default = ["try-runtime"]
ggwpez marked this conversation as resolved.
Show resolved Hide resolved
try-runtime = [
"frame-support/try-runtime",
"frame-try-runtime/try-runtime",
"frame-executive/try-runtime",
"frame-system/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",
Expand Down
49 changes: 46 additions & 3 deletions polkadot/xcm/xcm-simulator/fuzzer/src/fuzz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ 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;
use frame_support::{
assert_ok,
traits::{IntegrityTest, TryState, TryStateSelect::All},
};
use xcm::{latest::prelude::*, MAX_XCM_DECODE_DEPTH};

use arbitrary::{Arbitrary, Error, Unstructured};
Expand Down Expand Up @@ -98,7 +101,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)
}
Expand Down Expand Up @@ -155,6 +158,34 @@ fn run_input(xcm_messages: [XcmMessage; 5]) {
println!();

for xcm_message in xcm_messages {
fn matches_blocklisted_messages(message: Instruction<()>) -> bool {
matches!(message, Transact { .. })
}
// We check XCM messages recursively for blocklisted messages
fn matches_recursive(message: &mut Instruction<()>) -> Vec<Instruction<()>> {
ggwpez marked this conversation as resolved.
Show resolved Hide resolved
match message {
DepositReserveAsset { xcm, .. } |
ExportMessage { xcm, .. } |
InitiateReserveWithdraw { xcm, .. } |
InitiateTeleport { xcm, .. } |
TransferReserveAsset { xcm, .. } |
SetErrorHandler(xcm) |
SetAppendix(xcm) => Vec::from(xcm.inner()).iter_mut().flat_map(matches_recursive).collect(),
_ => vec![message.clone()],
Copy link
Member

@ggwpez ggwpez Feb 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, this function is called matches_recursive, but it dies not call the matches_blocklisted_messages?
To me it looks like it unpacks them.
You can also probably do both functions in one and just add a Transact { } here, then there are no vector instructions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be addressed

}
}

if xcm_message
.message
.clone()
.iter_mut()
.flat_map(matches_recursive)
.any(|m| matches_blocklisted_messages(m))
{
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;
Expand Down Expand Up @@ -197,8 +228,20 @@ 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(|| {
parachain::AllPalletsWithSystem::try_state(Default::default(), All).unwrap();
ggwpez marked this conversation as resolved.
Show resolved Hide resolved
parachain::AllPalletsWithSystem::integrity_test();
});
},
);
Relay::execute_with(|| {
relay_chain::AllPalletsWithSystem::try_state(Default::default(), All).unwrap();
relay_chain::AllPalletsWithSystem::integrity_test();
});
}
Relay::execute_with(|| {});
}

fn main() {
Expand Down
95 changes: 87 additions & 8 deletions polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ use frame_support::{
use frame_system::EnsureRoot;
use sp_core::{ConstU32, H256};
use sp_runtime::{
traits::{Hash, IdentityLookup},
AccountId32,
create_runtime_str, generic,
traits::{AccountIdLookup, BlakeTwo256, Hash, IdentifyAccount, Verify},
MultiAddress, MultiSignature,
};
use sp_std::prelude::*;

Expand All @@ -36,6 +37,7 @@ use polkadot_core_primitives::BlockNumber as RelayBlockNumber;
use polkadot_parachain_primitives::primitives::{
DmpMessageHandler, Id as ParaId, Sibling, XcmpMessageFormat, XcmpMessageHandler,
};
use sp_version::RuntimeVersion;
use xcm::{latest::prelude::*, VersionedXcm};
#[allow(deprecated)]
use xcm_builder::CurrencyAdapter as XcmCurrencyAdapter;
Expand All @@ -47,11 +49,33 @@ use xcm_builder::{
};
use xcm_executor::{Config, XcmExecutor};

pub type AccountId = AccountId32;
pub type SignedExtra = (frame_system::CheckNonZeroSender<Runtime>,);

pub type BlockNumber = u32;
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;

#[allow(unused_parens)]
type Migrations = ();

pub type Executive = frame_executive::Executive<
Runtime,
Block,
frame_system::ChainContext<Runtime>,
Runtime,
AllPalletsWithSystem,
Migrations,
>;

parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const BlockHashCount: u32 = 250;
}

#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
Expand All @@ -60,9 +84,9 @@ impl frame_system::Config for Runtime {
type RuntimeCall = RuntimeCall;
type Nonce = u64;
type Hash = H256;
type Hashing = ::sp_runtime::traits::BlakeTwo256;
type Hashing = BlakeTwo256;
type AccountId = AccountId;
type Lookup = IdentityLookup<Self::AccountId>;
type Lookup = AccountIdLookup<AccountId, ()>;
ggwpez marked this conversation as resolved.
Show resolved Hide resolved
type Block = Block;
type RuntimeEvent = RuntimeEvent;
type BlockHashCount = BlockHashCount;
Expand Down Expand Up @@ -356,8 +380,6 @@ impl pallet_xcm::Config for Runtime {
type AdminOrigin = EnsureRoot<AccountId>;
}

type Block = frame_system::mocking::MockBlock<Runtime>;

construct_runtime!(
pub enum Runtime
{
Expand All @@ -367,3 +389,60 @@ construct_runtime!(
PolkadotXcm: pallet_xcm,
}
);

// To learn more about runtime versioning, see:
// https://docs.substrate.io/main-docs/build/upgrade#runtime-versioning
#[sp_version::runtime_version]
pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("node-template"),
impl_name: create_runtime_str!("node-template"),
authoring_version: 1,
// The version of the runtime specification. A full node will not attempt to use its native
// runtime in substitute for the on-chain Wasm runtime unless all of `spec_name`,
// `spec_version`, and `authoring_version` are the same between Wasm and native.
// This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use
// the compatible custom types.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can delete these comments 😆 Maybe there is also a default or a mock for testing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

spec_version: 100,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,
state_version: 1,
};

sp_api::impl_runtime_apis! {
impl sp_api::Core<Block> for Runtime {
fn version() -> RuntimeVersion {
VERSION
}

fn execute_block(block: Block) {
Executive::execute_block(block);
}

fn initialize_block(header: &<Block as sp_runtime::traits::Block>::Header) {
Executive::initialize_block(header)
}
}

#[cfg(feature = "try-runtime")]
impl frame_try_runtime::TryRuntime<Block> for Runtime {
fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) {
// NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to
// have a backtrace here. If any of the pre/post migration checks fail, we shall stop
// right here and right now.
let weight = Executive::try_runtime_upgrade(checks).unwrap();
(weight, 0.into()) // BlockWeights::get().max_block)
}

fn execute_block(
block: Block,
state_root_check: bool,
signature_check: bool,
select: frame_try_runtime::TryStateSelect
) -> Weight {
// NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to
// have a backtrace here.
Executive::try_execute_block(block, state_root_check, signature_check, select).expect("execute-block failed")
}
}
}
Loading
Loading