mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 10:31:03 +00:00
Add xcm fuzzer (#3869)
* Extend xcm-simulator with a fuzzer for xcm exec This commit adds a very basic fuzzer that fuzzes the xcm exectution, in particular the process_instruction function. * Update cargo.toml in xcm-simulator-fuzzer * Add xcm-fuzzer to honggfuzz workflow * Update Cargo.lock * Update xcm/xcm-simulator/fuzzer/Cargo.toml so honggfuzz shows up on top Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> * Update relay_chain.rs in xcm-fuzzer * Use MAX_XCM_DECODE_DEPTH instead of hardcoded decode limit in xcm-fuzzer * Add comment on how to generate coverage report in xcm-fuzzer * fix warnings, fmt, and unused result * fix compiler Co-authored-by: Vincent Ulitzsch <vincent.ulitzsch@srlabs.de> Co-authored-by: Vincent Ulitzsch <vincent@srlabs.de> Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>
This commit is contained in:
+39
@@ -5,6 +5,45 @@ on:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
jobs:
|
||||
xcm-fuzzer:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Install minimal stable Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: stable
|
||||
override: true
|
||||
|
||||
- name: Install minimal nightly Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly
|
||||
target: wasm32-unknown-unknown
|
||||
|
||||
- name: Install honggfuzz deps
|
||||
run: sudo apt-get install --no-install-recommends binutils-dev libunwind8-dev
|
||||
|
||||
- name: Install honggfuzz
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: install
|
||||
args: honggfuzz --version "0.5.54"
|
||||
|
||||
- name: Build fuzzer binaries
|
||||
working-directory: xcm/xcm-simulator/fuzzer/
|
||||
run: cargo hfuzz build
|
||||
|
||||
- name: Run fuzzer
|
||||
working-directory: xcm/xcm-simulator/fuzzer/
|
||||
run: bash $GITHUB_WORKSPACE/scripts/github/run_fuzzer.sh xcm-fuzzer
|
||||
|
||||
erasure-coding-round-trip:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
Generated
+51
@@ -121,6 +121,12 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "577b08a4acd7b99869f863c50011b01eb73424ccc798ecd996f2e24817adfca7"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.6"
|
||||
@@ -2603,6 +2609,17 @@ dependencies = [
|
||||
"hmac 0.8.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "honggfuzz"
|
||||
version = "0.5.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bea09577d948a98a5f59b7c891e274c4fb35ad52f67782b3d0cb53b9c05301f1"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"lazy_static",
|
||||
"memmap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hostname"
|
||||
version = "0.3.1"
|
||||
@@ -4043,6 +4060,16 @@ version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "memmap"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.2.0"
|
||||
@@ -11886,6 +11913,30 @@ dependencies = [
|
||||
"xcm-simulator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xcm-simulator-fuzzer"
|
||||
version = "0.9.9"
|
||||
dependencies = [
|
||||
"frame-support",
|
||||
"frame-system",
|
||||
"honggfuzz",
|
||||
"pallet-balances",
|
||||
"pallet-xcm",
|
||||
"parity-scale-codec",
|
||||
"polkadot-core-primitives",
|
||||
"polkadot-parachain",
|
||||
"polkadot-runtime-parachains",
|
||||
"scale-info",
|
||||
"sp-core",
|
||||
"sp-io",
|
||||
"sp-runtime",
|
||||
"sp-std",
|
||||
"xcm",
|
||||
"xcm-builder",
|
||||
"xcm-executor",
|
||||
"xcm-simulator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yamux"
|
||||
version = "0.9.0"
|
||||
|
||||
@@ -42,6 +42,7 @@ members = [
|
||||
"xcm/xcm-executor/integration-tests",
|
||||
"xcm/xcm-simulator",
|
||||
"xcm/xcm-simulator/example",
|
||||
"xcm/xcm-simulator/fuzzer",
|
||||
"xcm/pallet-xcm",
|
||||
"xcm/pallet-xcm-benchmarks",
|
||||
"xcm/procedural",
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
[package]
|
||||
name = "xcm-simulator-fuzzer"
|
||||
version = "0.9.9"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
description = "Examples of xcm-simulator usage."
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
codec = { package = "parity-scale-codec", version = "2.0.0" }
|
||||
honggfuzz = "0.5.54"
|
||||
scale-info = { version = "1.0", features = ["derive"] }
|
||||
|
||||
frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
xcm = { path = "../../" }
|
||||
xcm-simulator = { path = "../" }
|
||||
xcm-executor = { path = "../../xcm-executor" }
|
||||
xcm-builder = { path = "../../xcm-builder" }
|
||||
pallet-xcm = { path = "../../pallet-xcm" }
|
||||
polkadot-core-primitives = { path = "../../../core-primitives" }
|
||||
polkadot-runtime-parachains = { path = "../../../runtime/parachains" }
|
||||
polkadot-parachain = { path = "../../../parachain" }
|
||||
|
||||
[[bin]]
|
||||
path = "src/fuzz.rs"
|
||||
name = "xcm-fuzzer"
|
||||
@@ -0,0 +1,166 @@
|
||||
// Copyright 2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Polkadot.
|
||||
|
||||
// Polkadot is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Polkadot is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
mod parachain;
|
||||
mod relay_chain;
|
||||
|
||||
use codec::DecodeLimit;
|
||||
use polkadot_parachain::primitives::Id as ParaId;
|
||||
use sp_runtime::traits::AccountIdConversion;
|
||||
use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt};
|
||||
|
||||
use frame_support::assert_ok;
|
||||
use xcm::{latest::prelude::*, MAX_XCM_DECODE_DEPTH};
|
||||
|
||||
pub const ALICE: sp_runtime::AccountId32 = sp_runtime::AccountId32::new([0u8; 32]);
|
||||
pub const INITIAL_BALANCE: u128 = 1_000_000_000;
|
||||
|
||||
decl_test_parachain! {
|
||||
pub struct ParaA {
|
||||
Runtime = parachain::Runtime,
|
||||
XcmpMessageHandler = parachain::MsgQueue,
|
||||
DmpMessageHandler = parachain::MsgQueue,
|
||||
new_ext = para_ext(1),
|
||||
}
|
||||
}
|
||||
|
||||
decl_test_parachain! {
|
||||
pub struct ParaB {
|
||||
Runtime = parachain::Runtime,
|
||||
XcmpMessageHandler = parachain::MsgQueue,
|
||||
DmpMessageHandler = parachain::MsgQueue,
|
||||
new_ext = para_ext(2),
|
||||
}
|
||||
}
|
||||
|
||||
decl_test_relay_chain! {
|
||||
pub struct Relay {
|
||||
Runtime = relay_chain::Runtime,
|
||||
XcmConfig = relay_chain::XcmConfig,
|
||||
new_ext = relay_ext(),
|
||||
}
|
||||
}
|
||||
|
||||
decl_test_network! {
|
||||
pub struct MockNet {
|
||||
relay_chain = Relay,
|
||||
parachains = vec![
|
||||
(1, ParaA),
|
||||
(2, ParaB),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn para_account_id(id: u32) -> relay_chain::AccountId {
|
||||
ParaId::from(id).into_account()
|
||||
}
|
||||
|
||||
pub fn para_ext(para_id: u32) -> sp_io::TestExternalities {
|
||||
use parachain::{MsgQueue, Runtime, System};
|
||||
|
||||
let mut t = frame_system::GenesisConfig::default().build_storage::<Runtime>().unwrap();
|
||||
|
||||
pallet_balances::GenesisConfig::<Runtime> { balances: vec![(ALICE, INITIAL_BALANCE)] }
|
||||
.assimilate_storage(&mut t)
|
||||
.unwrap();
|
||||
|
||||
let mut ext = sp_io::TestExternalities::new(t);
|
||||
ext.execute_with(|| {
|
||||
System::set_block_number(1);
|
||||
MsgQueue::set_para_id(para_id.into());
|
||||
});
|
||||
ext
|
||||
}
|
||||
|
||||
pub fn relay_ext() -> sp_io::TestExternalities {
|
||||
use relay_chain::{Runtime, System};
|
||||
|
||||
let mut t = frame_system::GenesisConfig::default().build_storage::<Runtime>().unwrap();
|
||||
|
||||
pallet_balances::GenesisConfig::<Runtime> {
|
||||
balances: vec![(ALICE, INITIAL_BALANCE), (para_account_id(1), INITIAL_BALANCE)],
|
||||
}
|
||||
.assimilate_storage(&mut t)
|
||||
.unwrap();
|
||||
|
||||
let mut ext = sp_io::TestExternalities::new(t);
|
||||
ext.execute_with(|| System::set_block_number(1));
|
||||
ext
|
||||
}
|
||||
|
||||
pub type RelayChainPalletXcm = pallet_xcm::Pallet<relay_chain::Runtime>;
|
||||
pub type ParachainPalletXcm = pallet_xcm::Pallet<parachain::Runtime>;
|
||||
|
||||
fn run_one_input(data: &[u8]) {
|
||||
MockNet::reset();
|
||||
if let Ok(m) = Xcm::decode_all_with_depth_limit(MAX_XCM_DECODE_DEPTH, data) {
|
||||
#[cfg(not(fuzzing))]
|
||||
{
|
||||
println!("Executing message {:?}", m);
|
||||
}
|
||||
ParaA::execute_with(|| {
|
||||
assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, m));
|
||||
});
|
||||
Relay::execute_with(|| {});
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
#[cfg(fuzzing)]
|
||||
{
|
||||
loop {
|
||||
fuzz!(|data: &[u8]| {
|
||||
run_one_input(data);
|
||||
});
|
||||
}
|
||||
}
|
||||
#[cfg(not(fuzzing))]
|
||||
{
|
||||
//This code path can be used to generate a line-code coverage report in html
|
||||
//that depicts which lines are executed by at least one input in the current fuzzing queue.
|
||||
//To generate this code coverage report, run the following commands:
|
||||
/*
|
||||
```
|
||||
export CARGO_INCREMENTAL=0
|
||||
export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort"
|
||||
export RUSTDOCFLAGS="-Cpanic=abort"
|
||||
rustup override set nightly
|
||||
SKIP_WASM_BUILD=1 cargo build
|
||||
./xcm/xcm-simulator/fuzzer/target/debug/xcm-fuzzer hfuzz_workspace/xcm-fuzzer/input
|
||||
zip -0 ccov.zip `find ../../target/debug \( -name "*.gc*" -o -name "test-*.gc*" \) -print`
|
||||
grcov ccov.zip -s / -t html --llvm --branch --ignore-not-existing -o ../../target/debug/coverage/
|
||||
```
|
||||
*/
|
||||
use std::{env, fs, fs::File, io::Read};
|
||||
let args: Vec<_> = env::args().collect();
|
||||
let md = fs::metadata(&args[1]).unwrap();
|
||||
let all_files = match md.is_dir() {
|
||||
true => fs::read_dir(&args[1])
|
||||
.unwrap()
|
||||
.map(|x| x.unwrap().path().to_str().unwrap().to_string())
|
||||
.collect::<Vec<String>>(),
|
||||
false => (&args[1..]).to_vec(),
|
||||
};
|
||||
println!("All_files {:?}", all_files);
|
||||
for argument in all_files {
|
||||
println!("Now doing file {:?}", argument);
|
||||
let mut buffer: Vec<u8> = Vec::new();
|
||||
let mut f = File::open(argument).unwrap();
|
||||
f.read_to_end(&mut buffer).unwrap();
|
||||
run_one_input(&buffer.as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,327 @@
|
||||
// Copyright 2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Polkadot.
|
||||
|
||||
// Polkadot is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Polkadot is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Parachain runtime mock.
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
use frame_support::{
|
||||
construct_runtime, parameter_types,
|
||||
traits::{Everything, Nothing},
|
||||
weights::{constants::WEIGHT_PER_SECOND, Weight},
|
||||
};
|
||||
use sp_core::H256;
|
||||
use sp_runtime::{
|
||||
testing::Header,
|
||||
traits::{Hash, IdentityLookup},
|
||||
AccountId32,
|
||||
};
|
||||
use sp_std::{convert::TryFrom, prelude::*};
|
||||
|
||||
use pallet_xcm::XcmPassthrough;
|
||||
use polkadot_core_primitives::BlockNumber as RelayBlockNumber;
|
||||
use polkadot_parachain::primitives::{
|
||||
DmpMessageHandler, Id as ParaId, Sibling, XcmpMessageFormat, XcmpMessageHandler,
|
||||
};
|
||||
use xcm::{latest::prelude::*, VersionedXcm};
|
||||
use xcm_builder::{
|
||||
AccountId32Aliases, AllowUnpaidExecutionFrom, CurrencyAdapter as XcmCurrencyAdapter,
|
||||
EnsureXcmOrigin, FixedRateOfFungible, FixedWeightBounds, IsConcrete, LocationInverter,
|
||||
NativeAsset, ParentIsDefault, SiblingParachainConvertsVia, SignedAccountId32AsNative,
|
||||
SignedToAccountId32, SovereignSignedViaLocation,
|
||||
};
|
||||
use xcm_executor::{Config, XcmExecutor};
|
||||
|
||||
pub type AccountId = AccountId32;
|
||||
pub type Balance = u128;
|
||||
|
||||
parameter_types! {
|
||||
pub const BlockHashCount: u64 = 250;
|
||||
}
|
||||
|
||||
impl frame_system::Config for Runtime {
|
||||
type Origin = Origin;
|
||||
type Call = Call;
|
||||
type Index = u64;
|
||||
type BlockNumber = u64;
|
||||
type Hash = H256;
|
||||
type Hashing = ::sp_runtime::traits::BlakeTwo256;
|
||||
type AccountId = AccountId;
|
||||
type Lookup = IdentityLookup<Self::AccountId>;
|
||||
type Header = Header;
|
||||
type Event = Event;
|
||||
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 = ();
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub ExistentialDeposit: Balance = 1;
|
||||
pub const MaxLocks: u32 = 50;
|
||||
pub const MaxReserves: u32 = 50;
|
||||
}
|
||||
|
||||
impl pallet_balances::Config for Runtime {
|
||||
type MaxLocks = MaxLocks;
|
||||
type Balance = Balance;
|
||||
type Event = Event;
|
||||
type DustRemoval = ();
|
||||
type ExistentialDeposit = ExistentialDeposit;
|
||||
type AccountStore = System;
|
||||
type WeightInfo = ();
|
||||
type MaxReserves = MaxReserves;
|
||||
type ReserveIdentifier = [u8; 8];
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const ReservedXcmpWeight: Weight = WEIGHT_PER_SECOND / 4;
|
||||
pub const ReservedDmpWeight: Weight = WEIGHT_PER_SECOND / 4;
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const KsmLocation: MultiLocation = MultiLocation::parent();
|
||||
pub const RelayNetwork: NetworkId = NetworkId::Kusama;
|
||||
pub Ancestry: MultiLocation = Parachain(MsgQueue::parachain_id().into()).into();
|
||||
}
|
||||
|
||||
pub type LocationToAccountId = (
|
||||
ParentIsDefault<AccountId>,
|
||||
SiblingParachainConvertsVia<Sibling, AccountId>,
|
||||
AccountId32Aliases<RelayNetwork, AccountId>,
|
||||
);
|
||||
|
||||
pub type XcmOriginToCallOrigin = (
|
||||
SovereignSignedViaLocation<LocationToAccountId, Origin>,
|
||||
SignedAccountId32AsNative<RelayNetwork, Origin>,
|
||||
XcmPassthrough<Origin>,
|
||||
);
|
||||
|
||||
parameter_types! {
|
||||
pub const UnitWeightCost: Weight = 1;
|
||||
pub KsmPerSecond: (AssetId, u128) = (Concrete(Parent.into()), 1);
|
||||
pub const MaxInstructions: u32 = 100;
|
||||
}
|
||||
|
||||
pub type LocalAssetTransactor =
|
||||
XcmCurrencyAdapter<Balances, IsConcrete<KsmLocation>, LocationToAccountId, AccountId, ()>;
|
||||
|
||||
pub type XcmRouter = super::ParachainXcmRouter<MsgQueue>;
|
||||
pub type Barrier = AllowUnpaidExecutionFrom<Everything>;
|
||||
|
||||
pub struct XcmConfig;
|
||||
impl Config for XcmConfig {
|
||||
type Call = Call;
|
||||
type XcmSender = XcmRouter;
|
||||
type AssetTransactor = LocalAssetTransactor;
|
||||
type OriginConverter = XcmOriginToCallOrigin;
|
||||
type IsReserve = NativeAsset;
|
||||
type IsTeleporter = ();
|
||||
type LocationInverter = LocationInverter<Ancestry>;
|
||||
type Barrier = Barrier;
|
||||
type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
|
||||
type Trader = FixedRateOfFungible<KsmPerSecond, ()>;
|
||||
type ResponseHandler = ();
|
||||
type AssetTrap = ();
|
||||
type AssetClaims = ();
|
||||
type SubscriptionService = ();
|
||||
}
|
||||
|
||||
#[frame_support::pallet]
|
||||
pub mod mock_msg_queue {
|
||||
use super::*;
|
||||
use frame_support::pallet_prelude::*;
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {
|
||||
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
|
||||
type XcmExecutor: ExecuteXcm<Self::Call>;
|
||||
}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {}
|
||||
|
||||
#[pallet::pallet]
|
||||
#[pallet::generate_store(pub(super) trait Store)]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn parachain_id)]
|
||||
pub(super) type ParachainId<T: Config> = StorageValue<_, ParaId, ValueQuery>;
|
||||
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn received_dmp)]
|
||||
/// A queue of received DMP messages
|
||||
pub(super) type ReceivedDmp<T: Config> = StorageValue<_, Vec<Xcm<T::Call>>, ValueQuery>;
|
||||
|
||||
impl<T: Config> Get<ParaId> for Pallet<T> {
|
||||
fn get() -> ParaId {
|
||||
Self::parachain_id()
|
||||
}
|
||||
}
|
||||
|
||||
pub type MessageId = [u8; 32];
|
||||
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
// XCMP
|
||||
/// Some XCM was executed OK.
|
||||
Success(Option<T::Hash>),
|
||||
/// Some XCM failed.
|
||||
Fail(Option<T::Hash>, XcmError),
|
||||
/// Bad XCM version used.
|
||||
BadVersion(Option<T::Hash>),
|
||||
/// Bad XCM format used.
|
||||
BadFormat(Option<T::Hash>),
|
||||
|
||||
// DMP
|
||||
/// Downward message is invalid XCM.
|
||||
InvalidFormat(MessageId),
|
||||
/// Downward message is unsupported version of XCM.
|
||||
UnsupportedVersion(MessageId),
|
||||
/// Downward message executed with the given outcome.
|
||||
ExecutedDownward(MessageId, Outcome),
|
||||
}
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
pub fn set_para_id(para_id: ParaId) {
|
||||
ParachainId::<T>::put(para_id);
|
||||
}
|
||||
|
||||
fn handle_xcmp_message(
|
||||
sender: ParaId,
|
||||
_sent_at: RelayBlockNumber,
|
||||
xcm: VersionedXcm<T::Call>,
|
||||
max_weight: Weight,
|
||||
) -> Result<Weight, XcmError> {
|
||||
let hash = Encode::using_encoded(&xcm, T::Hashing::hash);
|
||||
let (result, event) = match Xcm::<T::Call>::try_from(xcm) {
|
||||
Ok(xcm) => {
|
||||
let location = MultiLocation::new(1, X1(Parachain(sender.into())));
|
||||
match T::XcmExecutor::execute_xcm(location, xcm, max_weight) {
|
||||
Outcome::Error(e) => (Err(e.clone()), Event::Fail(Some(hash), e)),
|
||||
Outcome::Complete(w) => (Ok(w), Event::Success(Some(hash))),
|
||||
// As far as the caller is concerned, this was dispatched without error, so
|
||||
// we just report the weight used.
|
||||
Outcome::Incomplete(w, e) => (Ok(w), Event::Fail(Some(hash), e)),
|
||||
}
|
||||
},
|
||||
Err(()) => (Err(XcmError::UnhandledXcmVersion), Event::BadVersion(Some(hash))),
|
||||
};
|
||||
Self::deposit_event(event);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> XcmpMessageHandler for Pallet<T> {
|
||||
fn handle_xcmp_messages<'a, I: Iterator<Item = (ParaId, RelayBlockNumber, &'a [u8])>>(
|
||||
iter: I,
|
||||
max_weight: Weight,
|
||||
) -> Weight {
|
||||
for (sender, sent_at, data) in iter {
|
||||
let mut data_ref = data;
|
||||
let _ = XcmpMessageFormat::decode(&mut data_ref)
|
||||
.expect("Simulator encodes with versioned xcm format; qed");
|
||||
|
||||
let mut remaining_fragments = &data_ref[..];
|
||||
while !remaining_fragments.is_empty() {
|
||||
if let Ok(xcm) = VersionedXcm::<T::Call>::decode(&mut remaining_fragments) {
|
||||
let _ = Self::handle_xcmp_message(sender, sent_at, xcm, max_weight);
|
||||
} else {
|
||||
debug_assert!(false, "Invalid incoming XCMP message data");
|
||||
}
|
||||
}
|
||||
}
|
||||
max_weight
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> DmpMessageHandler for Pallet<T> {
|
||||
fn handle_dmp_messages(
|
||||
iter: impl Iterator<Item = (RelayBlockNumber, Vec<u8>)>,
|
||||
limit: Weight,
|
||||
) -> Weight {
|
||||
for (_i, (_sent_at, data)) in iter.enumerate() {
|
||||
let id = sp_io::hashing::blake2_256(&data[..]);
|
||||
let maybe_msg =
|
||||
VersionedXcm::<T::Call>::decode(&mut &data[..]).map(Xcm::<T::Call>::try_from);
|
||||
match maybe_msg {
|
||||
Err(_) => {
|
||||
Self::deposit_event(Event::InvalidFormat(id));
|
||||
},
|
||||
Ok(Err(())) => {
|
||||
Self::deposit_event(Event::UnsupportedVersion(id));
|
||||
},
|
||||
Ok(Ok(x)) => {
|
||||
let outcome = T::XcmExecutor::execute_xcm(Parent, x.clone(), limit);
|
||||
<ReceivedDmp<T>>::append(x);
|
||||
Self::deposit_event(Event::ExecutedDownward(id, outcome));
|
||||
},
|
||||
}
|
||||
}
|
||||
limit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl mock_msg_queue::Config for Runtime {
|
||||
type Event = Event;
|
||||
type XcmExecutor = XcmExecutor<XcmConfig>;
|
||||
}
|
||||
|
||||
pub type LocalOriginToLocation = SignedToAccountId32<Origin, AccountId, RelayNetwork>;
|
||||
|
||||
impl pallet_xcm::Config for Runtime {
|
||||
type Event = Event;
|
||||
type SendXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
|
||||
type XcmRouter = XcmRouter;
|
||||
type ExecuteXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
|
||||
type XcmExecuteFilter = Everything;
|
||||
type XcmExecutor = XcmExecutor<XcmConfig>;
|
||||
type XcmTeleportFilter = Nothing;
|
||||
type XcmReserveTransferFilter = Everything;
|
||||
type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
|
||||
type LocationInverter = LocationInverter<Ancestry>;
|
||||
type Origin = Origin;
|
||||
type Call = Call;
|
||||
const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
|
||||
type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
|
||||
}
|
||||
|
||||
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Runtime>;
|
||||
type Block = frame_system::mocking::MockBlock<Runtime>;
|
||||
|
||||
construct_runtime!(
|
||||
pub enum Runtime where
|
||||
Block = Block,
|
||||
NodeBlock = Block,
|
||||
UncheckedExtrinsic = UncheckedExtrinsic,
|
||||
{
|
||||
System: frame_system::{Pallet, Call, Storage, Config, Event<T>},
|
||||
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
|
||||
MsgQueue: mock_msg_queue::{Pallet, Storage, Event<T>},
|
||||
PolkadotXcm: pallet_xcm::{Pallet, Call, Event<T>, Origin},
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,191 @@
|
||||
// Copyright 2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Polkadot.
|
||||
|
||||
// Polkadot is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Polkadot is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Relay chain runtime mock.
|
||||
|
||||
use frame_support::{
|
||||
construct_runtime, parameter_types,
|
||||
traits::{Everything, Nothing},
|
||||
weights::Weight,
|
||||
};
|
||||
use sp_core::H256;
|
||||
use sp_runtime::{testing::Header, traits::IdentityLookup, AccountId32};
|
||||
|
||||
use polkadot_parachain::primitives::Id as ParaId;
|
||||
use polkadot_runtime_parachains::{configuration, origin, shared, ump};
|
||||
use xcm::latest::prelude::*;
|
||||
use xcm_builder::{
|
||||
AccountId32Aliases, AllowUnpaidExecutionFrom, ChildParachainAsNative,
|
||||
ChildParachainConvertsVia, ChildSystemParachainAsSuperuser,
|
||||
CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible, FixedWeightBounds, IsConcrete,
|
||||
LocationInverter, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation,
|
||||
};
|
||||
use xcm_executor::{Config, XcmExecutor};
|
||||
|
||||
pub type AccountId = AccountId32;
|
||||
pub type Balance = u128;
|
||||
|
||||
parameter_types! {
|
||||
pub const BlockHashCount: u64 = 250;
|
||||
}
|
||||
|
||||
impl frame_system::Config for Runtime {
|
||||
type Origin = Origin;
|
||||
type Call = Call;
|
||||
type Index = u64;
|
||||
type BlockNumber = u64;
|
||||
type Hash = H256;
|
||||
type Hashing = ::sp_runtime::traits::BlakeTwo256;
|
||||
type AccountId = AccountId;
|
||||
type Lookup = IdentityLookup<Self::AccountId>;
|
||||
type Header = Header;
|
||||
type Event = Event;
|
||||
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 = ();
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub ExistentialDeposit: Balance = 1;
|
||||
pub const MaxLocks: u32 = 50;
|
||||
pub const MaxReserves: u32 = 50;
|
||||
}
|
||||
|
||||
impl pallet_balances::Config for Runtime {
|
||||
type MaxLocks = MaxLocks;
|
||||
type Balance = Balance;
|
||||
type Event = Event;
|
||||
type DustRemoval = ();
|
||||
type ExistentialDeposit = ExistentialDeposit;
|
||||
type AccountStore = System;
|
||||
type WeightInfo = ();
|
||||
type MaxReserves = MaxReserves;
|
||||
type ReserveIdentifier = [u8; 8];
|
||||
}
|
||||
|
||||
impl shared::Config for Runtime {}
|
||||
|
||||
impl configuration::Config for Runtime {
|
||||
type WeightInfo = configuration::TestWeightInfo;
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const KsmLocation: MultiLocation = Here.into();
|
||||
pub const KusamaNetwork: NetworkId = NetworkId::Kusama;
|
||||
pub const AnyNetwork: NetworkId = NetworkId::Any;
|
||||
pub Ancestry: MultiLocation = Here.into();
|
||||
pub UnitWeightCost: Weight = 1_000;
|
||||
}
|
||||
|
||||
pub type SovereignAccountOf =
|
||||
(ChildParachainConvertsVia<ParaId, AccountId>, AccountId32Aliases<KusamaNetwork, AccountId>);
|
||||
|
||||
pub type LocalAssetTransactor =
|
||||
XcmCurrencyAdapter<Balances, IsConcrete<KsmLocation>, SovereignAccountOf, AccountId, ()>;
|
||||
|
||||
type LocalOriginConverter = (
|
||||
SovereignSignedViaLocation<SovereignAccountOf, Origin>,
|
||||
ChildParachainAsNative<origin::Origin, Origin>,
|
||||
SignedAccountId32AsNative<KusamaNetwork, Origin>,
|
||||
ChildSystemParachainAsSuperuser<ParaId, Origin>,
|
||||
);
|
||||
|
||||
parameter_types! {
|
||||
pub const BaseXcmWeight: Weight = 1_000;
|
||||
pub KsmPerSecond: (AssetId, u128) = (Concrete(KsmLocation::get()), 1);
|
||||
pub const MaxInstructions: u32 = 100;
|
||||
}
|
||||
|
||||
pub type XcmRouter = super::RelayChainXcmRouter;
|
||||
pub type Barrier = AllowUnpaidExecutionFrom<Everything>;
|
||||
|
||||
pub struct XcmConfig;
|
||||
impl Config for XcmConfig {
|
||||
type Call = Call;
|
||||
type XcmSender = XcmRouter;
|
||||
type AssetTransactor = LocalAssetTransactor;
|
||||
type OriginConverter = LocalOriginConverter;
|
||||
type IsReserve = ();
|
||||
type IsTeleporter = ();
|
||||
type LocationInverter = LocationInverter<Ancestry>;
|
||||
type Barrier = Barrier;
|
||||
type Weigher = FixedWeightBounds<BaseXcmWeight, Call, MaxInstructions>;
|
||||
type Trader = FixedRateOfFungible<KsmPerSecond, ()>;
|
||||
type ResponseHandler = ();
|
||||
type AssetTrap = ();
|
||||
type AssetClaims = ();
|
||||
type SubscriptionService = ();
|
||||
}
|
||||
|
||||
pub type LocalOriginToLocation = SignedToAccountId32<Origin, AccountId, KusamaNetwork>;
|
||||
|
||||
impl pallet_xcm::Config for Runtime {
|
||||
type Event = Event;
|
||||
type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<Origin, LocalOriginToLocation>;
|
||||
type XcmRouter = XcmRouter;
|
||||
// Anyone can execute XCM messages locally...
|
||||
type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin<Origin, LocalOriginToLocation>;
|
||||
type XcmExecuteFilter = Nothing;
|
||||
type XcmExecutor = XcmExecutor<XcmConfig>;
|
||||
type XcmTeleportFilter = Everything;
|
||||
type XcmReserveTransferFilter = Everything;
|
||||
type Weigher = FixedWeightBounds<BaseXcmWeight, Call, MaxInstructions>;
|
||||
type LocationInverter = LocationInverter<Ancestry>;
|
||||
type Origin = Origin;
|
||||
type Call = Call;
|
||||
const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
|
||||
type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const FirstMessageFactorPercent: u64 = 100;
|
||||
}
|
||||
|
||||
impl ump::Config for Runtime {
|
||||
type Event = Event;
|
||||
type UmpSink = ump::XcmSink<XcmExecutor<XcmConfig>, Runtime>;
|
||||
type FirstMessageFactorPercent = FirstMessageFactorPercent;
|
||||
type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
|
||||
}
|
||||
|
||||
impl origin::Config for Runtime {}
|
||||
|
||||
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Runtime>;
|
||||
type Block = frame_system::mocking::MockBlock<Runtime>;
|
||||
|
||||
construct_runtime!(
|
||||
pub enum Runtime where
|
||||
Block = Block,
|
||||
NodeBlock = Block,
|
||||
UncheckedExtrinsic = UncheckedExtrinsic,
|
||||
{
|
||||
System: frame_system::{Pallet, Call, Storage, Config, Event<T>},
|
||||
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
|
||||
ParasOrigin: origin::{Pallet, Origin},
|
||||
ParasUmp: ump::{Pallet, Call, Storage, Event},
|
||||
XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event<T>, Origin},
|
||||
}
|
||||
);
|
||||
Reference in New Issue
Block a user