mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-30 08:27:55 +00:00
XCM v2: Scripting, Query responses, Exception handling and Error reporting (#3629)
* Intoduce XCM v2 Also some minor fix for v0/v1 * Minor version cleanup * Minor version cleanup * Introduce SendError for XcmSend trait to avoid cycles with having Outcome in Xcm * comment * Corrent type * Docs * Fix build * Fixes * Introduce the basic impl * Docs * Add function * Basic implementation * Weighed responses and on_report * Make XCM more script-like * Remove BuyExecution::orders * Fixes * Fixes * Fixes * Formatting * Initial draft and make pallet-xcm build * fix XCM tests * Formatting * Fixes * Formatting * spelling * Fixes * Fixes * spelling * tests for translation * extra fields to XCM pallet * Formatting * Fixes * spelling * first integration test * Another integration test * Formatting * fix tests * all tests * Fixes * Fixes * Formatting * Fixes * Fixes * Formatting * Bump * Remove unneeded structuring * add instruction * Fixes * spelling * Fixes * Fixes * Formatting * Fixes * Fixes * Formatting * Introduce and use VersionedResponse * Introduce versioning to dispatchables' params * Fixes * Formatting * Rest of merge * more work * Formatting * Basic logic * Fixes * Fixes * Add test * Fixes * Formatting * Fixes * Fixes * Fixes * Nits * Simplify * Spelling * Formatting * Return weight of unexecuted instructions in case of error as surplus * Formatting * Fixes * Test for instruction count limiting * Formatting * Docs
This commit is contained in:
@@ -21,46 +21,35 @@ use polkadot_test_client::{
|
||||
BlockBuilderExt, ClientBlockImportExt, DefaultTestClientBuilderExt, ExecutionStrategy,
|
||||
InitPolkadotBlockBuilder, TestClientBuilder, TestClientBuilderExt,
|
||||
};
|
||||
use polkadot_test_runtime::pallet_test_notifier;
|
||||
use polkadot_test_service::construct_extrinsic;
|
||||
use sp_runtime::{generic::BlockId, traits::Block};
|
||||
use sp_state_machine::InspectState;
|
||||
use xcm::{latest::prelude::*, VersionedXcm};
|
||||
use xcm_executor::MAX_RECURSION_LIMIT;
|
||||
|
||||
// This is the inflection point where the test should either fail or pass.
|
||||
const MAX_RECURSION_CHECK: u32 = MAX_RECURSION_LIMIT / 2;
|
||||
use xcm::{latest::prelude::*, VersionedResponse, VersionedXcm};
|
||||
|
||||
#[test]
|
||||
fn execute_within_recursion_limit() {
|
||||
fn basic_buy_fees_message_executes() {
|
||||
sp_tracing::try_init_simple();
|
||||
let mut client = TestClientBuilder::new()
|
||||
.set_execution_strategy(ExecutionStrategy::AlwaysWasm)
|
||||
.build();
|
||||
|
||||
let mut msg = WithdrawAsset { assets: (Parent, 100).into(), effects: vec![] };
|
||||
for _ in 0..MAX_RECURSION_CHECK {
|
||||
msg = WithdrawAsset {
|
||||
assets: (Parent, 100).into(),
|
||||
effects: vec![Order::BuyExecution {
|
||||
fees: (Parent, 1).into(),
|
||||
weight: 0,
|
||||
debt: 0,
|
||||
halt_on_error: true,
|
||||
// nest `msg` into itself on each iteration.
|
||||
instructions: vec![msg],
|
||||
}],
|
||||
};
|
||||
}
|
||||
let msg = Xcm(vec![
|
||||
WithdrawAsset((Parent, 100).into()),
|
||||
BuyExecution { fees: (Parent, 1).into(), weight_limit: Unlimited },
|
||||
DepositAsset { assets: Wild(All), max_assets: 1, beneficiary: Parent.into() },
|
||||
]);
|
||||
|
||||
let mut block_builder = client.init_polkadot_block_builder();
|
||||
|
||||
let execute = construct_extrinsic(
|
||||
&client,
|
||||
polkadot_test_runtime::Call::Xcm(pallet_xcm::Call::execute(
|
||||
Box::new(VersionedXcm::from(msg.clone())),
|
||||
Box::new(VersionedXcm::from(msg)),
|
||||
1_000_000_000,
|
||||
)),
|
||||
sp_keyring::Sr25519Keyring::Alice,
|
||||
0,
|
||||
);
|
||||
|
||||
block_builder.push_polkadot_extrinsic(execute).expect("pushes extrinsic");
|
||||
@@ -79,42 +68,65 @@ fn execute_within_recursion_limit() {
|
||||
r.event,
|
||||
polkadot_test_runtime::Event::Xcm(pallet_xcm::Event::Attempted(Outcome::Complete(
|
||||
_
|
||||
)),),
|
||||
))),
|
||||
)));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exceed_recursion_limit() {
|
||||
fn query_response_fires() {
|
||||
use pallet_test_notifier::Event::*;
|
||||
use pallet_xcm::QueryStatus;
|
||||
use polkadot_test_runtime::Event::TestNotifier;
|
||||
|
||||
sp_tracing::try_init_simple();
|
||||
let mut client = TestClientBuilder::new()
|
||||
.set_execution_strategy(ExecutionStrategy::AlwaysWasm)
|
||||
.build();
|
||||
|
||||
let mut msg = WithdrawAsset { assets: (Parent, 100).into(), effects: vec![] };
|
||||
for _ in 0..(MAX_RECURSION_CHECK + 1) {
|
||||
msg = WithdrawAsset {
|
||||
assets: (Parent, 100).into(),
|
||||
effects: vec![Order::BuyExecution {
|
||||
fees: (Parent, 1).into(),
|
||||
weight: 0,
|
||||
debt: 0,
|
||||
halt_on_error: true,
|
||||
// nest `msg` into itself on each iteration.
|
||||
instructions: vec![msg],
|
||||
}],
|
||||
};
|
||||
}
|
||||
|
||||
let mut block_builder = client.init_polkadot_block_builder();
|
||||
|
||||
let execute = construct_extrinsic(
|
||||
&client,
|
||||
polkadot_test_runtime::Call::Xcm(pallet_xcm::Call::execute(
|
||||
Box::new(VersionedXcm::from(msg.clone())),
|
||||
1_000_000_000,
|
||||
)),
|
||||
polkadot_test_runtime::Call::TestNotifier(pallet_test_notifier::Call::prepare_new_query()),
|
||||
sp_keyring::Sr25519Keyring::Alice,
|
||||
0,
|
||||
);
|
||||
|
||||
block_builder.push_polkadot_extrinsic(execute).expect("pushes extrinsic");
|
||||
|
||||
let block = block_builder.build().expect("Finalizes the block").block;
|
||||
let block_hash = block.hash();
|
||||
|
||||
futures::executor::block_on(client.import(sp_consensus::BlockOrigin::Own, block))
|
||||
.expect("imports the block");
|
||||
|
||||
let mut query_id = None;
|
||||
client
|
||||
.state_at(&BlockId::Hash(block_hash))
|
||||
.expect("state should exist")
|
||||
.inspect_state(|| {
|
||||
for r in polkadot_test_runtime::System::events().iter() {
|
||||
match r.event {
|
||||
TestNotifier(QueryPrepared(q)) => query_id = Some(q),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
});
|
||||
let query_id = query_id.unwrap();
|
||||
|
||||
let mut block_builder = client.init_polkadot_block_builder();
|
||||
|
||||
let response = Response::ExecutionResult(Ok(()));
|
||||
let max_weight = 1_000_000;
|
||||
let msg = Xcm(vec![QueryResponse { query_id, response, max_weight }]);
|
||||
let msg = Box::new(VersionedXcm::from(msg));
|
||||
|
||||
let execute = construct_extrinsic(
|
||||
&client,
|
||||
polkadot_test_runtime::Call::Xcm(pallet_xcm::Call::execute(msg, 1_000_000_000)),
|
||||
sp_keyring::Sr25519Keyring::Alice,
|
||||
1,
|
||||
);
|
||||
|
||||
block_builder.push_polkadot_extrinsic(execute).expect("pushes extrinsic");
|
||||
@@ -131,9 +143,99 @@ fn exceed_recursion_limit() {
|
||||
.inspect_state(|| {
|
||||
assert!(polkadot_test_runtime::System::events().iter().any(|r| matches!(
|
||||
r.event,
|
||||
polkadot_test_runtime::Event::Xcm(pallet_xcm::Event::Attempted(
|
||||
Outcome::Incomplete(_, XcmError::RecursionLimitReached),
|
||||
)),
|
||||
polkadot_test_runtime::Event::Xcm(pallet_xcm::Event::ResponseReady(
|
||||
q,
|
||||
Response::ExecutionResult(Ok(())),
|
||||
)) if q == query_id,
|
||||
)));
|
||||
assert_eq!(
|
||||
polkadot_test_runtime::Xcm::query(query_id),
|
||||
Some(QueryStatus::Ready {
|
||||
response: VersionedResponse::V2(Response::ExecutionResult(Ok(()))),
|
||||
at: 2u32.into()
|
||||
}),
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn query_response_elicits_handler() {
|
||||
use pallet_test_notifier::Event::*;
|
||||
use polkadot_test_runtime::Event::TestNotifier;
|
||||
|
||||
sp_tracing::try_init_simple();
|
||||
let mut client = TestClientBuilder::new()
|
||||
.set_execution_strategy(ExecutionStrategy::AlwaysWasm)
|
||||
.build();
|
||||
|
||||
let mut block_builder = client.init_polkadot_block_builder();
|
||||
|
||||
let execute = construct_extrinsic(
|
||||
&client,
|
||||
polkadot_test_runtime::Call::TestNotifier(
|
||||
pallet_test_notifier::Call::prepare_new_notify_query(),
|
||||
),
|
||||
sp_keyring::Sr25519Keyring::Alice,
|
||||
0,
|
||||
);
|
||||
|
||||
block_builder.push_polkadot_extrinsic(execute).expect("pushes extrinsic");
|
||||
|
||||
let block = block_builder.build().expect("Finalizes the block").block;
|
||||
let block_hash = block.hash();
|
||||
|
||||
futures::executor::block_on(client.import(sp_consensus::BlockOrigin::Own, block))
|
||||
.expect("imports the block");
|
||||
|
||||
let mut query_id = None;
|
||||
client
|
||||
.state_at(&BlockId::Hash(block_hash))
|
||||
.expect("state should exist")
|
||||
.inspect_state(|| {
|
||||
for r in polkadot_test_runtime::System::events().iter() {
|
||||
match r.event {
|
||||
TestNotifier(NotifyQueryPrepared(q)) => query_id = Some(q),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
});
|
||||
let query_id = query_id.unwrap();
|
||||
|
||||
let mut block_builder = client.init_polkadot_block_builder();
|
||||
|
||||
let response = Response::ExecutionResult(Ok(()));
|
||||
let max_weight = 1_000_000;
|
||||
let msg = Xcm(vec![QueryResponse { query_id, response, max_weight }]);
|
||||
|
||||
let execute = construct_extrinsic(
|
||||
&client,
|
||||
polkadot_test_runtime::Call::Xcm(pallet_xcm::Call::execute(
|
||||
Box::new(VersionedXcm::from(msg)),
|
||||
1_000_000_000,
|
||||
)),
|
||||
sp_keyring::Sr25519Keyring::Alice,
|
||||
1,
|
||||
);
|
||||
|
||||
block_builder.push_polkadot_extrinsic(execute).expect("pushes extrinsic");
|
||||
|
||||
let block = block_builder.build().expect("Finalizes the block").block;
|
||||
let block_hash = block.hash();
|
||||
|
||||
futures::executor::block_on(client.import(sp_consensus::BlockOrigin::Own, block))
|
||||
.expect("imports the block");
|
||||
|
||||
client
|
||||
.state_at(&BlockId::Hash(block_hash))
|
||||
.expect("state should exist")
|
||||
.inspect_state(|| {
|
||||
assert!(polkadot_test_runtime::System::events().iter().any(|r| matches!(
|
||||
r.event,
|
||||
TestNotifier(ResponseReceived(
|
||||
MultiLocation { parents: 0, interior: X1(Junction::AccountId32 { .. }) },
|
||||
q,
|
||||
Response::ExecutionResult(Ok(())),
|
||||
)) if q == query_id,
|
||||
)));
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user