diff --git a/Cargo.lock b/Cargo.lock index 1518fe839ca24..188b578d41804 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13537,6 +13537,7 @@ dependencies = [ "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", + "sp-tracing 16.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index d186507dab179..f0e3613914f64 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -239,6 +239,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = (); + type XcmEventEmitter = (); type AssetTransactor = (); type OriginConverter = BridgeHubLocationXcmOriginAsRoot; type IsReserve = (); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index bf44d2408d030..1a7ca90b05998 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -354,6 +354,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToTransactDispatchOrigin; // Asset Hub trusts only particular, pre-configured bridged locations from a different consensus diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs index cc093d6fa5752..2f3ceeb7f16ea 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs @@ -375,6 +375,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToTransactDispatchOrigin; // Asset Hub trusts only particular, pre-configured bridged locations from a different consensus diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs index 31b14f9a0517d..376e751299c50 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs @@ -181,6 +181,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = FungibleTransactor; type OriginConverter = XcmOriginToTransactDispatchOrigin; // BridgeHub does not recognize a reserve location for any asset. Users must teleport Native diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs index 205fc6ed4b87a..f7067748a6d7b 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs @@ -181,6 +181,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = FungibleTransactor; type OriginConverter = XcmOriginToTransactDispatchOrigin; // BridgeHub does not recognize a reserve location for any asset. Users must teleport Native diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs index 5d33d006c293c..07b6e563969f3 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs @@ -194,6 +194,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = FungibleTransactor; type OriginConverter = XcmOriginToTransactDispatchOrigin; // Collectives does not recognize a reserve location for any asset. Users must teleport WND diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs index 35b3b6fb55757..66d5267d91565 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs @@ -187,6 +187,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToTransactDispatchOrigin; // Coretime chain does not recognize a reserve location for any asset. Users must teleport ROC diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs index 707b9a42c8558..c8322573b4692 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs @@ -205,6 +205,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToTransactDispatchOrigin; // Coretime chain does not recognize a reserve location for any asset. Users must teleport ROC diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs index b67c32495d67c..8f90d07fc6ee3 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs @@ -65,6 +65,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = (); // sending XCM not supported + type XcmEventEmitter = (); type AssetTransactor = (); // balances not supported type OriginConverter = XcmOriginToTransactDispatchOrigin; type IsReserve = (); // balances not supported diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs index 9e89cd465e45c..d2d5c8c85bcb3 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs @@ -191,6 +191,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = FungibleTransactor; type OriginConverter = XcmOriginToTransactDispatchOrigin; // People chain does not recognize a reserve location for any asset. Users must teleport ROC diff --git a/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs index 98be08379a525..2e78772ca7c30 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs @@ -209,6 +209,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = FungibleTransactor; type OriginConverter = XcmOriginToTransactDispatchOrigin; // People does not recognize a reserve location for any asset. Users must teleport WND diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index 65e2c7e738d30..8e83ef318bca8 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -371,6 +371,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; // How to withdraw and deposit an asset. type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToTransactDispatchOrigin; diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index 0e237ba5c4318..45708fdf29dbb 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -472,6 +472,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; // How to withdraw and deposit an asset. type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToTransactDispatchOrigin; diff --git a/polkadot/runtime/rococo/src/xcm_config.rs b/polkadot/runtime/rococo/src/xcm_config.rs index 10c3f6c0cbfcf..af486db12f426 100644 --- a/polkadot/runtime/rococo/src/xcm_config.rs +++ b/polkadot/runtime/rococo/src/xcm_config.rs @@ -191,6 +191,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = XcmPallet; type AssetTransactor = LocalAssetTransactor; type OriginConverter = LocalOriginConverter; type IsReserve = (); diff --git a/polkadot/runtime/test-runtime/src/xcm_config.rs b/polkadot/runtime/test-runtime/src/xcm_config.rs index b424b9a3ee55b..304c1d52e9ef5 100644 --- a/polkadot/runtime/test-runtime/src/xcm_config.rs +++ b/polkadot/runtime/test-runtime/src/xcm_config.rs @@ -130,6 +130,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = super::RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = super::Xcm; type AssetTransactor = DummyAssetTransactor; type OriginConverter = OriginConverter; type IsReserve = (); diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index c7615ef217724..c5a3cc1bde736 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -196,6 +196,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = XcmPallet; type AssetTransactor = LocalAssetTransactor; type OriginConverter = LocalOriginConverter; type IsReserve = (); diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs index 59dcc7af0e83b..17bef935a2fa0 100644 --- a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs +++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs @@ -115,6 +115,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = (); + type XcmEventEmitter = (); type AssetTransactor = asset_transactor::AssetTransactor; type OriginConverter = (); // The declaration of which Locations are reserves for which Assets. diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs index cf044cd21be63..445e8f950acdd 100644 --- a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs +++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs @@ -88,6 +88,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = (); + type XcmEventEmitter = (); type AssetTransactor = asset_transactor::AssetTransactor; type OriginConverter = (); // We don't need to recognize anyone as a reserve diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs index c0dfa91afc786..9e06550b6b724 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs @@ -94,6 +94,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = EnsureDecodableXcm; + type XcmEventEmitter = (); type AssetTransactor = AssetTransactor; type OriginConverter = (); type IsReserve = TrustedReserves; diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs index f51d34092616b..1eeafaa7f5e97 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs @@ -83,6 +83,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = EnsureDecodableXcm; + type XcmEventEmitter = (); type AssetTransactor = NoAssetTransactor; type OriginConverter = AlwaysSignedByDefault; type IsReserve = AllAssetLocationsPass; diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index 85beba03b1576..c22bda0094f6a 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -37,6 +37,7 @@ pallet-balances = { optional = true, workspace = true } pallet-assets = { workspace = true, default-features = true } polkadot-parachain-primitives = { workspace = true, default-features = true } polkadot-runtime-parachains = { workspace = true, default-features = true } +sp-tracing = { features = ["test-utils"], workspace = true, default-features = true } [features] default = ["std"] diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index ba88622226638..ad0da135b31cd 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -61,9 +61,9 @@ use xcm_builder::{ use xcm_executor::{ traits::{ AssetTransferError, CheckSuspension, ClaimAssets, ConvertLocation, ConvertOrigin, - DropAssets, MatchesFungible, OnResponse, Properties, QueryHandler, QueryResponseStatus, - RecordXcm, TransactAsset, TransferType, VersionChangeNotifier, WeightBounds, - XcmAssetTransfers, + DropAssets, EventEmitter, MatchesFungible, OnResponse, Properties, QueryHandler, + QueryResponseStatus, RecordXcm, TransactAsset, TransferType, VersionChangeNotifier, + WeightBounds, XcmAssetTransfers, }, AssetsInHolding, }; @@ -402,13 +402,51 @@ pub mod pallet { } } + impl EventEmitter for Pallet { + fn emit_sent_event( + origin: Location, + destination: Location, + message: Option>, + message_id: XcmHash, + ) { + Self::deposit_event(Event::Sent { + origin, + destination, + message: message.unwrap_or_default(), + message_id, + }); + } + + fn emit_send_failure_event( + origin: Location, + destination: Location, + error: SendError, + message_id: XcmHash, + ) { + Self::deposit_event(Event::SendFailed { origin, destination, error, message_id }); + } + + fn emit_process_failure_event(origin: Location, error: XcmError, message_id: XcmHash) { + Self::deposit_event(Event::ProcessXcmError { origin, error, message_id }); + } + } + #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// Execution of an XCM message was attempted. Attempted { outcome: xcm::latest::Outcome }, - /// A XCM message was sent. + /// An XCM message was sent. Sent { origin: Location, destination: Location, message: Xcm<()>, message_id: XcmHash }, + /// An XCM message failed to send. + SendFailed { + origin: Location, + destination: Location, + error: SendError, + message_id: XcmHash, + }, + /// An XCM message failed to process. + ProcessXcmError { origin: Location, error: XcmError, message_id: XcmHash }, /// Query response received which does not match a registered query. This may be because a /// matching query was never registered, it may be because it is a duplicate response, or /// because the query timed out. diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index 74d2f4584d63b..a3062964627da 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -179,7 +179,14 @@ impl SendXcm for TestSendXcm { Ok((pair, Assets::new())) } fn deliver(pair: (Location, Xcm<()>)) -> Result { - let hash = fake_message_hash(&pair.1); + let message = pair.1.clone(); + if message + .iter() + .any(|instr| matches!(instr, ExpectError(Some((1, XcmError::Unimplemented))))) + { + return Err(SendError::Transport("Intentional deliver failure used in tests".into())); + } + let hash = fake_message_hash(&message); SENT_XCM.with(|q| q.borrow_mut().push(pair)); Ok(hash) } @@ -481,6 +488,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = XcmPallet; type AssetTransactor = AssetTransactors; type OriginConverter = LocalOriginConverter; type IsReserve = (Case, Case, Case); diff --git a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs index af81ac9cf43a9..00ebbb2010e36 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs @@ -2030,6 +2030,11 @@ fn transfer_assets_with_filtered_teleported_fee_disallowed() { /// burn) effects are reverted. #[test] fn intermediary_error_reverts_side_effects() { + use sp_tracing::{ + test_log_capture::init_log_capture, + tracing::{subscriber, Level}, + }; + let balances = vec![(ALICE, INITIAL_BALANCE)]; let beneficiary: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); new_test_ext_with_balances(balances).execute_with(|| { @@ -2060,15 +2065,32 @@ fn intermediary_error_reverts_side_effects() { set_send_xcm_artificial_failure(true); // do the transfer - extrinsic should completely fail on xcm send failure - assert!(XcmPallet::limited_reserve_transfer_assets( - RuntimeOrigin::signed(ALICE), - Box::new(dest.into()), - Box::new(beneficiary.into()), - Box::new(assets.into()), - fee_index as u32, - Unlimited, - ) - .is_err()); + let (log_capture, subscriber) = init_log_capture(Level::DEBUG, true); + subscriber::with_default(subscriber, || { + let result = XcmPallet::limited_reserve_transfer_assets( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + ); + assert!(result.is_err()); + + // Ensure the log occurs before `XcmEventEmitter::emit_process_failure_event` is called. + assert!(log_capture.contains( + "xcm::process: XCM execution failed at instruction index=2 error=Transport(\"Intentional send failure used in tests\")" + ), "Expected transport error log message not found"); + + // Verify that `XcmPallet::ProcessXcmError` was NOT emitted, indicating a rollback. + let process_xcm_error_emitted = System::events().iter().any(|r| { + matches!(r.event, RuntimeEvent::XcmPallet(crate::Event::ProcessXcmError { .. })) + }); + assert!( + !process_xcm_error_emitted, + "Expected no `XcmPallet::ProcessXcmError` event due to rollback, but it was emitted" + ); + }); // Alice no changes assert_eq!( @@ -2500,6 +2522,27 @@ fn remote_asset_reserve_and_remote_fee_reserve_paid_call( return; } + let context = UniversalLocation::get(); + let foreign_id_location_reanchored = + foreign_asset_id_location.clone().reanchored(&dest, &context).unwrap(); + let dest_reanchored = dest.reanchored(&reserve_location, &context).unwrap(); + let sent_message = Xcm(vec![ + WithdrawAsset((Location::here(), SEND_AMOUNT).into()), + ClearOrigin, + buy_execution((Location::here(), SEND_AMOUNT / 2)), + DepositReserveAsset { + assets: Wild(AllCounted(1)), + // final destination is `dest` as seen by `reserve` + dest: dest_reanchored, + // message sent onward to `dest` + xcm: Xcm(vec![ + buy_execution((foreign_id_location_reanchored, SEND_AMOUNT / 2)), + DepositAsset { assets: AllCounted(1).into(), beneficiary }, + ]), + }, + ]); + let sent_msg_id = fake_message_hash(&sent_message); + let mut last_events = last_events(7).into_iter(); // asset events // forceCreate @@ -2513,6 +2556,15 @@ fn remote_asset_reserve_and_remote_fee_reserve_paid_call( last_events.next().unwrap(); // mint delivery fee last_events.next().unwrap(); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Sent { + origin: user_account.clone().into(), + destination: Parachain(paid_para_id).into(), + message: Xcm::default(), + message_id: sent_msg_id, + }) + ); assert_eq!( last_events.next().unwrap(), RuntimeEvent::XcmPallet(crate::Event::Attempted { @@ -2542,37 +2594,15 @@ fn remote_asset_reserve_and_remote_fee_reserve_paid_call( AssetsPallet::total_issuance(foreign_asset_id_location.clone()), expected_issuance ); - assert_eq!( - AssetsPallet::active_issuance(foreign_asset_id_location.clone()), - expected_issuance - ); - - let context = UniversalLocation::get(); - let foreign_id_location_reanchored = - foreign_asset_id_location.reanchored(&dest, &context).unwrap(); - let dest_reanchored = dest.reanchored(&reserve_location, &context).unwrap(); + assert_eq!(AssetsPallet::active_issuance(foreign_asset_id_location), expected_issuance); // Verify sent XCM program assert_eq!( sent_xcm(), vec![( - reserve_location, // `assets` are burned on source and withdrawn from SA in remote reserve chain - Xcm(vec![ - WithdrawAsset((Location::here(), SEND_AMOUNT).into()), - ClearOrigin, - buy_execution((Location::here(), SEND_AMOUNT / 2)), - DepositReserveAsset { - assets: Wild(AllCounted(1)), - // final destination is `dest` as seen by `reserve` - dest: dest_reanchored, - // message sent onward to `dest` - xcm: Xcm(vec![ - buy_execution((foreign_id_location_reanchored, SEND_AMOUNT / 2)), - DepositAsset { assets: AllCounted(1).into(), beneficiary } - ]) - } - ]) + reserve_location, + sent_message, )] ); }); diff --git a/polkadot/xcm/pallet-xcm/src/tests/mod.rs b/polkadot/xcm/pallet-xcm/src/tests/mod.rs index 350530f7711f8..b215425cefdab 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/mod.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/mod.rs @@ -339,25 +339,33 @@ fn send_works() { /// Asserts that `send` fails with `Error::SendFailure` #[test] fn send_fails_when_xcm_router_blocks() { + use sp_tracing::{ + test_log_capture::init_log_capture, + tracing::{subscriber, Level}, + }; + let balances = vec![ (ALICE, INITIAL_BALANCE), (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), ]; new_test_ext_with_balances(balances).execute_with(|| { - let sender: Location = Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + let sender: Location = AccountId32 { network: None, id: ALICE.into() }.into(); let message = Xcm(vec![ ReserveAssetDeposited((Parent, SEND_AMOUNT).into()), buy_execution((Parent, SEND_AMOUNT)), DepositAsset { assets: AllCounted(1).into(), beneficiary: sender }, ]); - assert_noop!( - XcmPallet::send( + let (log_capture, subscriber) = init_log_capture(Level::DEBUG, true); + subscriber::with_default(subscriber, || { + let result = XcmPallet::send( RuntimeOrigin::signed(ALICE), Box::new(Location::ancestor(8).into()), Box::new(VersionedXcm::from(message.clone())), - ), - crate::Error::::SendFailure - ); + ); + assert_noop!(result, Error::::SendFailure); + assert!(log_capture + .contains("xcm::pallet_xcm::send: XCM send failed with error error=Transport(\"Destination location full\")")); + }); }); } @@ -1456,3 +1464,100 @@ fn record_xcm_works() { assert_eq!(RecordedXcm::::get(), Some(message.into())); }); } + +#[test] +fn execute_initiate_transfer_and_check_sent_event() { + use crate::Event; + use sp_tracing::{ + test_log_capture::init_log_capture, + tracing::{subscriber, Level}, + }; + + let (log_capture, subscriber) = init_log_capture(Level::TRACE, true); + subscriber::with_default(subscriber, || { + let balances = vec![(ALICE, INITIAL_BALANCE)]; + new_test_ext_with_balances(balances).execute_with(|| { + let beneficiary: Location = + Location::new(1, [AccountId32 { network: None, id: BOB.into() }]); + let fee_asset: Asset = (Parent, SEND_AMOUNT).into(); + + let message = Xcm(vec![InitiateReserveWithdraw { + assets: Wild(All), + reserve: Parent.into(), + xcm: Xcm(vec![ + BuyExecution { fees: fee_asset.clone(), weight_limit: Unlimited }, + DepositAsset { assets: All.into(), beneficiary: beneficiary.clone() }, + ]), + }]); + + let result = XcmPallet::execute( + RuntimeOrigin::signed(ALICE), + Box::new(VersionedXcm::from(message.clone())), + BaseXcmWeight::get() * 3, + ); + assert_ok!(result); + + let sent_message: Xcm<()> = Xcm(vec![ + WithdrawAsset(Assets::new()), + ClearOrigin, + BuyExecution { fees: fee_asset.clone(), weight_limit: Unlimited }, + DepositAsset { assets: All.into(), beneficiary: beneficiary.clone() }, + ]); + assert!(log_capture + .contains(format!("xcm::send: Sending msg msg={:?}", sent_message).as_str())); + + let origin: Location = AccountId32 { network: None, id: ALICE.into() }.into(); + let sent_msg_id = fake_message_hash(&sent_message); + assert_eq!( + last_events(2), + vec![ + RuntimeEvent::XcmPallet(Event::Sent { + origin, + destination: Parent.into(), + message: Xcm::default(), + message_id: sent_msg_id, + }), + RuntimeEvent::XcmPallet(Event::Attempted { + outcome: Outcome::Complete { used: Weight::from_parts(1_000, 1_000) } + }), + ] + ); + }) + }); +} + +#[test] +fn deliver_failure_with_expect_error() { + use sp_tracing::{ + test_log_capture::init_log_capture, + tracing::{subscriber, Level}, + }; + + let (log_capture, subscriber) = init_log_capture(Level::TRACE, true); + subscriber::with_default(subscriber, || { + let balances = vec![(ALICE, INITIAL_BALANCE)]; + + new_test_ext_with_balances(balances).execute_with(|| { + let message = Xcm(vec![InitiateReserveWithdraw { + assets: Wild(All), + reserve: Parent.into(), + xcm: Xcm(vec![ + ExpectError(Some((1, xcm::latest::Error::Unimplemented))) + ]), + }]); + + let result = XcmPallet::execute( + RuntimeOrigin::signed(ALICE), + Box::new(VersionedXcm::from(message.clone())), + BaseXcmWeight::get() * 3, + ); + + // Expect an error from the send operation + assert!(result.is_err()); + + // Check logs for send attempt and failure + assert!(log_capture.contains("xcm::send: Sending msg msg=Xcm([WithdrawAsset(Assets([])), ClearOrigin, ExpectError(Some((1, Unimplemented)))])")); + assert!(log_capture.contains("xcm::send: XCM failed to deliver with error error=Transport(\"Intentional deliver failure used in tests\")")); + }) + }); +} diff --git a/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mock.rs b/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mock.rs index d24f19fd36680..1184aba6ea43f 100644 --- a/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mock.rs +++ b/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mock.rs @@ -220,6 +220,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = (); + type XcmEventEmitter = (); type AssetTransactor = FungibleTransactor; type OriginConverter = (); type IsReserve = (); diff --git a/polkadot/xcm/xcm-builder/src/process_xcm_message.rs b/polkadot/xcm/xcm-builder/src/process_xcm_message.rs index ff8655a25fd05..d20b6333bbc5b 100644 --- a/polkadot/xcm/xcm-builder/src/process_xcm_message.rs +++ b/polkadot/xcm/xcm-builder/src/process_xcm_message.rs @@ -147,9 +147,11 @@ mod tests { #[test] fn process_message_trivial_fails() { // Trap makes it fail. - assert!(!process(v3_xcm(false)).unwrap()); - assert!(!process(v4_xcm(false)).unwrap()); - assert!(!process(v5_xcm(false)).unwrap()); + sp_io::TestExternalities::default().execute_with(|| { + assert!(!process(v3_xcm(false)).unwrap()); + assert!(!process(v4_xcm(false)).unwrap()); + assert!(!process(v5_xcm(false)).unwrap()); + }); } #[test] @@ -201,26 +203,28 @@ mod tests { #[test] fn process_message_overweight_fails() { - for msg in [v4_xcm(true), v4_xcm(false), v4_xcm(false), v3_xcm(false)] { - let msg = &msg.encode()[..]; + sp_io::TestExternalities::default().execute_with(|| { + for msg in [v4_xcm(true), v4_xcm(false), v4_xcm(false), v3_xcm(false)] { + let msg = &msg.encode()[..]; - // Errors if we stay below a weight limit of 1000. - for i in 0..10 { - let meter = &mut WeightMeter::with_limit((i * 10).into()); + // Errors if we stay below a weight limit of 1000. + for i in 0..10 { + let meter = &mut WeightMeter::with_limit((i * 10).into()); + let mut id = [0; 32]; + assert_err!( + Processor::process_message(msg, ORIGIN, meter, &mut id), + Overweight(1000.into()) + ); + assert_eq!(meter.consumed(), 0.into()); + } + + // Works with a limit of 1000. + let meter = &mut WeightMeter::with_limit(1000.into()); let mut id = [0; 32]; - assert_err!( - Processor::process_message(msg, ORIGIN, meter, &mut id), - Overweight(1000.into()) - ); - assert_eq!(meter.consumed(), 0.into()); + assert_ok!(Processor::process_message(msg, ORIGIN, meter, &mut id)); + assert_eq!(meter.consumed(), 1000.into()); } - - // Works with a limit of 1000. - let meter = &mut WeightMeter::with_limit(1000.into()); - let mut id = [0; 32]; - assert_ok!(Processor::process_message(msg, ORIGIN, meter, &mut id)); - assert_eq!(meter.consumed(), 1000.into()); - } + }); } fn v3_xcm(success: bool) -> VersionedXcm { diff --git a/polkadot/xcm/xcm-builder/src/tests/mock.rs b/polkadot/xcm/xcm-builder/src/tests/mock.rs index cbb44b77e8541..d81044bfffbbe 100644 --- a/polkadot/xcm/xcm-builder/src/tests/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/mock.rs @@ -742,6 +742,7 @@ pub struct TestConfig; impl Config for TestConfig { type RuntimeCall = TestCall; type XcmSender = TestMessageSender; + type XcmEventEmitter = (); type AssetTransactor = TestAssetTransactor; type OriginConverter = TestOriginConverter; type IsReserve = TestIsReserve; diff --git a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs index 3274b07ac2fd7..3a0e17b97dced 100644 --- a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs @@ -204,6 +204,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = TestMessageSender; + type XcmEventEmitter = XcmPallet; type AssetTransactor = LocalAssetsTransactor; type OriginConverter = OriginConverter; type IsReserve = (); diff --git a/polkadot/xcm/xcm-builder/tests/mock/mod.rs b/polkadot/xcm/xcm-builder/tests/mock/mod.rs index c3e5328450824..76656e3214789 100644 --- a/polkadot/xcm/xcm-builder/tests/mock/mod.rs +++ b/polkadot/xcm/xcm-builder/tests/mock/mod.rs @@ -168,6 +168,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = TestXcmRouter; + type XcmEventEmitter = XcmPallet; type AssetTransactor = LocalAssetTransactor; type OriginConverter = LocalOriginConverter; type IsReserve = (); diff --git a/polkadot/xcm/xcm-builder/tests/scenarios.rs b/polkadot/xcm/xcm-builder/tests/scenarios.rs index d7993e89eeebd..793d4f8b49bdd 100644 --- a/polkadot/xcm/xcm-builder/tests/scenarios.rs +++ b/polkadot/xcm/xcm-builder/tests/scenarios.rs @@ -372,6 +372,7 @@ fn recursive_xcm_execution_fail() { impl xcm_executor::Config for XcmTestConfig { type RuntimeCall = RuntimeCall; type XcmSender = TestXcmRouter; + type XcmEventEmitter = (); type AssetTransactor = LocalAssetTransactor; type OriginConverter = (); type IsReserve = (); diff --git a/polkadot/xcm/xcm-executor/src/config.rs b/polkadot/xcm/xcm-executor/src/config.rs index 5bcbbd3466e8e..60a5ed63f32ee 100644 --- a/polkadot/xcm/xcm-executor/src/config.rs +++ b/polkadot/xcm/xcm-executor/src/config.rs @@ -15,8 +15,8 @@ // along with Polkadot. If not, see . use crate::traits::{ - AssetExchange, AssetLock, CallDispatcher, ClaimAssets, ConvertOrigin, DropAssets, ExportXcm, - FeeManager, HandleHrmpChannelAccepted, HandleHrmpChannelClosing, + AssetExchange, AssetLock, CallDispatcher, ClaimAssets, ConvertOrigin, DropAssets, EventEmitter, + ExportXcm, FeeManager, HandleHrmpChannelAccepted, HandleHrmpChannelClosing, HandleHrmpNewChannelOpenRequest, OnResponse, ProcessTransaction, RecordXcm, ShouldExecute, TransactAsset, VersionChangeNotifier, WeightBounds, WeightTrader, }; @@ -39,6 +39,9 @@ pub trait Config { /// the executor. type XcmSender: SendXcm; + /// How to emit XCM events. + type XcmEventEmitter: EventEmitter; + /// How to withdraw and deposit an asset. type AssetTransactor: TransactAsset; diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs index 794b3cc93ee79..aa4e8e791df1f 100644 --- a/polkadot/xcm/xcm-executor/src/lib.rs +++ b/polkadot/xcm/xcm-executor/src/lib.rs @@ -34,7 +34,7 @@ use xcm::latest::{prelude::*, AssetTransferFilter}; pub mod traits; use traits::{ validate_export, AssetExchange, AssetLock, CallDispatcher, ClaimAssets, ConvertOrigin, - DropAssets, Enact, ExportXcm, FeeManager, FeeReason, HandleHrmpChannelAccepted, + DropAssets, Enact, EventEmitter, ExportXcm, FeeManager, FeeReason, HandleHrmpChannelAccepted, HandleHrmpChannelClosing, HandleHrmpNewChannelOpenRequest, OnResponse, ProcessTransaction, Properties, ShouldExecute, TransactAsset, VersionChangeNotifier, WeightBounds, WeightTrader, XcmAssetTransfers, @@ -438,9 +438,30 @@ impl XcmExecutor { reason = ?reason, "Sending msg", ); - let (ticket, fee) = validate_send::(dest, msg)?; + let (ticket, fee) = validate_send::(dest.clone(), msg)?; self.take_fee(fee, reason)?; - Config::XcmSender::deliver(ticket).map_err(Into::into) + match Config::XcmSender::deliver(ticket) { + Ok(message_id) => { + Config::XcmEventEmitter::emit_sent_event( + self.original_origin.clone(), + dest, + None, /* Avoid logging the full XCM message to prevent inconsistencies and + * reduce storage usage. */ + message_id, + ); + Ok(message_id) + }, + Err(error) => { + tracing::debug!(target: "xcm::send", ?error, "XCM failed to deliver with error"); + Config::XcmEventEmitter::emit_send_failure_event( + self.original_origin.clone(), + dest, + error.clone(), + self.context.message_id, + ); + Err(error.into()) + }, + } } /// Remove the registered error handler and return it. Do not refund its weight. @@ -823,11 +844,19 @@ impl XcmExecutor { self.process_instruction(instr) }); - if let Err(e) = inst_res { - tracing::trace!(target: "xcm::execute", "!!! ERROR: {:?}", e); + if let Err(error) = inst_res { + tracing::debug!( + target: "xcm::process", + ?error, "XCM execution failed at instruction index={i}" + ); + Config::XcmEventEmitter::emit_process_failure_event( + self.original_origin.clone(), + error, + self.context.message_id, + ); *r = Err(ExecutorError { index: i as u32, - xcm_error: e, + xcm_error: error, weight: Weight::zero(), }); } diff --git a/polkadot/xcm/xcm-executor/src/tests/mock.rs b/polkadot/xcm/xcm-executor/src/tests/mock.rs index 11cdbf1128f84..db84e9cabe282 100644 --- a/polkadot/xcm/xcm-executor/src/tests/mock.rs +++ b/polkadot/xcm/xcm-executor/src/tests/mock.rs @@ -288,6 +288,7 @@ pub struct XcmConfig; impl Config for XcmConfig { type RuntimeCall = TestCall; type XcmSender = TestSender; + type XcmEventEmitter = (); type AssetTransactor = TestAssetTransactor; type OriginConverter = (); type IsReserve = (); diff --git a/polkadot/xcm/xcm-executor/src/traits/event_emitter.rs b/polkadot/xcm/xcm-executor/src/traits/event_emitter.rs new file mode 100644 index 0000000000000..5457b30c045ff --- /dev/null +++ b/polkadot/xcm/xcm-executor/src/traits/event_emitter.rs @@ -0,0 +1,83 @@ +// Copyright (C) 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 . + +use xcm::{ + latest::{Location, SendError, Xcm, XcmHash}, + prelude::XcmError, +}; + +/// Defines the event emitter for the XCM executor. +/// This trait allows implementations to emit events related to XCM handling, including successful +/// sends and failure cases. +pub trait EventEmitter { + /// Emits an event when an XCM is successfully sent. + /// + /// # Parameters + /// - `origin`: The origin location of the XCM. + /// - `destination`: The target location where the message is sent. + /// - `message`: `Some(Xcm)` for `pallet_xcm::Event::Sent`, `None` for other events to reduce + /// - `message_id`: A unique identifier for the XCM. storage. + fn emit_sent_event( + origin: Location, + destination: Location, + message: Option>, + message_id: XcmHash, + ); + + /// Emits an event when an XCM fails to send. + /// + /// # Parameters + /// - `origin`: The origin location of the XCM. + /// - `destination`: The intended target location. + /// - `error`: The error encountered while sending. + /// - `message_id`: The unique identifier for the failed message. + fn emit_send_failure_event( + origin: Location, + destination: Location, + error: SendError, + message_id: XcmHash, + ); + + /// Emits an event when an XCM fails to process. + /// + /// # Parameters + /// - `origin`: The origin location of the message. + /// - `error`: The error encountered while processing. + /// - `message_id`: The unique identifier for the failed message. + fn emit_process_failure_event(origin: Location, error: XcmError, message_id: XcmHash); +} + +/// A no-op implementation of `EventEmitter` for unit type `()`. +/// This can be used when event emission is not required. +impl EventEmitter for () { + fn emit_sent_event( + _origin: Location, + _destination: Location, + _message: Option>, + _message_id: XcmHash, + ) { + } + + fn emit_send_failure_event( + _origin: Location, + _destination: Location, + _error: SendError, + _message_id: XcmHash, + ) { + } + + fn emit_process_failure_event(_origin: Location, _error: XcmError, _message_id: XcmHash) {} +} diff --git a/polkadot/xcm/xcm-executor/src/traits/mod.rs b/polkadot/xcm/xcm-executor/src/traits/mod.rs index fe73477f516fb..e70d2c2f4f3af 100644 --- a/polkadot/xcm/xcm-executor/src/traits/mod.rs +++ b/polkadot/xcm/xcm-executor/src/traits/mod.rs @@ -49,8 +49,11 @@ mod hrmp; pub use hrmp::{ HandleHrmpChannelAccepted, HandleHrmpChannelClosing, HandleHrmpNewChannelOpenRequest, }; +mod event_emitter; mod record_xcm; mod weight; +pub use event_emitter::EventEmitter; + pub use record_xcm::RecordXcm; #[deprecated = "Use `sp_runtime::traits::` instead"] pub use sp_runtime::traits::{Identity, TryConvertInto as JustTry}; @@ -59,10 +62,10 @@ pub use weight::{WeightBounds, WeightTrader}; pub mod prelude { pub use super::{ export_xcm, validate_export, AssetExchange, AssetLock, ClaimAssets, ConvertOrigin, - DropAssets, Enact, Error, ExportXcm, FeeManager, FeeReason, LockError, MatchesFungible, - MatchesFungibles, MatchesNonFungible, MatchesNonFungibles, OnResponse, ProcessTransaction, - ShouldExecute, TransactAsset, VersionChangeNotifier, WeightBounds, WeightTrader, - WithOriginFilter, + DropAssets, Enact, Error, EventEmitter, ExportXcm, FeeManager, FeeReason, LockError, + MatchesFungible, MatchesFungibles, MatchesNonFungible, MatchesNonFungibles, OnResponse, + ProcessTransaction, ShouldExecute, TransactAsset, VersionChangeNotifier, WeightBounds, + WeightTrader, WithOriginFilter, }; #[allow(deprecated)] pub use super::{Identity, JustTry}; diff --git a/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs b/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs index ba0ba95442e9c..c9683e0268290 100644 --- a/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs +++ b/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs @@ -392,25 +392,23 @@ fn dry_run_xcm_common(xcm_version: XcmVersion) { ) .unwrap() .unwrap(); + let expected_xcms = Xcm::<()>::builder_unsafe() + .reserve_asset_deposited(( + (Parent, Parachain(2000)), + transfer_amount + execution_fees - DeliveryFees::get(), + )) + .clear_origin() + .buy_execution((Here, 1u128), Unlimited) + .deposit_asset(AllCounted(1), [0u8; 32]) + .build(); + let expected_msg_id = fake_message_hash(&expected_xcms); assert_eq!( dry_run_effects.forwarded_xcms, vec![( VersionedLocation::from((Parent, Parachain(2100))) .into_version(xcm_version) .unwrap(), - vec![VersionedXcm::from( - Xcm::<()>::builder_unsafe() - .reserve_asset_deposited(( - (Parent, Parachain(2000)), - transfer_amount + execution_fees - DeliveryFees::get() - )) - .clear_origin() - .buy_execution((Here, 1u128), Unlimited) - .deposit_asset(AllCounted(1), [0u8; 32]) - .build() - ) - .into_version(xcm_version) - .unwrap()], + vec![VersionedXcm::from(expected_xcms).into_version(xcm_version).unwrap()], ),] ); @@ -424,6 +422,12 @@ fn dry_run_xcm_common(xcm_version: XcmVersion) { free_balance: 520 }), RuntimeEvent::Balances(pallet_balances::Event::Minted { who: 2100, amount: 520 }), + RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { + origin: (who,).into(), + destination: (Parent, Parachain(2100)).into(), + message: Xcm::default(), + message_id: expected_msg_id, + }) ] ); }); diff --git a/polkadot/xcm/xcm-runtime-apis/tests/mock.rs b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs index 9da4030fef159..9c5be8a563404 100644 --- a/polkadot/xcm/xcm-runtime-apis/tests/mock.rs +++ b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs @@ -300,6 +300,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = XcmPallet; type AssetTransactor = AssetTransactors; type OriginConverter = (); type IsReserve = RelayTokenToAssetHub; diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/mod.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/mod.rs index a6b55d1bd9be0..8278d645cb504 100644 --- a/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/mod.rs +++ b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/mod.rs @@ -34,6 +34,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = asset_transactor::AssetTransactor; type OriginConverter = origin_converter::OriginConverter; type IsReserve = reserve::TrustedReserves; diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/mod.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/mod.rs index 6218915cd12d6..9a4cd0cb8f2ce 100644 --- a/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/mod.rs +++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/mod.rs @@ -34,6 +34,7 @@ pub struct XcmConfig; impl Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = (); type AssetTransactor = asset_transactor::AssetTransactor; type OriginConverter = origin_converter::OriginConverter; type IsReserve = (); diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs index 38530fd3f5aa5..025cda3707594 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs @@ -120,6 +120,7 @@ pub struct XcmConfig; impl Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = (); type AssetTransactor = LocalAssetTransactor; type OriginConverter = XcmOriginToCallOrigin; type IsReserve = NativeAsset; diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs index 58687b4785262..e5c37531fb10a 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs @@ -123,6 +123,7 @@ pub struct XcmConfig; impl Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = (); type AssetTransactor = LocalAssetTransactor; type OriginConverter = LocalOriginConverter; type IsReserve = (); diff --git a/prdoc/pr_7234.prdoc b/prdoc/pr_7234.prdoc new file mode 100644 index 0000000000000..7a0daf5971ff4 --- /dev/null +++ b/prdoc/pr_7234.prdoc @@ -0,0 +1,60 @@ +title: Add EventEmitter to XCM Executor +doc: +- audience: Runtime Dev + description: |- + This PR introduces the `EventEmitter` trait to the XCM executor, allowing configurable event emission. +crates: +- name: pallet-xcm-bridge-hub + bump: patch +- name: asset-hub-rococo-runtime + bump: minor +- name: asset-hub-westend-runtime + bump: minor +- name: bridge-hub-rococo-runtime + bump: minor +- name: bridge-hub-westend-runtime + bump: minor +- name: collectives-westend-runtime + bump: minor +- name: coretime-rococo-runtime + bump: minor +- name: coretime-westend-runtime + bump: minor +- name: glutton-westend-runtime + bump: minor +- name: people-rococo-runtime + bump: minor +- name: people-westend-runtime + bump: minor +- name: penpal-runtime + bump: minor +- name: rococo-parachain-runtime + bump: minor +- name: rococo-runtime + bump: minor +- name: westend-runtime + bump: minor +- name: pallet-xcm-benchmarks + bump: patch +- name: pallet-xcm + bump: major +- name: staging-xcm-builder + bump: patch +- name: staging-xcm-executor + bump: major +- name: xcm-runtime-apis + bump: patch +- name: xcm-simulator-example + bump: patch +- name: xcm-simulator-fuzzer + bump: patch +- name: pallet-contracts-mock-network + bump: minor +- name: pallet-revive-mock-network + bump: minor +- name: bridge-runtime-common + bump: minor +- name: pallet-bridge-grandpa + bump: minor +- name: pallet-bridge-messages + bump: minor \ No newline at end of file diff --git a/substrate/frame/contracts/mock-network/src/parachain.rs b/substrate/frame/contracts/mock-network/src/parachain.rs index 6e422927cb2b5..2c24682ae91d9 100644 --- a/substrate/frame/contracts/mock-network/src/parachain.rs +++ b/substrate/frame/contracts/mock-network/src/parachain.rs @@ -255,6 +255,7 @@ pub struct XcmConfig; impl Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToCallOrigin; type IsReserve = (NativeAsset, TrustedReserves); diff --git a/substrate/frame/contracts/mock-network/src/relay_chain.rs b/substrate/frame/contracts/mock-network/src/relay_chain.rs index 221943654c6c9..d6c092d4c8343 100644 --- a/substrate/frame/contracts/mock-network/src/relay_chain.rs +++ b/substrate/frame/contracts/mock-network/src/relay_chain.rs @@ -155,6 +155,7 @@ pub struct XcmConfig; impl Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = XcmPallet; type AssetTransactor = AssetTransactors; type OriginConverter = LocalOriginConverter; type IsReserve = (); diff --git a/substrate/frame/revive/mock-network/src/parachain.rs b/substrate/frame/revive/mock-network/src/parachain.rs index 77a9b912f9a66..fcb6beabce353 100644 --- a/substrate/frame/revive/mock-network/src/parachain.rs +++ b/substrate/frame/revive/mock-network/src/parachain.rs @@ -255,6 +255,7 @@ pub struct XcmConfig; impl Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToCallOrigin; type IsReserve = (NativeAsset, TrustedReserves); diff --git a/substrate/frame/revive/mock-network/src/relay_chain.rs b/substrate/frame/revive/mock-network/src/relay_chain.rs index 221943654c6c9..d6c092d4c8343 100644 --- a/substrate/frame/revive/mock-network/src/relay_chain.rs +++ b/substrate/frame/revive/mock-network/src/relay_chain.rs @@ -155,6 +155,7 @@ pub struct XcmConfig; impl Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = XcmPallet; type AssetTransactor = AssetTransactors; type OriginConverter = LocalOriginConverter; type IsReserve = (); diff --git a/templates/parachain/runtime/src/configs/xcm_config.rs b/templates/parachain/runtime/src/configs/xcm_config.rs index ab1ce0d41d666..7328b3d163f0b 100644 --- a/templates/parachain/runtime/src/configs/xcm_config.rs +++ b/templates/parachain/runtime/src/configs/xcm_config.rs @@ -120,6 +120,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; // How to withdraw and deposit an asset. type AssetTransactor = LocalAssetTransactor; type OriginConverter = XcmOriginToTransactDispatchOrigin;