From b9382b1338c71121ef15a6d3d4c20cff67bf2de5 Mon Sep 17 00:00:00 2001 From: Dinonard Date: Mon, 7 Nov 2022 13:16:16 +0100 Subject: [PATCH 1/7] Init commit with experiments --- xcm/xcm-simulator/example/src/lib.rs | 204 ++++++++++++++++----------- 1 file changed, 125 insertions(+), 79 deletions(-) diff --git a/xcm/xcm-simulator/example/src/lib.rs b/xcm/xcm-simulator/example/src/lib.rs index 299007a307e3..6cbf17e3d933 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -21,6 +21,7 @@ use frame_support::sp_tracing; use xcm::prelude::*; use xcm_executor::traits::Convert; use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain}; +// use xcm::latest::WildFungibility; pub const ALICE: sp_runtime::AccountId32 = sp_runtime::AccountId32::new([0u8; 32]); pub const INITIAL_BALANCE: u128 = 1_000_000_000; @@ -267,40 +268,101 @@ mod tests { }); } + ////////////////////////////////////////////////////// + ///////////////// SCENARIOS START///////////////////// + ////////////////////////////////////////////////////// + + /// Scenario: + /// + /// Original: + /// A parachain wants to be notified that a transfer worked correctly. + /// It sends a `QueryHolding` after the deposit to get notified on success. + /// + /// Modified: + /// The example has been modified slightly to demonstrate that correct asset amount is returned. + /// We withdraw certain amount, but deposit less. We expect that `QueryHolding` will report the remainder. + /// + /// Asserts that the balances are updated correctly and the expected XCM is sent. #[test] - fn remote_locking() { + fn query_holding() { MockNet::reset(); - let locked_amount = 100; + let withdraw_amount = 10; + let deposit_amount = 3; + let first_query_id_set = 1234; + let second_query_id_set = 5678; - ParaB::execute_with(|| { - let message = Xcm(vec![LockAsset { - asset: (Here, locked_amount).into(), - unlocker: (Parachain(1),).into(), - }]); - assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone())); + // Send a message which fully succeeds on the relay chain + ParaA::execute_with(|| { + let message = Xcm(vec![ + WithdrawAsset((Here, withdraw_amount).into()), + // We don't deposit everything intentionally, so we can check that `ReportHolding` works as expected + DepositAsset { + assets: MultiAsset { id: Concrete(Here.into()), fun: Fungible(deposit_amount) } + .into(), + beneficiary: Parachain(2).into(), + }, + ReportHolding { + response_info: QueryResponseInfo { + destination: Parachain(1).into(), + query_id: first_query_id_set, + max_weight: 1_000_000_000, + }, + assets: All.into(), // we choose to report everything, but we could limit it if we wanted to + }, + ReportHolding { + response_info: QueryResponseInfo { + destination: Parachain(1).into(), + query_id: second_query_id_set, + max_weight: 1_000_000_000, + }, + // We repeat almost the same query but we limit it to only native asset and to 1 amount! + // So even if we have more than 1, at max, 1 can be reported (0 or 1). + assets: MultiAsset { id: Concrete(Here.into()), fun: Fungible(1) }.into(), + }, + ]); + // Send withdraw and deposit with query holding + assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone(),)); }); + // Check that transfer was executed Relay::execute_with(|| { - use pallet_balances::{BalanceLock, Reasons}; + // Withdraw executed assert_eq!( - relay_chain::Balances::locks(&child_account_id(2)), - vec![BalanceLock { - id: *b"py/xcmlk", - amount: locked_amount, - reasons: Reasons::All - }] + relay_chain::Balances::free_balance(child_account_id(1)), + INITIAL_BALANCE - withdraw_amount + ); + // Deposit executed + assert_eq!( + relay_chain::Balances::free_balance(child_account_id(2)), + INITIAL_BALANCE + deposit_amount ); }); + // Check that QueryResponse message was received ParaA::execute_with(|| { assert_eq!( parachain::MsgQueue::received_dmp(), - vec![Xcm(vec![NoteUnlockable { - owner: (Parent, Parachain(2)).into(), - asset: (Parent, locked_amount).into() - }])] + vec![ + Xcm(vec![QueryResponse { + query_id: first_query_id_set, + response: Response::Assets( + (Parent, withdraw_amount - deposit_amount).into() + ), + max_weight: 1_000_000_000, + querier: Some(Here.into()), + },]), + Xcm(vec![QueryResponse { + query_id: second_query_id_set, + response: Response::Assets((Parent, 1).into()), + max_weight: 1_000_000_000, + querier: Some(Here.into()), + },]) + // Notice that we define 2 separate XCM sequences. This is because each `QueryHolding`'s reponse is done individually. + ], ); + + // TODO: check what happened with the unused funds left in the holding register }); } @@ -317,19 +379,62 @@ mod tests { }); ParaA::execute_with(|| { + // We want to transfer asset owned by `ParaA` over to `Para2` let message = Xcm(vec![TransferAsset { assets: (GeneralIndex(1), 42u32).into(), beneficiary: Parachain(2).into(), }]); - // Send withdraw and deposit + // We send the message to the `Parent`, the relay chain, since asset is there assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message)); }); + // Asset ownership has changed Relay::execute_with(|| { assert_eq!(relay_chain::Uniques::owner(1, 42), Some(child_account_id(2))); }); } + ////////////////////////////////////////////////////// + ///////////////// SCENARIOS END ////////////////////// + ////////////////////////////////////////////////////// + + #[test] + fn remote_locking() { + MockNet::reset(); + + let locked_amount = 100; + + ParaB::execute_with(|| { + let message = Xcm(vec![LockAsset { + asset: (Here, locked_amount).into(), + unlocker: (Parachain(1),).into(), + }]); + assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone())); + }); + + Relay::execute_with(|| { + use pallet_balances::{BalanceLock, Reasons}; + assert_eq!( + relay_chain::Balances::locks(&child_account_id(2)), + vec![BalanceLock { + id: *b"py/xcmlk", + amount: locked_amount, + reasons: Reasons::All + }] + ); + }); + + ParaA::execute_with(|| { + assert_eq!( + parachain::MsgQueue::received_dmp(), + vec![Xcm(vec![NoteUnlockable { + owner: (Parent, Parachain(2)).into(), + asset: (Parent, locked_amount).into() + }])] + ); + }); + } + /// Scenario: /// The relay-chain teleports an NFT to a parachain. /// @@ -563,63 +668,4 @@ mod tests { ); }); } - - /// Scenario: - /// A parachain wants to be notified that a transfer worked correctly. - /// It sends a `QueryHolding` after the deposit to get notified on success. - /// - /// Asserts that the balances are updated correctly and the expected XCM is sent. - #[test] - fn query_holding() { - MockNet::reset(); - - let send_amount = 10; - let query_id_set = 1234; - - // Send a message which fully succeeds on the relay chain - ParaA::execute_with(|| { - let message = Xcm(vec![ - WithdrawAsset((Here, send_amount).into()), - buy_execution((Here, send_amount)), - DepositAsset { assets: AllCounted(1).into(), beneficiary: Parachain(2).into() }, - ReportHolding { - response_info: QueryResponseInfo { - destination: Parachain(1).into(), - query_id: query_id_set, - max_weight: 1_000_000_000, - }, - assets: All.into(), - }, - ]); - // Send withdraw and deposit with query holding - assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone(),)); - }); - - // Check that transfer was executed - Relay::execute_with(|| { - // Withdraw executed - assert_eq!( - relay_chain::Balances::free_balance(child_account_id(1)), - INITIAL_BALANCE - send_amount - ); - // Deposit executed - assert_eq!( - relay_chain::Balances::free_balance(child_account_id(2)), - INITIAL_BALANCE + send_amount - ); - }); - - // Check that QueryResponse message was received - ParaA::execute_with(|| { - assert_eq!( - parachain::MsgQueue::received_dmp(), - vec![Xcm(vec![QueryResponse { - query_id: query_id_set, - response: Response::Assets(MultiAssets::new()), - max_weight: 1_000_000_000, - querier: Some(Here.into()), - }])], - ); - }); - } } From 50f6a4f8a22da1704bc17e0ec9225c9dd1cfc5e2 Mon Sep 17 00:00:00 2001 From: Dinonard Date: Mon, 7 Nov 2022 15:08:53 +0100 Subject: [PATCH 2/7] ReportError example --- xcm/xcm-simulator/example/src/lib.rs | 83 ++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 5 deletions(-) diff --git a/xcm/xcm-simulator/example/src/lib.rs b/xcm/xcm-simulator/example/src/lib.rs index 6cbf17e3d933..b46c157f7a95 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -18,10 +18,9 @@ mod parachain; mod relay_chain; use frame_support::sp_tracing; -use xcm::prelude::*; +use xcm::{latest::Error, prelude::*}; use xcm_executor::traits::Convert; use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain}; -// use xcm::latest::WildFungibility; pub const ALICE: sp_runtime::AccountId32 = sp_runtime::AccountId32::new([0u8; 32]); pub const INITIAL_BALANCE: u128 = 1_000_000_000; @@ -357,8 +356,7 @@ mod tests { response: Response::Assets((Parent, 1).into()), max_weight: 1_000_000_000, querier: Some(Here.into()), - },]) - // Notice that we define 2 separate XCM sequences. This is because each `QueryHolding`'s reponse is done individually. + },]) // Notice that we define 2 separate XCM sequences. This is because each `QueryHolding`'s reponse is done individually. ], ); @@ -371,7 +369,7 @@ mod tests { /// /// Asserts that the parachain accounts are updated as expected. #[test] - fn withdraw_and_deposit_nft() { + fn transfer_asset_nft() { MockNet::reset(); Relay::execute_with(|| { @@ -394,6 +392,81 @@ mod tests { }); } + /// Scenario: + /// A parachain configures error handler on relay chain, [ReportError] + /// A parachain attempts to withdraw on relay chain more than it has, causing an error. + /// We expect to receive error back in a report. + #[test] + fn report_error() { + MockNet::reset(); + + let first_query_id = 1234; + let second_query_id = 5678; + let max_weight = 1_000_000_000; + + // Send a message which will result in an error on the relay chain + ParaA::execute_with(|| { + // First we prepare the sequence for the error handler. + // The idea is to report actual error, clear error and then report it again. + // In the first report we expect to see the error but we don't expect it in the second one. + let error_handler_sequence = Xcm(vec![ + ReportError(QueryResponseInfo { + destination: Parachain(1).into(), + query_id: first_query_id, + max_weight, + }), + ClearError, + ReportError(QueryResponseInfo { + destination: Parachain(1).into(), + query_id: second_query_id, + max_weight, + }), + ]); + + let message = Xcm(vec![ + // This will set the error handler on the relay chain + SetErrorHandler(error_handler_sequence), + // We expect this to fail since it's more than the ParaA account has + WithdrawAsset((Here, INITIAL_BALANCE + 1).into()), + ]); + // Send withdraw and deposit with query holding + assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone(),)); + }); + + Relay::execute_with(|| { + // Withdraw was attempted & failed, balance hasn't changed + assert_eq!(relay_chain::Balances::free_balance(child_account_id(1)), INITIAL_BALANCE); + }); + + // Check that QueryResponse message was received and correct error was reported + ParaA::execute_with(|| { + assert_eq!( + parachain::MsgQueue::received_dmp(), + vec![ + // We expect the first response to contain an error since we failed to withdraw assets + Xcm(vec![QueryResponse { + query_id: first_query_id, + response: Response::ExecutionResult(Some(( + 1, // this is the instruction index at which the error occured + Error::FailedToTransactAsset("") + ))), + max_weight: 1_000_000_000, + querier: Some(Here.into()), + },]), + // The second response shouldn't contain any errors since we cleared all errors + Xcm(vec![QueryResponse { + query_id: second_query_id, + response: Response::ExecutionResult(None), + max_weight: 1_000_000_000, + querier: Some(Here.into()), + },]) + ], + ); + }); + + // Error enum can be found here: polkadot/xcm/src/v3/traits.rs + } + ////////////////////////////////////////////////////// ///////////////// SCENARIOS END ////////////////////// ////////////////////////////////////////////////////// From 7dc6de3c07c7062665200ac15de3ca6cc5989461 Mon Sep 17 00:00:00 2001 From: Dinonard Date: Tue, 8 Nov 2022 11:35:07 +0100 Subject: [PATCH 3/7] set_appendix scenario --- xcm/xcm-simulator/example/src/lib.rs | 80 ++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/xcm/xcm-simulator/example/src/lib.rs b/xcm/xcm-simulator/example/src/lib.rs index b46c157f7a95..6174468fb8d4 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -467,6 +467,86 @@ mod tests { // Error enum can be found here: polkadot/xcm/src/v3/traits.rs } + /// Scenario: + /// A parachain sets appendix (callback after XCM execution finishes) and executes a remote transaction. + /// It expects to replies, one with execution error and one with 'success' (should be empty since result was cleared). + #[test] + fn set_appendix() { + MockNet::reset(); + + let first_query_id = 1234; + let second_query_id = 5678; + let max_weight = 1_000_000_000; + + // Send a message which will set appendix and perform remote transact on the relay chain + ParaA::execute_with(|| { + // First we prepare the sequence for the appendix - to be executed after XCM execution finishes (post-call hook). + // The idea is to report transact status, clear it and then report it again. + // In the first report we expect to see the execution result (error), while in second we expect success (state after `ClearOrigin`) + let appendix_sequence = Xcm(vec![ + ReportTransactStatus(QueryResponseInfo { + destination: Parachain(1).into(), + query_id: first_query_id, + max_weight, + }), + ClearTransactStatus, + ReportTransactStatus(QueryResponseInfo { + destination: Parachain(1).into(), + query_id: second_query_id, + max_weight, + }), + ]); + + // This is what we'll execute on the remote chain, relay in particular. + // It's a priviliged action and we expect it to fail + let priviliged_action = + relay_chain::RuntimeCall::System( + frame_system::Call::::set_heap_pages { pages: 1337 }, + ); + + let message = Xcm(vec![ + // This will set the error handler on the relay chain + SetAppendix(appendix_sequence), + // We expect this to fail since it's more than the ParaA account has + Transact { + origin_kind: OriginKind::SovereignAccount, + require_weight_at_most: 1_000_000_000, + call: priviliged_action.encode().into(), + }, + ]); + + // Send XCM instructions to the relay chain + assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone(),)); + }); + + // process received XCM instructions from the ParaA + Relay::execute_with(|| { + // just execute received XCM instructions on the relay chain side + }); + + ParaA::execute_with(|| { + assert_eq!( + parachain::MsgQueue::received_dmp(), + vec![ + // We expect the first response to contain DispatchResult error since we tried to transact root-only priviliged action + Xcm(vec![QueryResponse { + query_id: first_query_id, + response: Response::DispatchResult(MaybeErrorCode::Error(vec![2])), + max_weight: 1_000_000_000, + querier: Some(Here.into()), + },]), + // The second response should be ok since we cleared the transact status prior to sending the response + Xcm(vec![QueryResponse { + query_id: second_query_id, + response: Response::DispatchResult(MaybeErrorCode::Success), + max_weight: 1_000_000_000, + querier: Some(Here.into()), + },]) + ], + ); + }); + } + ////////////////////////////////////////////////////// ///////////////// SCENARIOS END ////////////////////// ////////////////////////////////////////////////////// From a2707902a691089c9bc76eea202b223261b4d1da Mon Sep 17 00:00:00 2001 From: Dinonard Date: Tue, 8 Nov 2022 15:18:23 +0100 Subject: [PATCH 4/7] topic --- xcm/xcm-simulator/example/src/lib.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/xcm/xcm-simulator/example/src/lib.rs b/xcm/xcm-simulator/example/src/lib.rs index 6174468fb8d4..b0d53eb69812 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -547,6 +547,32 @@ mod tests { }); } + /// Scenario: + /// ParaA sets topic on relay chain. + /// + /// At the moment, I'm not sure how to verify it works in a nice & convenient way. One possible approach would be to + /// add custom handlers for certain actions which would make use of the topic. + #[test] + fn set_topic() { + MockNet::reset(); + + ParaA::execute_with(|| { + // we want to set a custom topic, which must be [u8; 32] + let mut topic = vec![0x1u8, 0x3, 0x3, 0x7]; + topic.extend(vec![0u8; 28]); + + let message = Xcm(vec![SetTopic(topic.try_into().unwrap())]); + assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message)); + }); + + Relay::execute_with(|| { + // VM is created when XCM execution starts, and is dropped afterwards so I cannot check internal state. + // TODO: add custom handler so e.g. asset withdraw will work differently based on context? + }); + } + + // TODO: Idea - maybe demonstrate recursive error handling or appendix setting? + ////////////////////////////////////////////////////// ///////////////// SCENARIOS END ////////////////////// ////////////////////////////////////////////////////// From 7f6961ca07e4465f44d9fa184bbeb52ad2b32142 Mon Sep 17 00:00:00 2001 From: Dinonard Date: Tue, 8 Nov 2022 17:35:50 +0100 Subject: [PATCH 5/7] claim asset WIP --- xcm/xcm-simulator/example/src/lib.rs | 30 ++++++++++++++++++++ xcm/xcm-simulator/example/src/relay_chain.rs | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/xcm/xcm-simulator/example/src/lib.rs b/xcm/xcm-simulator/example/src/lib.rs index b0d53eb69812..da759c80232c 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -571,6 +571,36 @@ mod tests { }); } + /// Scenario: + /// We get some assets trapped and then claim them using `ClaimAsset` instruction. + /// We verify the balance state changes on the destination chain. + #[test] + fn claim_asset() { + MockNet::reset(); + + let trap_value = 61; + + ParaA::execute_with(|| { + // Just withdraw assets and don't do anything with them. Post-processing will trap them. + let message = Xcm(vec![WithdrawAsset((Here, trap_value).into())]); + assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message)); + }); + + Relay::execute_with(|| { + // some assets were withdrawn - and lost! Or trapped, to be more precise. + assert_eq!( + relay_chain::Balances::free_balance(child_account_id(1)), + INITIAL_BALANCE - trap_value + ); + }); + + ParaA::execute_with(|| { + // Now we can attempt to claim the trapped assets TODO: CONTINUE HERE! + // let message = Xcm(vec![WithdrawAsset((Here, trap_value).into())]); + // assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message)); + }); + } + // TODO: Idea - maybe demonstrate recursive error handling or appendix setting? ////////////////////////////////////////////////////// diff --git a/xcm/xcm-simulator/example/src/relay_chain.rs b/xcm/xcm-simulator/example/src/relay_chain.rs index f743b84ab280..906d01e8a824 100644 --- a/xcm/xcm-simulator/example/src/relay_chain.rs +++ b/xcm/xcm-simulator/example/src/relay_chain.rs @@ -173,7 +173,7 @@ impl Config for XcmConfig { type AssetTrap = (); type AssetLocker = XcmPallet; type AssetExchanger = (); - type AssetClaims = (); + type AssetClaims = XcmPallet; type SubscriptionService = (); type PalletInstancesInfo = (); type FeeManager = (); From 2037f2d1d3a7291376ce833057da1686c0b7eeb8 Mon Sep 17 00:00:00 2001 From: Dinonard Date: Wed, 9 Nov 2022 12:03:57 +0100 Subject: [PATCH 6/7] expect branching --- xcm/xcm-simulator/example/src/lib.rs | 96 +++++++++++++++++++- xcm/xcm-simulator/example/src/relay_chain.rs | 2 +- 2 files changed, 92 insertions(+), 6 deletions(-) diff --git a/xcm/xcm-simulator/example/src/lib.rs b/xcm/xcm-simulator/example/src/lib.rs index da759c80232c..3cb234ddb392 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -505,7 +505,7 @@ mod tests { ); let message = Xcm(vec![ - // This will set the error handler on the relay chain + // This will set the post process handler on the relay chain SetAppendix(appendix_sequence), // We expect this to fail since it's more than the ParaA account has Transact { @@ -573,7 +573,8 @@ mod tests { /// Scenario: /// We get some assets trapped and then claim them using `ClaimAsset` instruction. - /// We verify the balance state changes on the destination chain. + /// We verify the balance state changes on the destination chain, right after they were trapped + /// and after they were claimed. #[test] fn claim_asset() { MockNet::reset(); @@ -595,9 +596,94 @@ mod tests { }); ParaA::execute_with(|| { - // Now we can attempt to claim the trapped assets TODO: CONTINUE HERE! - // let message = Xcm(vec![WithdrawAsset((Here, trap_value).into())]); - // assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message)); + // Now we can attempt to claim the trapped assets. + // It's important we specify EXACTLY the amount of assets that were trapped and use the same origin we used when assets got trapped. + let message = Xcm(vec![ + ClaimAsset { + assets: (Here, trap_value).into(), + ticket: Here.into(), // not important, this value is equivalent to `Don't care` + }, + DepositAsset { assets: AllCounted(1).into(), beneficiary: Parachain(1).into() }, + ]); + assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message)); + }); + + Relay::execute_with(|| { + // We can verify that previous balance was restored - trapped assets have been re-claimed. + assert_eq!(relay_chain::Balances::free_balance(child_account_id(1)), INITIAL_BALANCE); + }); + } + + /// Scenario: + /// We register appendix and error handler on the relay chain. + /// In one case, assets will get deposited to ParaA account, in other to `ParaB` account. + /// We rely on `ExpectAsset` instruction to raise an error in case expected condition isn't met. + /// Both scenarios are tested, with and without the error being raised. + #[test] + fn expect_asset_branching() { + MockNet::reset(); + + // In case execution results in an error, deposit asset to `ParaA` account + let error_handler_seq = Xcm(vec![DepositAsset { + assets: AllCounted(1).into(), + beneficiary: Parachain(1).into(), + }]); + + // In case all goes fine, deposit asset to `ParaB` account + let appendix_handler_seq = Xcm(vec![DepositAsset { + assets: AllCounted(1).into(), + beneficiary: Parachain(2).into(), + }]); + + let send_amount = 29; + + // We will withdraw some assets but will expect to have more in the holding register than we actually have. + // This is intentional to produce an error. + ParaA::execute_with(|| { + let message = Xcm(vec![ + SetErrorHandler(error_handler_seq.clone()), + SetAppendix(appendix_handler_seq.clone()), + WithdrawAsset((Here, send_amount).into()), + ExpectAsset((Here, send_amount + 1).into()), + ]); + // Send XCM instructions to the relay chain + assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone(),)); + }); + + // process received XCM instructions from the ParaA. + // We expect that error was raised since we expected too much assets in the holding register. + // In that scenario, all assets that were withdrawn should hav been deposited back to `ParaA` + Relay::execute_with(|| { + assert_eq!(relay_chain::Balances::free_balance(child_account_id(1)), INITIAL_BALANCE); + + assert_eq!(relay_chain::Balances::free_balance(child_account_id(2)), INITIAL_BALANCE); + }); + + // We repeat the same sequence but this time we'll expect a bit less than what we have. + // This shoudl pass and no error should be raised. + ParaA::execute_with(|| { + let message = Xcm(vec![ + SetErrorHandler(error_handler_seq.clone()), + SetAppendix(appendix_handler_seq.clone()), + WithdrawAsset((Here, send_amount).into()), + ExpectAsset((Here, send_amount - 1).into()), + ]); + // Send XCM instructions to the relay chain + assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone(),)); + }); + + // process received XCM instructions from the `ParaA`. + // We expect that assets were deposited to `ParaB` since appendix handler should have been executed. + Relay::execute_with(|| { + assert_eq!( + relay_chain::Balances::free_balance(child_account_id(1)), + INITIAL_BALANCE - send_amount + ); + + assert_eq!( + relay_chain::Balances::free_balance(child_account_id(2)), + INITIAL_BALANCE + send_amount + ); }); } diff --git a/xcm/xcm-simulator/example/src/relay_chain.rs b/xcm/xcm-simulator/example/src/relay_chain.rs index 906d01e8a824..9b6f9cb5d866 100644 --- a/xcm/xcm-simulator/example/src/relay_chain.rs +++ b/xcm/xcm-simulator/example/src/relay_chain.rs @@ -170,7 +170,7 @@ impl Config for XcmConfig { type Weigher = FixedWeightBounds; type Trader = FixedRateOfFungible; type ResponseHandler = (); - type AssetTrap = (); + type AssetTrap = XcmPallet; type AssetLocker = XcmPallet; type AssetExchanger = (); type AssetClaims = XcmPallet; From 832e5d2d050cb131a6cc7857048177ed9905f057 Mon Sep 17 00:00:00 2001 From: Dinonard Date: Wed, 9 Nov 2022 13:24:15 +0100 Subject: [PATCH 7/7] query pallet --- xcm/xcm-simulator/example/src/lib.rs | 56 ++++++++++++++++++++ xcm/xcm-simulator/example/src/relay_chain.rs | 2 +- 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/xcm/xcm-simulator/example/src/lib.rs b/xcm/xcm-simulator/example/src/lib.rs index 3cb234ddb392..9e5a2658eace 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -687,6 +687,62 @@ mod tests { }); } + /// Scenario + /// Query system pallet on the relay chain and ensure it's present with expected version. + #[test] + fn query_pallet() { + MockNet::reset(); + + let query_id = 1234; + let max_weight = 1_000_000_000; + let module_name = "frame_system"; + + // Query the relay chain for the system pallet by it's module name + ParaA::execute_with(|| { + let message = Xcm(vec![QueryPallet { + module_name: module_name.into(), + response_info: QueryResponseInfo { + destination: Parachain(1).into(), + query_id, + max_weight, + }, + }]); + assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone(),)); + }); + + Relay::execute_with(|| { + // execute message received from ParaA, send response back to `ParaA` + }); + + // Check that QueryResponse message was received and pallet info is as expected + ParaA::execute_with(|| { + assert_eq!( + parachain::MsgQueue::received_dmp(), + vec![ + // We expect the first response to contain an error since we failed to withdraw assets + Xcm(vec![QueryResponse { + query_id, + response: Response::PalletsInfo( + vec![PalletInfo::new( + 0, // index + "System".into(), // name + module_name.into(), // module_name + 4, // major + 0, // minor + 0, // patch + ) + .unwrap()] + .try_into() + .unwrap() + ), + max_weight: 1_000_000_000, + querier: Some(Here.into()), + },]) + ], + ); + }); + } + // TODO: Idea - maybe demonstrate recursive error handling or appendix setting? ////////////////////////////////////////////////////// diff --git a/xcm/xcm-simulator/example/src/relay_chain.rs b/xcm/xcm-simulator/example/src/relay_chain.rs index 9b6f9cb5d866..e56fcf888490 100644 --- a/xcm/xcm-simulator/example/src/relay_chain.rs +++ b/xcm/xcm-simulator/example/src/relay_chain.rs @@ -175,7 +175,7 @@ impl Config for XcmConfig { type AssetExchanger = (); type AssetClaims = XcmPallet; type SubscriptionService = (); - type PalletInstancesInfo = (); + type PalletInstancesInfo = AllPalletsWithSystem; type FeeManager = (); type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type MessageExporter = ();