mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 10:31:03 +00:00
XCM: Tools for uniquely referencing messages (#7234)
* Tools for unique topic references * Formatting * Naming * Repot into routing.rs. * More things done * Universal Exporter supports topic-as-reference * Some tests for the topic routing * More tests * Paid bridge tests * Add message ID to sending events * Formatting * fix and integrate into test nets * Move DenyThenTry and friend from Cumulus * Append SetTopic rather than prepend * Docs * Docs * Work with new ProcessMessage ID API * Formatting * Fix build * Fixes * Formatting * Update xcm/xcm-builder/src/barriers.rs Co-authored-by: Francisco Aguirre <franciscoaguirreperez@gmail.com> * Update xcm/xcm-builder/src/routing.rs Co-authored-by: Francisco Aguirre <franciscoaguirreperez@gmail.com> * Docs * Rename message_hash * Formatting * ".git/.scripts/commands/fmt/fmt.sh" * Rename * Another Rename * ".git/.scripts/commands/fmt/fmt.sh" * ".git/.scripts/commands/fmt/fmt.sh" * Update xcm/xcm-builder/src/routing.rs Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> --------- Co-authored-by: Francisco Aguirre <franciscoaguirreperez@gmail.com> Co-authored-by: command-bot <> Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>
This commit is contained in:
@@ -41,8 +41,8 @@ use xcm_builder::{
|
|||||||
ChildParachainConvertsVia, ChildSystemParachainAsSuperuser,
|
ChildParachainConvertsVia, ChildSystemParachainAsSuperuser,
|
||||||
CurrencyAdapter as XcmCurrencyAdapter, FixedWeightBounds, IsChildSystemParachain, IsConcrete,
|
CurrencyAdapter as XcmCurrencyAdapter, FixedWeightBounds, IsChildSystemParachain, IsConcrete,
|
||||||
MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32,
|
MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32,
|
||||||
SovereignSignedViaLocation, TakeWeightCredit, UsingComponents, WeightInfoBounds,
|
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
|
||||||
WithComputedOrigin,
|
WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
|
||||||
};
|
};
|
||||||
use xcm_executor::traits::WithOriginFilter;
|
use xcm_executor::traits::WithOriginFilter;
|
||||||
|
|
||||||
@@ -115,14 +115,14 @@ parameter_types! {
|
|||||||
|
|
||||||
/// The XCM router. When we want to send an XCM message, we use this type. It amalgamates all of our
|
/// The XCM router. When we want to send an XCM message, we use this type. It amalgamates all of our
|
||||||
/// individual routers.
|
/// individual routers.
|
||||||
pub type XcmRouter = (
|
pub type XcmRouter = WithUniqueTopic<(
|
||||||
// Only one router so far - use DMP to communicate with child parachains.
|
// Only one router so far - use DMP to communicate with child parachains.
|
||||||
ChildParachainRouter<
|
ChildParachainRouter<
|
||||||
Runtime,
|
Runtime,
|
||||||
XcmPallet,
|
XcmPallet,
|
||||||
ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, Dmp>,
|
ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, Dmp>,
|
||||||
>,
|
>,
|
||||||
);
|
)>;
|
||||||
|
|
||||||
parameter_types! {
|
parameter_types! {
|
||||||
pub const Ksm: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) });
|
pub const Ksm: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) });
|
||||||
@@ -142,7 +142,7 @@ match_types! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The barriers one of which must be passed for an XCM message to be executed.
|
/// The barriers one of which must be passed for an XCM message to be executed.
|
||||||
pub type Barrier = (
|
pub type Barrier = TrailingSetTopicAsId<(
|
||||||
// Weight that is paid for may be consumed.
|
// Weight that is paid for may be consumed.
|
||||||
TakeWeightCredit,
|
TakeWeightCredit,
|
||||||
// Expected responses are OK.
|
// Expected responses are OK.
|
||||||
@@ -159,7 +159,7 @@ pub type Barrier = (
|
|||||||
UniversalLocation,
|
UniversalLocation,
|
||||||
ConstU32<8>,
|
ConstU32<8>,
|
||||||
>,
|
>,
|
||||||
);
|
)>;
|
||||||
|
|
||||||
/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly
|
/// A call filter for the XCM Transact instruction. This is a temporary measure until we properly
|
||||||
/// account for proof size weights.
|
/// account for proof size weights.
|
||||||
|
|||||||
@@ -40,7 +40,8 @@ use xcm_builder::{
|
|||||||
ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser,
|
ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser,
|
||||||
CurrencyAdapter as XcmCurrencyAdapter, FixedWeightBounds, IsChildSystemParachain, IsConcrete,
|
CurrencyAdapter as XcmCurrencyAdapter, FixedWeightBounds, IsChildSystemParachain, IsConcrete,
|
||||||
MintLocation, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation,
|
MintLocation, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation,
|
||||||
TakeWeightCredit, UsingComponents, WeightInfoBounds, WithComputedOrigin,
|
TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin,
|
||||||
|
WithUniqueTopic,
|
||||||
};
|
};
|
||||||
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
|
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
|
||||||
|
|
||||||
@@ -95,14 +96,14 @@ parameter_types! {
|
|||||||
|
|
||||||
/// The XCM router. When we want to send an XCM message, we use this type. It amalgamates all of our
|
/// The XCM router. When we want to send an XCM message, we use this type. It amalgamates all of our
|
||||||
/// individual routers.
|
/// individual routers.
|
||||||
pub type XcmRouter = (
|
pub type XcmRouter = WithUniqueTopic<(
|
||||||
// Only one router so far - use DMP to communicate with child parachains.
|
// Only one router so far - use DMP to communicate with child parachains.
|
||||||
ChildParachainRouter<
|
ChildParachainRouter<
|
||||||
Runtime,
|
Runtime,
|
||||||
XcmPallet,
|
XcmPallet,
|
||||||
ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, Dmp>,
|
ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, Dmp>,
|
||||||
>,
|
>,
|
||||||
);
|
)>;
|
||||||
|
|
||||||
parameter_types! {
|
parameter_types! {
|
||||||
pub const Roc: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) });
|
pub const Roc: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) });
|
||||||
@@ -137,7 +138,7 @@ match_types! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The barriers one of which must be passed for an XCM message to be executed.
|
/// The barriers one of which must be passed for an XCM message to be executed.
|
||||||
pub type Barrier = (
|
pub type Barrier = TrailingSetTopicAsId<(
|
||||||
// Weight that is paid for may be consumed.
|
// Weight that is paid for may be consumed.
|
||||||
TakeWeightCredit,
|
TakeWeightCredit,
|
||||||
// Expected responses are OK.
|
// Expected responses are OK.
|
||||||
@@ -154,7 +155,7 @@ pub type Barrier = (
|
|||||||
UniversalLocation,
|
UniversalLocation,
|
||||||
ConstU32<8>,
|
ConstU32<8>,
|
||||||
>,
|
>,
|
||||||
);
|
)>;
|
||||||
|
|
||||||
/// A call filter for the XCM Transact instruction. This is a temporary measure until we
|
/// A call filter for the XCM Transact instruction. This is a temporary measure until we
|
||||||
/// properly account for proof size weights.
|
/// properly account for proof size weights.
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ use xcm_builder::{
|
|||||||
ChildParachainConvertsVia, ChildSystemParachainAsSuperuser,
|
ChildParachainConvertsVia, ChildSystemParachainAsSuperuser,
|
||||||
CurrencyAdapter as XcmCurrencyAdapter, IsChildSystemParachain, IsConcrete, MintLocation,
|
CurrencyAdapter as XcmCurrencyAdapter, IsChildSystemParachain, IsConcrete, MintLocation,
|
||||||
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
|
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
|
||||||
UsingComponents, WeightInfoBounds, WithComputedOrigin,
|
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
|
||||||
};
|
};
|
||||||
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
|
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
|
||||||
|
|
||||||
@@ -80,14 +80,14 @@ type LocalOriginConverter = (
|
|||||||
|
|
||||||
/// The XCM router. When we want to send an XCM message, we use this type. It amalgamates all of our
|
/// The XCM router. When we want to send an XCM message, we use this type. It amalgamates all of our
|
||||||
/// individual routers.
|
/// individual routers.
|
||||||
pub type XcmRouter = (
|
pub type XcmRouter = WithUniqueTopic<(
|
||||||
// Only one router so far - use DMP to communicate with child parachains.
|
// Only one router so far - use DMP to communicate with child parachains.
|
||||||
ChildParachainRouter<
|
ChildParachainRouter<
|
||||||
Runtime,
|
Runtime,
|
||||||
XcmPallet,
|
XcmPallet,
|
||||||
ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, Dmp>,
|
ExponentialPrice<FeeAssetId, BaseDeliveryFee, TransactionByteFee, Dmp>,
|
||||||
>,
|
>,
|
||||||
);
|
)>;
|
||||||
|
|
||||||
parameter_types! {
|
parameter_types! {
|
||||||
pub const Westmint: MultiLocation = Parachain(1000).into_location();
|
pub const Westmint: MultiLocation = Parachain(1000).into_location();
|
||||||
@@ -108,7 +108,7 @@ pub type TrustedTeleporters =
|
|||||||
(xcm_builder::Case<WndForWestmint>, xcm_builder::Case<WndForCollectives>);
|
(xcm_builder::Case<WndForWestmint>, xcm_builder::Case<WndForCollectives>);
|
||||||
|
|
||||||
/// The barriers one of which must be passed for an XCM message to be executed.
|
/// The barriers one of which must be passed for an XCM message to be executed.
|
||||||
pub type Barrier = (
|
pub type Barrier = TrailingSetTopicAsId<(
|
||||||
// Weight that is paid for may be consumed.
|
// Weight that is paid for may be consumed.
|
||||||
TakeWeightCredit,
|
TakeWeightCredit,
|
||||||
// Expected responses are OK.
|
// Expected responses are OK.
|
||||||
@@ -125,7 +125,7 @@ pub type Barrier = (
|
|||||||
UniversalLocation,
|
UniversalLocation,
|
||||||
ConstU32<8>,
|
ConstU32<8>,
|
||||||
>,
|
>,
|
||||||
);
|
)>;
|
||||||
|
|
||||||
/// A call filter for the XCM Transact instruction. This is a temporary measure until we
|
/// A call filter for the XCM Transact instruction. This is a temporary measure until we
|
||||||
/// properly account for proof size weights.
|
/// properly account for proof size weights.
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ benchmarks_instance_pallet! {
|
|||||||
&sender_location,
|
&sender_location,
|
||||||
&XcmContext {
|
&XcmContext {
|
||||||
origin: Some(sender_location.clone()),
|
origin: Some(sender_location.clone()),
|
||||||
message_hash: [0; 32],
|
message_id: [0; 32],
|
||||||
topic: None,
|
topic: None,
|
||||||
},
|
},
|
||||||
).unwrap();
|
).unwrap();
|
||||||
@@ -82,7 +82,7 @@ benchmarks_instance_pallet! {
|
|||||||
&sender_location,
|
&sender_location,
|
||||||
&XcmContext {
|
&XcmContext {
|
||||||
origin: Some(sender_location.clone()),
|
origin: Some(sender_location.clone()),
|
||||||
message_hash: [0; 32],
|
message_id: [0; 32],
|
||||||
topic: None,
|
topic: None,
|
||||||
},
|
},
|
||||||
).unwrap();
|
).unwrap();
|
||||||
@@ -109,7 +109,7 @@ benchmarks_instance_pallet! {
|
|||||||
&sender_location,
|
&sender_location,
|
||||||
&XcmContext {
|
&XcmContext {
|
||||||
origin: Some(sender_location.clone()),
|
origin: Some(sender_location.clone()),
|
||||||
message_hash: [0; 32],
|
message_id: [0; 32],
|
||||||
topic: None,
|
topic: None,
|
||||||
},
|
},
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ benchmarks! {
|
|||||||
assets.clone().into(),
|
assets.clone().into(),
|
||||||
&XcmContext {
|
&XcmContext {
|
||||||
origin: Some(origin.clone()),
|
origin: Some(origin.clone()),
|
||||||
message_hash: [0; 32],
|
message_id: [0; 32],
|
||||||
topic: None,
|
topic: None,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -266,7 +266,7 @@ benchmarks! {
|
|||||||
max_response_weight,
|
max_response_weight,
|
||||||
&XcmContext {
|
&XcmContext {
|
||||||
origin: Some(origin.clone()),
|
origin: Some(origin.clone()),
|
||||||
message_hash: [0; 32],
|
message_id: [0; 32],
|
||||||
topic: None,
|
topic: None,
|
||||||
},
|
},
|
||||||
).map_err(|_| "Could not start subscription")?;
|
).map_err(|_| "Could not start subscription")?;
|
||||||
|
|||||||
+151
-123
@@ -40,7 +40,7 @@ use sp_runtime::{
|
|||||||
};
|
};
|
||||||
use sp_std::{boxed::Box, marker::PhantomData, prelude::*, result::Result, vec};
|
use sp_std::{boxed::Box, marker::PhantomData, prelude::*, result::Result, vec};
|
||||||
use xcm::{latest::QueryResponseInfo, prelude::*};
|
use xcm::{latest::QueryResponseInfo, prelude::*};
|
||||||
use xcm_executor::traits::{Convert, ConvertOrigin};
|
use xcm_executor::traits::{Convert, ConvertOrigin, Properties};
|
||||||
|
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
dispatch::{Dispatchable, GetDispatchInfo},
|
dispatch::{Dispatchable, GetDispatchInfo},
|
||||||
@@ -272,52 +272,49 @@ pub mod pallet {
|
|||||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||||
pub enum Event<T: Config> {
|
pub enum Event<T: Config> {
|
||||||
/// Execution of an XCM message was attempted.
|
/// Execution of an XCM message was attempted.
|
||||||
///
|
Attempted { outcome: xcm::latest::Outcome },
|
||||||
/// \[ outcome \]
|
|
||||||
Attempted(xcm::latest::Outcome),
|
|
||||||
/// A XCM message was sent.
|
/// A XCM message was sent.
|
||||||
///
|
Sent {
|
||||||
/// \[ origin, destination, message \]
|
origin: MultiLocation,
|
||||||
Sent(MultiLocation, MultiLocation, Xcm<()>),
|
destination: MultiLocation,
|
||||||
|
message: Xcm<()>,
|
||||||
|
message_id: XcmHash,
|
||||||
|
},
|
||||||
/// Query response received which does not match a registered query. This may be because a
|
/// 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
|
/// matching query was never registered, it may be because it is a duplicate response, or
|
||||||
/// because the query timed out.
|
/// because the query timed out.
|
||||||
///
|
UnexpectedResponse { origin: MultiLocation, query_id: QueryId },
|
||||||
/// \[ origin location, id \]
|
|
||||||
UnexpectedResponse(MultiLocation, QueryId),
|
|
||||||
/// Query response has been received and is ready for taking with `take_response`. There is
|
/// Query response has been received and is ready for taking with `take_response`. There is
|
||||||
/// no registered notification call.
|
/// no registered notification call.
|
||||||
///
|
ResponseReady { query_id: QueryId, response: Response },
|
||||||
/// \[ id, response \]
|
|
||||||
ResponseReady(QueryId, Response),
|
|
||||||
/// Query response has been received and query is removed. The registered notification has
|
/// Query response has been received and query is removed. The registered notification has
|
||||||
/// been dispatched and executed successfully.
|
/// been dispatched and executed successfully.
|
||||||
///
|
Notified { query_id: QueryId, pallet_index: u8, call_index: u8 },
|
||||||
/// \[ id, pallet index, call index \]
|
|
||||||
Notified(QueryId, u8, u8),
|
|
||||||
/// Query response has been received and query is removed. The registered notification could
|
/// Query response has been received and query is removed. The registered notification could
|
||||||
/// not be dispatched because the dispatch weight is greater than the maximum weight
|
/// not be dispatched because the dispatch weight is greater than the maximum weight
|
||||||
/// originally budgeted by this runtime for the query result.
|
/// originally budgeted by this runtime for the query result.
|
||||||
///
|
NotifyOverweight {
|
||||||
/// \[ id, pallet index, call index, actual weight, max budgeted weight \]
|
query_id: QueryId,
|
||||||
NotifyOverweight(QueryId, u8, u8, Weight, Weight),
|
pallet_index: u8,
|
||||||
|
call_index: u8,
|
||||||
|
actual_weight: Weight,
|
||||||
|
max_budgeted_weight: Weight,
|
||||||
|
},
|
||||||
/// Query response has been received and query is removed. There was a general error with
|
/// Query response has been received and query is removed. There was a general error with
|
||||||
/// dispatching the notification call.
|
/// dispatching the notification call.
|
||||||
///
|
NotifyDispatchError { query_id: QueryId, pallet_index: u8, call_index: u8 },
|
||||||
/// \[ id, pallet index, call index \]
|
|
||||||
NotifyDispatchError(QueryId, u8, u8),
|
|
||||||
/// Query response has been received and query is removed. The dispatch was unable to be
|
/// Query response has been received and query is removed. The dispatch was unable to be
|
||||||
/// decoded into a `Call`; this might be due to dispatch function having a signature which
|
/// decoded into a `Call`; this might be due to dispatch function having a signature which
|
||||||
/// is not `(origin, QueryId, Response)`.
|
/// is not `(origin, QueryId, Response)`.
|
||||||
///
|
NotifyDecodeFailed { query_id: QueryId, pallet_index: u8, call_index: u8 },
|
||||||
/// \[ id, pallet index, call index \]
|
|
||||||
NotifyDecodeFailed(QueryId, u8, u8),
|
|
||||||
/// Expected query response has been received but the origin location of the response does
|
/// Expected query response has been received but the origin location of the response does
|
||||||
/// not match that expected. The query remains registered for a later, valid, response to
|
/// not match that expected. The query remains registered for a later, valid, response to
|
||||||
/// be received and acted upon.
|
/// be received and acted upon.
|
||||||
///
|
InvalidResponder {
|
||||||
/// \[ origin location, id, expected location \]
|
origin: MultiLocation,
|
||||||
InvalidResponder(MultiLocation, QueryId, Option<MultiLocation>),
|
query_id: QueryId,
|
||||||
|
expected_location: Option<MultiLocation>,
|
||||||
|
},
|
||||||
/// Expected query response has been received but the expected origin location placed in
|
/// Expected query response has been received but the expected origin location placed in
|
||||||
/// storage by this runtime previously cannot be decoded. The query remains registered.
|
/// storage by this runtime previously cannot be decoded. The query remains registered.
|
||||||
///
|
///
|
||||||
@@ -325,38 +322,29 @@ pub mod pallet {
|
|||||||
/// runtime should be readable prior to query timeout) and dangerous since the possibly
|
/// runtime should be readable prior to query timeout) and dangerous since the possibly
|
||||||
/// valid response will be dropped. Manual governance intervention is probably going to be
|
/// valid response will be dropped. Manual governance intervention is probably going to be
|
||||||
/// needed.
|
/// needed.
|
||||||
///
|
InvalidResponderVersion { origin: MultiLocation, query_id: QueryId },
|
||||||
/// \[ origin location, id \]
|
|
||||||
InvalidResponderVersion(MultiLocation, QueryId),
|
|
||||||
/// Received query response has been read and removed.
|
/// Received query response has been read and removed.
|
||||||
///
|
ResponseTaken { query_id: QueryId },
|
||||||
/// \[ id \]
|
|
||||||
ResponseTaken(QueryId),
|
|
||||||
/// Some assets have been placed in an asset trap.
|
/// Some assets have been placed in an asset trap.
|
||||||
///
|
AssetsTrapped { hash: H256, origin: MultiLocation, assets: VersionedMultiAssets },
|
||||||
/// \[ hash, origin, assets \]
|
|
||||||
AssetsTrapped(H256, MultiLocation, VersionedMultiAssets),
|
|
||||||
/// An XCM version change notification message has been attempted to be sent.
|
/// An XCM version change notification message has been attempted to be sent.
|
||||||
///
|
///
|
||||||
/// The cost of sending it (borne by the chain) is included.
|
/// The cost of sending it (borne by the chain) is included.
|
||||||
///
|
VersionChangeNotified {
|
||||||
/// \[ destination, result, cost \]
|
destination: MultiLocation,
|
||||||
VersionChangeNotified(MultiLocation, XcmVersion, MultiAssets),
|
result: XcmVersion,
|
||||||
|
cost: MultiAssets,
|
||||||
|
message_id: XcmHash,
|
||||||
|
},
|
||||||
/// The supported version of a location has been changed. This might be through an
|
/// The supported version of a location has been changed. This might be through an
|
||||||
/// automatic notification or a manual intervention.
|
/// automatic notification or a manual intervention.
|
||||||
///
|
SupportedVersionChanged { location: MultiLocation, version: XcmVersion },
|
||||||
/// \[ location, XCM version \]
|
|
||||||
SupportedVersionChanged(MultiLocation, XcmVersion),
|
|
||||||
/// A given location which had a version change subscription was dropped owing to an error
|
/// A given location which had a version change subscription was dropped owing to an error
|
||||||
/// sending the notification to it.
|
/// sending the notification to it.
|
||||||
///
|
NotifyTargetSendFail { location: MultiLocation, query_id: QueryId, error: XcmError },
|
||||||
/// \[ location, query ID, error \]
|
|
||||||
NotifyTargetSendFail(MultiLocation, QueryId, XcmError),
|
|
||||||
/// A given location which had a version change subscription was dropped owing to an error
|
/// A given location which had a version change subscription was dropped owing to an error
|
||||||
/// migrating the location to our new XCM format.
|
/// migrating the location to our new XCM format.
|
||||||
///
|
NotifyTargetMigrationFail { location: VersionedMultiLocation, query_id: QueryId },
|
||||||
/// \[ location, query ID \]
|
|
||||||
NotifyTargetMigrationFail(VersionedMultiLocation, QueryId),
|
|
||||||
/// Expected query response has been received but the expected querier location placed in
|
/// Expected query response has been received but the expected querier location placed in
|
||||||
/// storage by this runtime previously cannot be decoded. The query remains registered.
|
/// storage by this runtime previously cannot be decoded. The query remains registered.
|
||||||
///
|
///
|
||||||
@@ -364,36 +352,35 @@ pub mod pallet {
|
|||||||
/// runtime should be readable prior to query timeout) and dangerous since the possibly
|
/// runtime should be readable prior to query timeout) and dangerous since the possibly
|
||||||
/// valid response will be dropped. Manual governance intervention is probably going to be
|
/// valid response will be dropped. Manual governance intervention is probably going to be
|
||||||
/// needed.
|
/// needed.
|
||||||
///
|
InvalidQuerierVersion { origin: MultiLocation, query_id: QueryId },
|
||||||
/// \[ origin location, id \]
|
|
||||||
InvalidQuerierVersion(MultiLocation, QueryId),
|
|
||||||
/// Expected query response has been received but the querier location of the response does
|
/// Expected query response has been received but the querier location of the response does
|
||||||
/// not match the expected. The query remains registered for a later, valid, response to
|
/// not match the expected. The query remains registered for a later, valid, response to
|
||||||
/// be received and acted upon.
|
/// be received and acted upon.
|
||||||
///
|
InvalidQuerier {
|
||||||
/// \[ origin location, id, expected querier, maybe actual querier \]
|
origin: MultiLocation,
|
||||||
InvalidQuerier(MultiLocation, QueryId, MultiLocation, Option<MultiLocation>),
|
query_id: QueryId,
|
||||||
|
expected_querier: MultiLocation,
|
||||||
|
maybe_actual_querier: Option<MultiLocation>,
|
||||||
|
},
|
||||||
/// A remote has requested XCM version change notification from us and we have honored it.
|
/// A remote has requested XCM version change notification from us and we have honored it.
|
||||||
/// A version information message is sent to them and its cost is included.
|
/// A version information message is sent to them and its cost is included.
|
||||||
///
|
VersionNotifyStarted { destination: MultiLocation, cost: MultiAssets, message_id: XcmHash },
|
||||||
/// \[ destination location, cost \]
|
/// We have requested that a remote chain send us XCM version change notifications.
|
||||||
VersionNotifyStarted(MultiLocation, MultiAssets),
|
VersionNotifyRequested {
|
||||||
/// We have requested that a remote chain sends us XCM version change notifications.
|
destination: MultiLocation,
|
||||||
///
|
cost: MultiAssets,
|
||||||
/// \[ destination location, cost \]
|
message_id: XcmHash,
|
||||||
VersionNotifyRequested(MultiLocation, MultiAssets),
|
},
|
||||||
/// We have requested that a remote chain stops sending us XCM version change notifications.
|
/// We have requested that a remote chain stops sending us XCM version change notifications.
|
||||||
///
|
VersionNotifyUnrequested {
|
||||||
/// \[ destination location, cost \]
|
destination: MultiLocation,
|
||||||
VersionNotifyUnrequested(MultiLocation, MultiAssets),
|
cost: MultiAssets,
|
||||||
|
message_id: XcmHash,
|
||||||
|
},
|
||||||
/// Fees were paid from a location for an operation (often for using `SendXcm`).
|
/// Fees were paid from a location for an operation (often for using `SendXcm`).
|
||||||
///
|
FeesPaid { paying: MultiLocation, fees: MultiAssets },
|
||||||
/// \[ paying location, fees \]
|
|
||||||
FeesPaid(MultiLocation, MultiAssets),
|
|
||||||
/// Some assets have been claimed from an asset trap
|
/// Some assets have been claimed from an asset trap
|
||||||
///
|
AssetsClaimed { hash: H256, origin: MultiLocation, assets: VersionedMultiAssets },
|
||||||
/// \[ hash, origin, assets \]
|
|
||||||
AssetsClaimed(H256, MultiLocation, VersionedMultiAssets),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pallet::origin]
|
#[pallet::origin]
|
||||||
@@ -793,8 +780,10 @@ pub mod pallet {
|
|||||||
let dest = MultiLocation::try_from(*dest).map_err(|()| Error::<T>::BadVersion)?;
|
let dest = MultiLocation::try_from(*dest).map_err(|()| Error::<T>::BadVersion)?;
|
||||||
let message: Xcm<()> = (*message).try_into().map_err(|()| Error::<T>::BadVersion)?;
|
let message: Xcm<()> = (*message).try_into().map_err(|()| Error::<T>::BadVersion)?;
|
||||||
|
|
||||||
|
let message_id =
|
||||||
Self::send_xcm(interior, dest, message.clone()).map_err(Error::<T>::from)?;
|
Self::send_xcm(interior, dest, message.clone()).map_err(Error::<T>::from)?;
|
||||||
Self::deposit_event(Event::Sent(origin_location, dest, message));
|
let e = Event::Sent { origin: origin_location, destination: dest, message, message_id };
|
||||||
|
Self::deposit_event(e);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -927,7 +916,7 @@ pub mod pallet {
|
|||||||
);
|
);
|
||||||
let result =
|
let result =
|
||||||
Ok(Some(outcome.weight_used().saturating_add(T::WeightInfo::execute())).into());
|
Ok(Some(outcome.weight_used().saturating_add(T::WeightInfo::execute())).into());
|
||||||
Self::deposit_event(Event::Attempted(outcome));
|
Self::deposit_event(Event::Attempted { outcome });
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -942,16 +931,16 @@ pub mod pallet {
|
|||||||
pub fn force_xcm_version(
|
pub fn force_xcm_version(
|
||||||
origin: OriginFor<T>,
|
origin: OriginFor<T>,
|
||||||
location: Box<MultiLocation>,
|
location: Box<MultiLocation>,
|
||||||
xcm_version: XcmVersion,
|
version: XcmVersion,
|
||||||
) -> DispatchResult {
|
) -> DispatchResult {
|
||||||
T::AdminOrigin::ensure_origin(origin)?;
|
T::AdminOrigin::ensure_origin(origin)?;
|
||||||
let location = *location;
|
let location = *location;
|
||||||
SupportedVersion::<T>::insert(
|
SupportedVersion::<T>::insert(
|
||||||
XCM_VERSION,
|
XCM_VERSION,
|
||||||
LatestVersionedMultiLocation(&location),
|
LatestVersionedMultiLocation(&location),
|
||||||
xcm_version,
|
version,
|
||||||
);
|
);
|
||||||
Self::deposit_event(Event::SupportedVersionChanged(location, xcm_version));
|
Self::deposit_event(Event::SupportedVersionChanged { location, version });
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1195,7 +1184,7 @@ impl<T: Config> Pallet<T> {
|
|||||||
let hash = message.using_encoded(sp_io::hashing::blake2_256);
|
let hash = message.using_encoded(sp_io::hashing::blake2_256);
|
||||||
let outcome =
|
let outcome =
|
||||||
T::XcmExecutor::execute_xcm_in_credit(origin_location, message, hash, weight, weight);
|
T::XcmExecutor::execute_xcm_in_credit(origin_location, message, hash, weight, weight);
|
||||||
Self::deposit_event(Event::Attempted(outcome));
|
Self::deposit_event(Event::Attempted { outcome });
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1256,7 +1245,7 @@ impl<T: Config> Pallet<T> {
|
|||||||
let hash = message.using_encoded(sp_io::hashing::blake2_256);
|
let hash = message.using_encoded(sp_io::hashing::blake2_256);
|
||||||
let outcome =
|
let outcome =
|
||||||
T::XcmExecutor::execute_xcm_in_credit(origin_location, message, hash, weight, weight);
|
T::XcmExecutor::execute_xcm_in_credit(origin_location, message, hash, weight, weight);
|
||||||
Self::deposit_event(Event::Attempted(outcome));
|
Self::deposit_event(Event::Attempted { outcome });
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1331,14 +1320,19 @@ impl<T: Config> Pallet<T> {
|
|||||||
let message =
|
let message =
|
||||||
Xcm(vec![QueryResponse { query_id, response, max_weight, querier: None }]);
|
Xcm(vec![QueryResponse { query_id, response, max_weight, querier: None }]);
|
||||||
let event = match send_xcm::<T::XcmRouter>(new_key, message) {
|
let event = match send_xcm::<T::XcmRouter>(new_key, message) {
|
||||||
Ok((_hash, cost)) => {
|
Ok((message_id, cost)) => {
|
||||||
let value = (query_id, max_weight, xcm_version);
|
let value = (query_id, max_weight, xcm_version);
|
||||||
VersionNotifyTargets::<T>::insert(XCM_VERSION, key, value);
|
VersionNotifyTargets::<T>::insert(XCM_VERSION, key, value);
|
||||||
Event::VersionChangeNotified(new_key, xcm_version, cost)
|
Event::VersionChangeNotified {
|
||||||
|
destination: new_key,
|
||||||
|
result: xcm_version,
|
||||||
|
cost,
|
||||||
|
message_id,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
VersionNotifyTargets::<T>::remove(XCM_VERSION, key);
|
VersionNotifyTargets::<T>::remove(XCM_VERSION, key);
|
||||||
Event::NotifyTargetSendFail(new_key, query_id, e.into())
|
Event::NotifyTargetSendFail { location: new_key, query_id, error: e.into() }
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
Self::deposit_event(event);
|
Self::deposit_event(event);
|
||||||
@@ -1357,7 +1351,10 @@ impl<T: Config> Pallet<T> {
|
|||||||
let new_key = match MultiLocation::try_from(old_key.clone()) {
|
let new_key = match MultiLocation::try_from(old_key.clone()) {
|
||||||
Ok(k) => k,
|
Ok(k) => k,
|
||||||
Err(()) => {
|
Err(()) => {
|
||||||
Self::deposit_event(Event::NotifyTargetMigrationFail(old_key, value.0));
|
Self::deposit_event(Event::NotifyTargetMigrationFail {
|
||||||
|
location: old_key,
|
||||||
|
query_id: value.0,
|
||||||
|
});
|
||||||
weight_used.saturating_accrue(vnt_migrate_fail_weight);
|
weight_used.saturating_accrue(vnt_migrate_fail_weight);
|
||||||
if weight_used.any_gte(weight_cutoff) {
|
if weight_used.any_gte(weight_cutoff) {
|
||||||
return (weight_used, Some(stage))
|
return (weight_used, Some(stage))
|
||||||
@@ -1380,15 +1377,24 @@ impl<T: Config> Pallet<T> {
|
|||||||
querier: None,
|
querier: None,
|
||||||
}]);
|
}]);
|
||||||
let event = match send_xcm::<T::XcmRouter>(new_key, message) {
|
let event = match send_xcm::<T::XcmRouter>(new_key, message) {
|
||||||
Ok((_hash, cost)) => {
|
Ok((message_id, cost)) => {
|
||||||
VersionNotifyTargets::<T>::insert(
|
VersionNotifyTargets::<T>::insert(
|
||||||
XCM_VERSION,
|
XCM_VERSION,
|
||||||
versioned_key,
|
versioned_key,
|
||||||
(query_id, max_weight, xcm_version),
|
(query_id, max_weight, xcm_version),
|
||||||
);
|
);
|
||||||
Event::VersionChangeNotified(new_key, xcm_version, cost)
|
Event::VersionChangeNotified {
|
||||||
|
destination: new_key,
|
||||||
|
result: xcm_version,
|
||||||
|
cost,
|
||||||
|
message_id,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => Event::NotifyTargetSendFail {
|
||||||
|
location: new_key,
|
||||||
|
query_id,
|
||||||
|
error: e.into(),
|
||||||
},
|
},
|
||||||
Err(e) => Event::NotifyTargetSendFail(new_key, query_id, e.into()),
|
|
||||||
};
|
};
|
||||||
Self::deposit_event(event);
|
Self::deposit_event(event);
|
||||||
weight_used.saturating_accrue(vnt_notify_migrate_weight);
|
weight_used.saturating_accrue(vnt_notify_migrate_weight);
|
||||||
@@ -1415,8 +1421,8 @@ impl<T: Config> Pallet<T> {
|
|||||||
});
|
});
|
||||||
// TODO #3735: Correct weight.
|
// TODO #3735: Correct weight.
|
||||||
let instruction = SubscribeVersion { query_id, max_response_weight: Weight::zero() };
|
let instruction = SubscribeVersion { query_id, max_response_weight: Weight::zero() };
|
||||||
let (_hash, cost) = send_xcm::<T::XcmRouter>(dest, Xcm(vec![instruction]))?;
|
let (message_id, cost) = send_xcm::<T::XcmRouter>(dest, Xcm(vec![instruction]))?;
|
||||||
Self::deposit_event(Event::VersionNotifyRequested(dest, cost));
|
Self::deposit_event(Event::VersionNotifyRequested { destination: dest, cost, message_id });
|
||||||
VersionNotifiers::<T>::insert(XCM_VERSION, &versioned_dest, query_id);
|
VersionNotifiers::<T>::insert(XCM_VERSION, &versioned_dest, query_id);
|
||||||
let query_status =
|
let query_status =
|
||||||
QueryStatus::VersionNotifier { origin: versioned_dest, is_active: false };
|
QueryStatus::VersionNotifier { origin: versioned_dest, is_active: false };
|
||||||
@@ -1430,8 +1436,12 @@ impl<T: Config> Pallet<T> {
|
|||||||
let versioned_dest = LatestVersionedMultiLocation(&dest);
|
let versioned_dest = LatestVersionedMultiLocation(&dest);
|
||||||
let query_id = VersionNotifiers::<T>::take(XCM_VERSION, versioned_dest)
|
let query_id = VersionNotifiers::<T>::take(XCM_VERSION, versioned_dest)
|
||||||
.ok_or(XcmError::InvalidLocation)?;
|
.ok_or(XcmError::InvalidLocation)?;
|
||||||
let (_hash, cost) = send_xcm::<T::XcmRouter>(dest, Xcm(vec![UnsubscribeVersion]))?;
|
let (message_id, cost) = send_xcm::<T::XcmRouter>(dest, Xcm(vec![UnsubscribeVersion]))?;
|
||||||
Self::deposit_event(Event::VersionNotifyUnrequested(dest, cost));
|
Self::deposit_event(Event::VersionNotifyUnrequested {
|
||||||
|
destination: dest,
|
||||||
|
cost,
|
||||||
|
message_id,
|
||||||
|
});
|
||||||
Queries::<T>::remove(query_id);
|
Queries::<T>::remove(query_id);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -1589,7 +1599,7 @@ impl<T: Config> Pallet<T> {
|
|||||||
if let Some(QueryStatus::Ready { response, at }) = Queries::<T>::get(query_id) {
|
if let Some(QueryStatus::Ready { response, at }) = Queries::<T>::get(query_id) {
|
||||||
let response = response.try_into().ok()?;
|
let response = response.try_into().ok()?;
|
||||||
Queries::<T>::remove(query_id);
|
Queries::<T>::remove(query_id);
|
||||||
Self::deposit_event(Event::ResponseTaken(query_id));
|
Self::deposit_event(Event::ResponseTaken { query_id });
|
||||||
Some((response, at))
|
Some((response, at))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@@ -1623,7 +1633,7 @@ impl<T: Config> Pallet<T> {
|
|||||||
fn charge_fees(location: MultiLocation, assets: MultiAssets) -> DispatchResult {
|
fn charge_fees(location: MultiLocation, assets: MultiAssets) -> DispatchResult {
|
||||||
T::XcmExecutor::charge_fees(location, assets.clone())
|
T::XcmExecutor::charge_fees(location, assets.clone())
|
||||||
.map_err(|_| Error::<T>::FeesNotMet)?;
|
.map_err(|_| Error::<T>::FeesNotMet)?;
|
||||||
Self::deposit_event(Event::FeesPaid(location, assets));
|
Self::deposit_event(Event::FeesPaid { paying: location, fees: assets });
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1861,8 +1871,12 @@ impl<T: Config> VersionChangeNotifier for Pallet<T> {
|
|||||||
let xcm_version = T::AdvertisedXcmVersion::get();
|
let xcm_version = T::AdvertisedXcmVersion::get();
|
||||||
let response = Response::Version(xcm_version);
|
let response = Response::Version(xcm_version);
|
||||||
let instruction = QueryResponse { query_id, response, max_weight, querier: None };
|
let instruction = QueryResponse { query_id, response, max_weight, querier: None };
|
||||||
let (_hash, cost) = send_xcm::<T::XcmRouter>(*dest, Xcm(vec![instruction]))?;
|
let (message_id, cost) = send_xcm::<T::XcmRouter>(*dest, Xcm(vec![instruction]))?;
|
||||||
Self::deposit_event(Event::<T>::VersionNotifyStarted(*dest, cost));
|
Self::deposit_event(Event::<T>::VersionNotifyStarted {
|
||||||
|
destination: *dest,
|
||||||
|
cost,
|
||||||
|
message_id,
|
||||||
|
});
|
||||||
|
|
||||||
let value = (query_id, max_weight, xcm_version);
|
let value = (query_id, max_weight, xcm_version);
|
||||||
VersionNotifyTargets::<T>::insert(XCM_VERSION, versioned_dest, value);
|
VersionNotifyTargets::<T>::insert(XCM_VERSION, versioned_dest, value);
|
||||||
@@ -1891,7 +1905,7 @@ impl<T: Config> DropAssets for Pallet<T> {
|
|||||||
let versioned = VersionedMultiAssets::from(MultiAssets::from(assets));
|
let versioned = VersionedMultiAssets::from(MultiAssets::from(assets));
|
||||||
let hash = BlakeTwo256::hash_of(&(&origin, &versioned));
|
let hash = BlakeTwo256::hash_of(&(&origin, &versioned));
|
||||||
AssetTraps::<T>::mutate(hash, |n| *n += 1);
|
AssetTraps::<T>::mutate(hash, |n| *n += 1);
|
||||||
Self::deposit_event(Event::AssetsTrapped(hash, *origin, versioned));
|
Self::deposit_event(Event::AssetsTrapped { hash, origin: *origin, assets: versioned });
|
||||||
// TODO #3735: Put the real weight in there.
|
// TODO #3735: Put the real weight in there.
|
||||||
Weight::zero()
|
Weight::zero()
|
||||||
}
|
}
|
||||||
@@ -1920,7 +1934,7 @@ impl<T: Config> ClaimAssets for Pallet<T> {
|
|||||||
1 => AssetTraps::<T>::remove(hash),
|
1 => AssetTraps::<T>::remove(hash),
|
||||||
n => AssetTraps::<T>::insert(hash, n - 1),
|
n => AssetTraps::<T>::insert(hash, n - 1),
|
||||||
}
|
}
|
||||||
Self::deposit_event(Event::AssetsClaimed(hash, *origin, versioned));
|
Self::deposit_event(Event::AssetsClaimed { hash, origin: *origin, assets: versioned });
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1953,19 +1967,28 @@ impl<T: Config> OnResponse for Pallet<T> {
|
|||||||
max_weight: Weight,
|
max_weight: Weight,
|
||||||
_context: &XcmContext,
|
_context: &XcmContext,
|
||||||
) -> Weight {
|
) -> Weight {
|
||||||
|
let origin = *origin;
|
||||||
match (response, Queries::<T>::get(query_id)) {
|
match (response, Queries::<T>::get(query_id)) {
|
||||||
(
|
(
|
||||||
Response::Version(v),
|
Response::Version(v),
|
||||||
Some(QueryStatus::VersionNotifier { origin: expected_origin, is_active }),
|
Some(QueryStatus::VersionNotifier { origin: expected_origin, is_active }),
|
||||||
) => {
|
) => {
|
||||||
let origin: MultiLocation = match expected_origin.try_into() {
|
let origin: MultiLocation = match expected_origin.try_into() {
|
||||||
Ok(o) if &o == origin => o,
|
Ok(o) if o == origin => o,
|
||||||
Ok(o) => {
|
Ok(o) => {
|
||||||
Self::deposit_event(Event::InvalidResponder(*origin, query_id, Some(o)));
|
Self::deposit_event(Event::InvalidResponder {
|
||||||
|
origin,
|
||||||
|
query_id,
|
||||||
|
expected_location: Some(o),
|
||||||
|
});
|
||||||
return Weight::zero()
|
return Weight::zero()
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
Self::deposit_event(Event::InvalidResponder(*origin, query_id, None));
|
Self::deposit_event(Event::InvalidResponder {
|
||||||
|
origin,
|
||||||
|
query_id,
|
||||||
|
expected_location: None,
|
||||||
|
});
|
||||||
// TODO #3735: Correct weight for this.
|
// TODO #3735: Correct weight for this.
|
||||||
return Weight::zero()
|
return Weight::zero()
|
||||||
},
|
},
|
||||||
@@ -1983,7 +2006,10 @@ impl<T: Config> OnResponse for Pallet<T> {
|
|||||||
LatestVersionedMultiLocation(&origin),
|
LatestVersionedMultiLocation(&origin),
|
||||||
v,
|
v,
|
||||||
);
|
);
|
||||||
Self::deposit_event(Event::SupportedVersionChanged(origin, v));
|
Self::deposit_event(Event::SupportedVersionChanged {
|
||||||
|
location: origin,
|
||||||
|
version: v,
|
||||||
|
});
|
||||||
Weight::zero()
|
Weight::zero()
|
||||||
},
|
},
|
||||||
(
|
(
|
||||||
@@ -1994,33 +2020,33 @@ impl<T: Config> OnResponse for Pallet<T> {
|
|||||||
let match_querier = match MultiLocation::try_from(match_querier) {
|
let match_querier = match MultiLocation::try_from(match_querier) {
|
||||||
Ok(mq) => mq,
|
Ok(mq) => mq,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
Self::deposit_event(Event::InvalidQuerierVersion(*origin, query_id));
|
Self::deposit_event(Event::InvalidQuerierVersion { origin, query_id });
|
||||||
return Weight::zero()
|
return Weight::zero()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
if querier.map_or(true, |q| q != &match_querier) {
|
if querier.map_or(true, |q| q != &match_querier) {
|
||||||
Self::deposit_event(Event::InvalidQuerier(
|
Self::deposit_event(Event::InvalidQuerier {
|
||||||
*origin,
|
origin,
|
||||||
query_id,
|
query_id,
|
||||||
match_querier,
|
expected_querier: match_querier,
|
||||||
querier.cloned(),
|
maybe_actual_querier: querier.cloned(),
|
||||||
));
|
});
|
||||||
return Weight::zero()
|
return Weight::zero()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let responder = match MultiLocation::try_from(responder) {
|
let responder = match MultiLocation::try_from(responder) {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
Self::deposit_event(Event::InvalidResponderVersion(*origin, query_id));
|
Self::deposit_event(Event::InvalidResponderVersion { origin, query_id });
|
||||||
return Weight::zero()
|
return Weight::zero()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
if origin != &responder {
|
if origin != responder {
|
||||||
Self::deposit_event(Event::InvalidResponder(
|
Self::deposit_event(Event::InvalidResponder {
|
||||||
*origin,
|
origin,
|
||||||
query_id,
|
query_id,
|
||||||
Some(responder),
|
expected_location: Some(responder),
|
||||||
));
|
});
|
||||||
return Weight::zero()
|
return Weight::zero()
|
||||||
}
|
}
|
||||||
return match maybe_notify {
|
return match maybe_notify {
|
||||||
@@ -2035,29 +2061,29 @@ impl<T: Config> OnResponse for Pallet<T> {
|
|||||||
Queries::<T>::remove(query_id);
|
Queries::<T>::remove(query_id);
|
||||||
let weight = call.get_dispatch_info().weight;
|
let weight = call.get_dispatch_info().weight;
|
||||||
if weight.any_gt(max_weight) {
|
if weight.any_gt(max_weight) {
|
||||||
let e = Event::NotifyOverweight(
|
let e = Event::NotifyOverweight {
|
||||||
query_id,
|
query_id,
|
||||||
pallet_index,
|
pallet_index,
|
||||||
call_index,
|
call_index,
|
||||||
weight,
|
actual_weight: weight,
|
||||||
max_weight,
|
max_budgeted_weight: max_weight,
|
||||||
);
|
};
|
||||||
Self::deposit_event(e);
|
Self::deposit_event(e);
|
||||||
return Weight::zero()
|
return Weight::zero()
|
||||||
}
|
}
|
||||||
let dispatch_origin = Origin::Response(*origin).into();
|
let dispatch_origin = Origin::Response(origin).into();
|
||||||
match call.dispatch(dispatch_origin) {
|
match call.dispatch(dispatch_origin) {
|
||||||
Ok(post_info) => {
|
Ok(post_info) => {
|
||||||
let e = Event::Notified(query_id, pallet_index, call_index);
|
let e = Event::Notified { query_id, pallet_index, call_index };
|
||||||
Self::deposit_event(e);
|
Self::deposit_event(e);
|
||||||
post_info.actual_weight
|
post_info.actual_weight
|
||||||
},
|
},
|
||||||
Err(error_and_info) => {
|
Err(error_and_info) => {
|
||||||
let e = Event::NotifyDispatchError(
|
let e = Event::NotifyDispatchError {
|
||||||
query_id,
|
query_id,
|
||||||
pallet_index,
|
pallet_index,
|
||||||
call_index,
|
call_index,
|
||||||
);
|
};
|
||||||
Self::deposit_event(e);
|
Self::deposit_event(e);
|
||||||
// Not much to do with the result as it is. It's up to the parachain to ensure that the
|
// Not much to do with the result as it is. It's up to the parachain to ensure that the
|
||||||
// message makes sense.
|
// message makes sense.
|
||||||
@@ -2066,13 +2092,14 @@ impl<T: Config> OnResponse for Pallet<T> {
|
|||||||
}
|
}
|
||||||
.unwrap_or(weight)
|
.unwrap_or(weight)
|
||||||
} else {
|
} else {
|
||||||
let e = Event::NotifyDecodeFailed(query_id, pallet_index, call_index);
|
let e =
|
||||||
|
Event::NotifyDecodeFailed { query_id, pallet_index, call_index };
|
||||||
Self::deposit_event(e);
|
Self::deposit_event(e);
|
||||||
Weight::zero()
|
Weight::zero()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
let e = Event::ResponseReady(query_id, response.clone());
|
let e = Event::ResponseReady { query_id, response: response.clone() };
|
||||||
Self::deposit_event(e);
|
Self::deposit_event(e);
|
||||||
let at = frame_system::Pallet::<T>::current_block_number();
|
let at = frame_system::Pallet::<T>::current_block_number();
|
||||||
let response = response.into();
|
let response = response.into();
|
||||||
@@ -2082,7 +2109,8 @@ impl<T: Config> OnResponse for Pallet<T> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
Self::deposit_event(Event::UnexpectedResponse(*origin, query_id));
|
let e = Event::UnexpectedResponse { origin, query_id };
|
||||||
|
Self::deposit_event(e);
|
||||||
Weight::zero()
|
Weight::zero()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -2094,7 +2122,7 @@ impl<T: Config> CheckSuspension for Pallet<T> {
|
|||||||
_origin: &MultiLocation,
|
_origin: &MultiLocation,
|
||||||
_instructions: &mut [Instruction<Call>],
|
_instructions: &mut [Instruction<Call>],
|
||||||
_max_weight: Weight,
|
_max_weight: Weight,
|
||||||
_weight_credit: &mut Weight,
|
_properties: &mut Properties,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
XcmExecutionSuspended::<T>::get()
|
XcmExecutionSuspended::<T>::get()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,10 @@ use polkadot_parachain::primitives::Id as ParaId;
|
|||||||
use sp_runtime::traits::{AccountIdConversion, BlakeTwo256, Hash};
|
use sp_runtime::traits::{AccountIdConversion, BlakeTwo256, Hash};
|
||||||
use xcm::{latest::QueryResponseInfo, prelude::*};
|
use xcm::{latest::QueryResponseInfo, prelude::*};
|
||||||
use xcm_builder::AllowKnownQueryResponses;
|
use xcm_builder::AllowKnownQueryResponses;
|
||||||
use xcm_executor::{traits::ShouldExecute, XcmExecutor};
|
use xcm_executor::{
|
||||||
|
traits::{Properties, ShouldExecute},
|
||||||
|
XcmExecutor,
|
||||||
|
};
|
||||||
|
|
||||||
const ALICE: AccountId = AccountId::new([0u8; 32]);
|
const ALICE: AccountId = AccountId::new([0u8; 32]);
|
||||||
const BOB: AccountId = AccountId::new([1u8; 32]);
|
const BOB: AccountId = AccountId::new([1u8; 32]);
|
||||||
@@ -101,7 +104,11 @@ fn report_outcome_notify_works() {
|
|||||||
0,
|
0,
|
||||||
Response::ExecutionResult(None),
|
Response::ExecutionResult(None),
|
||||||
)),
|
)),
|
||||||
RuntimeEvent::XcmPallet(crate::Event::Notified(0, 4, 2)),
|
RuntimeEvent::XcmPallet(crate::Event::Notified {
|
||||||
|
query_id: 0,
|
||||||
|
pallet_index: 4,
|
||||||
|
call_index: 2
|
||||||
|
}),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
assert_eq!(crate::Queries::<Test>::iter().collect::<Vec<_>>(), vec![]);
|
assert_eq!(crate::Queries::<Test>::iter().collect::<Vec<_>>(), vec![]);
|
||||||
@@ -157,10 +164,10 @@ fn report_outcome_works() {
|
|||||||
assert_eq!(r, Outcome::Complete(Weight::from_parts(1_000, 1_000)));
|
assert_eq!(r, Outcome::Complete(Weight::from_parts(1_000, 1_000)));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
last_event(),
|
last_event(),
|
||||||
RuntimeEvent::XcmPallet(crate::Event::ResponseReady(
|
RuntimeEvent::XcmPallet(crate::Event::ResponseReady {
|
||||||
0,
|
query_id: 0,
|
||||||
Response::ExecutionResult(None),
|
response: Response::ExecutionResult(None),
|
||||||
))
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
let response = Some((Response::ExecutionResult(None), 1));
|
let response = Some((Response::ExecutionResult(None), 1));
|
||||||
@@ -206,12 +213,12 @@ fn custom_querier_works() {
|
|||||||
assert_eq!(r, Outcome::Complete(Weight::from_parts(1_000, 1_000)));
|
assert_eq!(r, Outcome::Complete(Weight::from_parts(1_000, 1_000)));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
last_event(),
|
last_event(),
|
||||||
RuntimeEvent::XcmPallet(crate::Event::InvalidQuerier(
|
RuntimeEvent::XcmPallet(crate::Event::InvalidQuerier {
|
||||||
AccountId32 { network: None, id: ALICE.into() }.into(),
|
origin: AccountId32 { network: None, id: ALICE.into() }.into(),
|
||||||
0,
|
query_id: 0,
|
||||||
querier.clone(),
|
expected_querier: querier.clone(),
|
||||||
None,
|
maybe_actual_querier: None,
|
||||||
)),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Supplying the wrong querier will also fail
|
// Supplying the wrong querier will also fail
|
||||||
@@ -232,12 +239,12 @@ fn custom_querier_works() {
|
|||||||
assert_eq!(r, Outcome::Complete(Weight::from_parts(1_000, 1_000)));
|
assert_eq!(r, Outcome::Complete(Weight::from_parts(1_000, 1_000)));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
last_event(),
|
last_event(),
|
||||||
RuntimeEvent::XcmPallet(crate::Event::InvalidQuerier(
|
RuntimeEvent::XcmPallet(crate::Event::InvalidQuerier {
|
||||||
AccountId32 { network: None, id: ALICE.into() }.into(),
|
origin: AccountId32 { network: None, id: ALICE.into() }.into(),
|
||||||
0,
|
query_id: 0,
|
||||||
querier.clone(),
|
expected_querier: querier.clone(),
|
||||||
Some(MultiLocation::here()),
|
maybe_actual_querier: Some(MultiLocation::here()),
|
||||||
)),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Multiple failures should not have changed the query state
|
// Multiple failures should not have changed the query state
|
||||||
@@ -257,10 +264,10 @@ fn custom_querier_works() {
|
|||||||
assert_eq!(r, Outcome::Complete(Weight::from_parts(1_000, 1_000)));
|
assert_eq!(r, Outcome::Complete(Weight::from_parts(1_000, 1_000)));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
last_event(),
|
last_event(),
|
||||||
RuntimeEvent::XcmPallet(crate::Event::ResponseReady(
|
RuntimeEvent::XcmPallet(crate::Event::ResponseReady {
|
||||||
0,
|
query_id: 0,
|
||||||
Response::ExecutionResult(None),
|
response: Response::ExecutionResult(None),
|
||||||
))
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
let response = Some((Response::ExecutionResult(None), 1));
|
let response = Some((Response::ExecutionResult(None), 1));
|
||||||
@@ -285,6 +292,7 @@ fn send_works() {
|
|||||||
buy_execution((Parent, SEND_AMOUNT)),
|
buy_execution((Parent, SEND_AMOUNT)),
|
||||||
DepositAsset { assets: AllCounted(1).into(), beneficiary: sender.clone() },
|
DepositAsset { assets: AllCounted(1).into(), beneficiary: sender.clone() },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let versioned_dest = Box::new(RelayLocation::get().into());
|
let versioned_dest = Box::new(RelayLocation::get().into());
|
||||||
let versioned_message = Box::new(VersionedXcm::from(message.clone()));
|
let versioned_message = Box::new(VersionedXcm::from(message.clone()));
|
||||||
assert_ok!(XcmPallet::send(
|
assert_ok!(XcmPallet::send(
|
||||||
@@ -292,19 +300,20 @@ fn send_works() {
|
|||||||
versioned_dest,
|
versioned_dest,
|
||||||
versioned_message
|
versioned_message
|
||||||
));
|
));
|
||||||
assert_eq!(
|
let sent_message = Xcm(Some(DescendOrigin(sender.clone().try_into().unwrap()))
|
||||||
sent_xcm(),
|
|
||||||
vec![(
|
|
||||||
Here.into(),
|
|
||||||
Xcm(Some(DescendOrigin(sender.clone().try_into().unwrap()))
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(message.0.clone().into_iter())
|
.chain(message.0.clone().into_iter())
|
||||||
.collect())
|
.collect());
|
||||||
)],
|
let id = fake_message_hash(&sent_message);
|
||||||
);
|
assert_eq!(sent_xcm(), vec![(Here.into(), sent_message)]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
last_event(),
|
last_event(),
|
||||||
RuntimeEvent::XcmPallet(crate::Event::Sent(sender, RelayLocation::get(), message))
|
RuntimeEvent::XcmPallet(crate::Event::Sent {
|
||||||
|
origin: sender,
|
||||||
|
destination: RelayLocation::get(),
|
||||||
|
message,
|
||||||
|
message_id: id,
|
||||||
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -376,7 +385,7 @@ fn teleport_assets_works() {
|
|||||||
let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap();
|
let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
last_event(),
|
last_event(),
|
||||||
RuntimeEvent::XcmPallet(crate::Event::Attempted(Outcome::Complete(weight)))
|
RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) })
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -420,7 +429,7 @@ fn limited_teleport_assets_works() {
|
|||||||
let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap();
|
let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
last_event(),
|
last_event(),
|
||||||
RuntimeEvent::XcmPallet(crate::Event::Attempted(Outcome::Complete(weight)))
|
RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) })
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -462,7 +471,7 @@ fn unlimited_teleport_assets_works() {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
last_event(),
|
last_event(),
|
||||||
RuntimeEvent::XcmPallet(crate::Event::Attempted(Outcome::Complete(weight)))
|
RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) })
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -509,7 +518,7 @@ fn reserve_transfer_assets_works() {
|
|||||||
let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap();
|
let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
last_event(),
|
last_event(),
|
||||||
RuntimeEvent::XcmPallet(crate::Event::Attempted(Outcome::Complete(weight)))
|
RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) })
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -557,7 +566,7 @@ fn limited_reserve_transfer_assets_works() {
|
|||||||
let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap();
|
let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
last_event(),
|
last_event(),
|
||||||
RuntimeEvent::XcmPallet(crate::Event::Attempted(Outcome::Complete(weight)))
|
RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) })
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -603,7 +612,7 @@ fn unlimited_reserve_transfer_assets_works() {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
last_event(),
|
last_event(),
|
||||||
RuntimeEvent::XcmPallet(crate::Event::Attempted(Outcome::Complete(weight)))
|
RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) })
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -635,7 +644,7 @@ fn execute_withdraw_to_deposit_works() {
|
|||||||
assert_eq!(Balances::total_balance(&BOB), SEND_AMOUNT);
|
assert_eq!(Balances::total_balance(&BOB), SEND_AMOUNT);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
last_event(),
|
last_event(),
|
||||||
RuntimeEvent::XcmPallet(crate::Event::Attempted(Outcome::Complete(weight)))
|
RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) })
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -670,10 +679,14 @@ fn trapped_assets_can_be_claimed() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
last_events(2),
|
last_events(2),
|
||||||
vec![
|
vec![
|
||||||
RuntimeEvent::XcmPallet(crate::Event::AssetsTrapped(hash.clone(), source, vma)),
|
RuntimeEvent::XcmPallet(crate::Event::AssetsTrapped {
|
||||||
RuntimeEvent::XcmPallet(crate::Event::Attempted(Outcome::Complete(
|
hash: hash.clone(),
|
||||||
BaseXcmWeight::get() * 5
|
origin: source,
|
||||||
)))
|
assets: vma
|
||||||
|
}),
|
||||||
|
RuntimeEvent::XcmPallet(crate::Event::Attempted {
|
||||||
|
outcome: Outcome::Complete(BaseXcmWeight::get() * 5)
|
||||||
|
}),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT);
|
assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT);
|
||||||
@@ -707,13 +720,8 @@ fn trapped_assets_can_be_claimed() {
|
|||||||
]))),
|
]))),
|
||||||
weight
|
weight
|
||||||
));
|
));
|
||||||
assert_eq!(
|
let outcome = Outcome::Incomplete(BaseXcmWeight::get(), XcmError::UnknownClaim);
|
||||||
last_event(),
|
assert_eq!(last_event(), RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome }));
|
||||||
RuntimeEvent::XcmPallet(crate::Event::Attempted(Outcome::Incomplete(
|
|
||||||
BaseXcmWeight::get(),
|
|
||||||
XcmError::UnknownClaim
|
|
||||||
)))
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -768,7 +776,7 @@ fn basic_subscription_works() {
|
|||||||
&remote,
|
&remote,
|
||||||
message.inner_mut(),
|
message.inner_mut(),
|
||||||
weight,
|
weight,
|
||||||
&mut Weight::zero(),
|
&mut Properties { weight_credit: Weight::zero(), message_id: None },
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ pub mod prelude {
|
|||||||
NetworkId::{self, *},
|
NetworkId::{self, *},
|
||||||
OriginKind, Outcome, PalletInfo, Parent, ParentThen, PreparedMessage, QueryId,
|
OriginKind, Outcome, PalletInfo, Parent, ParentThen, PreparedMessage, QueryId,
|
||||||
QueryResponseInfo, Response, Result as XcmResult, SendError, SendResult, SendXcm,
|
QueryResponseInfo, Response, Result as XcmResult, SendError, SendResult, SendXcm,
|
||||||
Unwrappable,
|
Unwrappable, Weight,
|
||||||
WeightLimit::{self, *},
|
WeightLimit::{self, *},
|
||||||
WildFungibility::{self, Fungible as WildFungible, NonFungible as WildNonFungible},
|
WildFungibility::{self, Fungible as WildFungible, NonFungible as WildNonFungible},
|
||||||
WildMultiAsset::{self, *},
|
WildMultiAsset::{self, *},
|
||||||
@@ -337,19 +337,27 @@ impl TryFrom<OldWeightLimit> for WeightLimit {
|
|||||||
/// Contextual data pertaining to a specific list of XCM instructions.
|
/// Contextual data pertaining to a specific list of XCM instructions.
|
||||||
#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)]
|
#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)]
|
||||||
pub struct XcmContext {
|
pub struct XcmContext {
|
||||||
/// The `MultiLocation` origin of the corresponding XCM.
|
/// The current value of the Origin register of the XCVM.
|
||||||
pub origin: Option<MultiLocation>,
|
pub origin: Option<MultiLocation>,
|
||||||
/// The hash of the XCM.
|
/// The identity of the XCM; this may be a hash of its versioned encoding but could also be
|
||||||
pub message_hash: XcmHash,
|
/// a high-level identity set by an appropriate barrier.
|
||||||
/// The topic of the XCM.
|
pub message_id: XcmHash,
|
||||||
|
/// The current value of the Topic register of the XCVM.
|
||||||
pub topic: Option<[u8; 32]>,
|
pub topic: Option<[u8; 32]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl XcmContext {
|
impl XcmContext {
|
||||||
/// Constructor which sets the message hash to the supplied parameter and leaves the origin and
|
/// Constructor which sets the message ID to the supplied parameter and leaves the origin and
|
||||||
/// topic unset.
|
/// topic unset.
|
||||||
pub fn with_message_hash(message_hash: XcmHash) -> XcmContext {
|
#[deprecated = "Use `with_message_id` instead."]
|
||||||
XcmContext { origin: None, message_hash, topic: None }
|
pub fn with_message_hash(message_id: XcmHash) -> XcmContext {
|
||||||
|
XcmContext { origin: None, message_id, topic: None }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructor which sets the message ID to the supplied parameter and leaves the origin and
|
||||||
|
/// topic unset.
|
||||||
|
pub fn with_message_id(message_id: XcmHash) -> XcmContext {
|
||||||
|
XcmContext { origin: None, message_id, topic: None }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -212,6 +212,52 @@ impl From<SendError> for Error {
|
|||||||
|
|
||||||
pub type Result = result::Result<(), Error>;
|
pub type Result = result::Result<(), Error>;
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO: XCMv4
|
||||||
|
/// Outcome of an XCM execution.
|
||||||
|
#[derive(Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)]
|
||||||
|
pub enum Outcome {
|
||||||
|
/// Execution completed successfully; given weight was used.
|
||||||
|
Complete { used: Weight },
|
||||||
|
/// Execution started, but did not complete successfully due to the given error; given weight
|
||||||
|
/// was used.
|
||||||
|
Incomplete { used: Weight, error: Error },
|
||||||
|
/// Execution did not start due to the given error.
|
||||||
|
Error { error: Error },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Outcome {
|
||||||
|
pub fn ensure_complete(self) -> Result {
|
||||||
|
match self {
|
||||||
|
Outcome::Complete { .. } => Ok(()),
|
||||||
|
Outcome::Incomplete { error, .. } => Err(error),
|
||||||
|
Outcome::Error { error, .. } => Err(error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn ensure_execution(self) -> result::Result<Weight, Error> {
|
||||||
|
match self {
|
||||||
|
Outcome::Complete { used, .. } => Ok(used),
|
||||||
|
Outcome::Incomplete { used, .. } => Ok(used),
|
||||||
|
Outcome::Error { error, .. } => Err(error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// How much weight was used by the XCM execution attempt.
|
||||||
|
pub fn weight_used(&self) -> Weight {
|
||||||
|
match self {
|
||||||
|
Outcome::Complete { used, .. } => *used,
|
||||||
|
Outcome::Incomplete { used, .. } => *used,
|
||||||
|
Outcome::Error { .. } => Weight::zero(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Error> for Outcome {
|
||||||
|
fn from(error: Error) -> Self {
|
||||||
|
Self::Error { error, maybe_id: None }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
/// Outcome of an XCM execution.
|
/// Outcome of an XCM execution.
|
||||||
#[derive(Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)]
|
#[derive(Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)]
|
||||||
pub enum Outcome {
|
pub enum Outcome {
|
||||||
@@ -259,13 +305,34 @@ pub trait ExecuteXcm<Call> {
|
|||||||
fn execute(
|
fn execute(
|
||||||
origin: impl Into<MultiLocation>,
|
origin: impl Into<MultiLocation>,
|
||||||
pre: Self::Prepared,
|
pre: Self::Prepared,
|
||||||
hash: XcmHash,
|
id: &mut XcmHash,
|
||||||
weight_credit: Weight,
|
weight_credit: Weight,
|
||||||
) -> Outcome;
|
) -> Outcome;
|
||||||
|
fn prepare_and_execute(
|
||||||
|
origin: impl Into<MultiLocation>,
|
||||||
|
message: Xcm<Call>,
|
||||||
|
id: &mut XcmHash,
|
||||||
|
weight_limit: Weight,
|
||||||
|
weight_credit: Weight,
|
||||||
|
) -> Outcome {
|
||||||
|
let pre = match Self::prepare(message) {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(_) => return Outcome::Error(Error::WeightNotComputable),
|
||||||
|
};
|
||||||
|
let xcm_weight = pre.weight_of();
|
||||||
|
if xcm_weight.any_gt(weight_limit) {
|
||||||
|
return Outcome::Error(Error::WeightLimitReached(xcm_weight))
|
||||||
|
}
|
||||||
|
Self::execute(origin, pre, id, weight_credit)
|
||||||
|
}
|
||||||
|
|
||||||
/// Execute some XCM `message` with the message `hash` from `origin` using no more than `weight_limit` weight.
|
/// Execute some XCM `message` with the message `hash` from `origin` using no more than
|
||||||
/// The weight limit is a basic hard-limit and the implementation may place further restrictions or requirements
|
/// `weight_limit` weight.
|
||||||
/// on weight and other aspects.
|
///
|
||||||
|
/// The weight limit is a basic hard-limit and the implementation may place further
|
||||||
|
/// restrictions or requirements on weight and other aspects.
|
||||||
|
// TODO: XCMv4
|
||||||
|
// #[deprecated = "Use `prepare_and_execute` instead"]
|
||||||
fn execute_xcm(
|
fn execute_xcm(
|
||||||
origin: impl Into<MultiLocation>,
|
origin: impl Into<MultiLocation>,
|
||||||
message: Xcm<Call>,
|
message: Xcm<Call>,
|
||||||
@@ -283,14 +350,17 @@ pub trait ExecuteXcm<Call> {
|
|||||||
Self::execute_xcm_in_credit(origin, message, hash, weight_limit, Weight::zero())
|
Self::execute_xcm_in_credit(origin, message, hash, weight_limit, Weight::zero())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute some XCM `message` with the message `hash` from `origin` using no more than `weight_limit` weight.
|
/// Execute some XCM `message` with the message `hash` from `origin` using no more than
|
||||||
|
/// `weight_limit` weight.
|
||||||
///
|
///
|
||||||
/// Some amount of `weight_credit` may be provided which, depending on the implementation, may allow
|
/// Some amount of `weight_credit` may be provided which, depending on the implementation, may
|
||||||
/// execution without associated payment.
|
/// allow execution without associated payment.
|
||||||
|
// TODO: XCMv4
|
||||||
|
// #[deprecated = "Use `prepare_and_execute` instead"]
|
||||||
fn execute_xcm_in_credit(
|
fn execute_xcm_in_credit(
|
||||||
origin: impl Into<MultiLocation>,
|
origin: impl Into<MultiLocation>,
|
||||||
message: Xcm<Call>,
|
message: Xcm<Call>,
|
||||||
hash: XcmHash,
|
mut hash: XcmHash,
|
||||||
weight_limit: Weight,
|
weight_limit: Weight,
|
||||||
weight_credit: Weight,
|
weight_credit: Weight,
|
||||||
) -> Outcome {
|
) -> Outcome {
|
||||||
@@ -302,7 +372,7 @@ pub trait ExecuteXcm<Call> {
|
|||||||
if xcm_weight.any_gt(weight_limit) {
|
if xcm_weight.any_gt(weight_limit) {
|
||||||
return Outcome::Error(Error::WeightLimitReached(xcm_weight))
|
return Outcome::Error(Error::WeightLimitReached(xcm_weight))
|
||||||
}
|
}
|
||||||
Self::execute(origin, pre, hash, weight_credit)
|
Self::execute(origin, pre, &mut hash, weight_credit)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deduct some `fees` to the sovereign account of the given `location` and place them as per
|
/// Deduct some `fees` to the sovereign account of the given `location` and place them as per
|
||||||
@@ -322,7 +392,12 @@ impl<C> ExecuteXcm<C> for () {
|
|||||||
fn prepare(message: Xcm<C>) -> result::Result<Self::Prepared, Xcm<C>> {
|
fn prepare(message: Xcm<C>) -> result::Result<Self::Prepared, Xcm<C>> {
|
||||||
Err(message)
|
Err(message)
|
||||||
}
|
}
|
||||||
fn execute(_: impl Into<MultiLocation>, _: Self::Prepared, _: XcmHash, _: Weight) -> Outcome {
|
fn execute(
|
||||||
|
_: impl Into<MultiLocation>,
|
||||||
|
_: Self::Prepared,
|
||||||
|
_: &mut XcmHash,
|
||||||
|
_: Weight,
|
||||||
|
) -> Outcome {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
fn charge_fees(_location: impl Into<MultiLocation>, _fees: MultiAssets) -> Result {
|
fn charge_fees(_location: impl Into<MultiLocation>, _fees: MultiAssets) -> Result {
|
||||||
|
|||||||
@@ -23,16 +23,10 @@ use frame_support::{
|
|||||||
};
|
};
|
||||||
use polkadot_parachain::primitives::IsSystem;
|
use polkadot_parachain::primitives::IsSystem;
|
||||||
use sp_std::{cell::Cell, marker::PhantomData, ops::ControlFlow, result::Result};
|
use sp_std::{cell::Cell, marker::PhantomData, ops::ControlFlow, result::Result};
|
||||||
use xcm::latest::{
|
use xcm::prelude::*;
|
||||||
Instruction::{self, *},
|
use xcm_executor::traits::{CheckSuspension, OnResponse, Properties, ShouldExecute};
|
||||||
InteriorMultiLocation, Junction, Junctions,
|
|
||||||
Junctions::X1,
|
|
||||||
MultiLocation, Weight,
|
|
||||||
WeightLimit::*,
|
|
||||||
};
|
|
||||||
use xcm_executor::traits::{CheckSuspension, OnResponse, ShouldExecute};
|
|
||||||
|
|
||||||
/// Execution barrier that just takes `max_weight` from `weight_credit`.
|
/// Execution barrier that just takes `max_weight` from `properties.weight_credit`.
|
||||||
///
|
///
|
||||||
/// Useful to allow XCM execution by local chain users via extrinsics.
|
/// Useful to allow XCM execution by local chain users via extrinsics.
|
||||||
/// E.g. `pallet_xcm::reserve_asset_transfer` to transfer a reserve asset
|
/// E.g. `pallet_xcm::reserve_asset_transfer` to transfer a reserve asset
|
||||||
@@ -43,14 +37,15 @@ impl ShouldExecute for TakeWeightCredit {
|
|||||||
_origin: &MultiLocation,
|
_origin: &MultiLocation,
|
||||||
_instructions: &mut [Instruction<RuntimeCall>],
|
_instructions: &mut [Instruction<RuntimeCall>],
|
||||||
max_weight: Weight,
|
max_weight: Weight,
|
||||||
weight_credit: &mut Weight,
|
properties: &mut Properties,
|
||||||
) -> Result<(), ProcessMessageError> {
|
) -> Result<(), ProcessMessageError> {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
target: "xcm::barriers",
|
target: "xcm::barriers",
|
||||||
"TakeWeightCredit origin: {:?}, instructions: {:?}, max_weight: {:?}, weight_credit: {:?}",
|
"TakeWeightCredit origin: {:?}, instructions: {:?}, max_weight: {:?}, properties: {:?}",
|
||||||
_origin, _instructions, max_weight, weight_credit,
|
_origin, _instructions, max_weight, properties,
|
||||||
);
|
);
|
||||||
*weight_credit = weight_credit
|
properties.weight_credit = properties
|
||||||
|
.weight_credit
|
||||||
.checked_sub(&max_weight)
|
.checked_sub(&max_weight)
|
||||||
.ok_or(ProcessMessageError::Overweight(max_weight))?;
|
.ok_or(ProcessMessageError::Overweight(max_weight))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -68,12 +63,12 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowTopLevelPaidExecutionFro
|
|||||||
origin: &MultiLocation,
|
origin: &MultiLocation,
|
||||||
instructions: &mut [Instruction<RuntimeCall>],
|
instructions: &mut [Instruction<RuntimeCall>],
|
||||||
max_weight: Weight,
|
max_weight: Weight,
|
||||||
_weight_credit: &mut Weight,
|
_properties: &mut Properties,
|
||||||
) -> Result<(), ProcessMessageError> {
|
) -> Result<(), ProcessMessageError> {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
target: "xcm::barriers",
|
target: "xcm::barriers",
|
||||||
"AllowTopLevelPaidExecutionFrom origin: {:?}, instructions: {:?}, max_weight: {:?}, weight_credit: {:?}",
|
"AllowTopLevelPaidExecutionFrom origin: {:?}, instructions: {:?}, max_weight: {:?}, properties: {:?}",
|
||||||
origin, instructions, max_weight, _weight_credit,
|
origin, instructions, max_weight, _properties,
|
||||||
);
|
);
|
||||||
|
|
||||||
ensure!(T::contains(origin), ProcessMessageError::Unsupported);
|
ensure!(T::contains(origin), ProcessMessageError::Unsupported);
|
||||||
@@ -166,12 +161,12 @@ impl<
|
|||||||
origin: &MultiLocation,
|
origin: &MultiLocation,
|
||||||
instructions: &mut [Instruction<Call>],
|
instructions: &mut [Instruction<Call>],
|
||||||
max_weight: Weight,
|
max_weight: Weight,
|
||||||
weight_credit: &mut Weight,
|
properties: &mut Properties,
|
||||||
) -> Result<(), ProcessMessageError> {
|
) -> Result<(), ProcessMessageError> {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
target: "xcm::barriers",
|
target: "xcm::barriers",
|
||||||
"WithComputedOrigin origin: {:?}, instructions: {:?}, max_weight: {:?}, weight_credit: {:?}",
|
"WithComputedOrigin origin: {:?}, instructions: {:?}, max_weight: {:?}, properties: {:?}",
|
||||||
origin, instructions, max_weight, weight_credit,
|
origin, instructions, max_weight, properties,
|
||||||
);
|
);
|
||||||
let mut actual_origin = *origin;
|
let mut actual_origin = *origin;
|
||||||
let skipped = Cell::new(0usize);
|
let skipped = Cell::new(0usize);
|
||||||
@@ -205,11 +200,37 @@ impl<
|
|||||||
&actual_origin,
|
&actual_origin,
|
||||||
&mut instructions[skipped.get()..],
|
&mut instructions[skipped.get()..],
|
||||||
max_weight,
|
max_weight,
|
||||||
weight_credit,
|
properties,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the message ID to `t` using a `SetTopic(t)` in the last position if present.
|
||||||
|
///
|
||||||
|
/// Requires some inner barrier to pass on the rest of the message.
|
||||||
|
pub struct TrailingSetTopicAsId<InnerBarrier>(PhantomData<InnerBarrier>);
|
||||||
|
impl<InnerBarrier: ShouldExecute> ShouldExecute for TrailingSetTopicAsId<InnerBarrier> {
|
||||||
|
fn should_execute<Call>(
|
||||||
|
origin: &MultiLocation,
|
||||||
|
instructions: &mut [Instruction<Call>],
|
||||||
|
max_weight: Weight,
|
||||||
|
properties: &mut Properties,
|
||||||
|
) -> Result<(), ProcessMessageError> {
|
||||||
|
log::trace!(
|
||||||
|
target: "xcm::barriers",
|
||||||
|
"TrailingSetTopicAsId origin: {:?}, instructions: {:?}, max_weight: {:?}, properties: {:?}",
|
||||||
|
origin, instructions, max_weight, properties,
|
||||||
|
);
|
||||||
|
let until = if let Some(SetTopic(t)) = instructions.last() {
|
||||||
|
properties.message_id = Some(*t);
|
||||||
|
instructions.len() - 1
|
||||||
|
} else {
|
||||||
|
instructions.len()
|
||||||
|
};
|
||||||
|
InnerBarrier::should_execute(&origin, &mut instructions[..until], max_weight, properties)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Barrier condition that allows for a `SuspensionChecker` that controls whether or not the XCM
|
/// Barrier condition that allows for a `SuspensionChecker` that controls whether or not the XCM
|
||||||
/// executor will be suspended from executing the given XCM.
|
/// executor will be suspended from executing the given XCM.
|
||||||
pub struct RespectSuspension<Inner, SuspensionChecker>(PhantomData<(Inner, SuspensionChecker)>);
|
pub struct RespectSuspension<Inner, SuspensionChecker>(PhantomData<(Inner, SuspensionChecker)>);
|
||||||
@@ -222,12 +243,12 @@ where
|
|||||||
origin: &MultiLocation,
|
origin: &MultiLocation,
|
||||||
instructions: &mut [Instruction<Call>],
|
instructions: &mut [Instruction<Call>],
|
||||||
max_weight: Weight,
|
max_weight: Weight,
|
||||||
weight_credit: &mut Weight,
|
properties: &mut Properties,
|
||||||
) -> Result<(), ProcessMessageError> {
|
) -> Result<(), ProcessMessageError> {
|
||||||
if SuspensionChecker::is_suspended(origin, instructions, max_weight, weight_credit) {
|
if SuspensionChecker::is_suspended(origin, instructions, max_weight, properties) {
|
||||||
Err(ProcessMessageError::Yield)
|
Err(ProcessMessageError::Yield)
|
||||||
} else {
|
} else {
|
||||||
Inner::should_execute(origin, instructions, max_weight, weight_credit)
|
Inner::should_execute(origin, instructions, max_weight, properties)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -242,12 +263,12 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowUnpaidExecutionFrom<T> {
|
|||||||
origin: &MultiLocation,
|
origin: &MultiLocation,
|
||||||
instructions: &mut [Instruction<RuntimeCall>],
|
instructions: &mut [Instruction<RuntimeCall>],
|
||||||
_max_weight: Weight,
|
_max_weight: Weight,
|
||||||
_weight_credit: &mut Weight,
|
_properties: &mut Properties,
|
||||||
) -> Result<(), ProcessMessageError> {
|
) -> Result<(), ProcessMessageError> {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
target: "xcm::barriers",
|
target: "xcm::barriers",
|
||||||
"AllowUnpaidExecutionFrom origin: {:?}, instructions: {:?}, max_weight: {:?}, weight_credit: {:?}",
|
"AllowUnpaidExecutionFrom origin: {:?}, instructions: {:?}, max_weight: {:?}, properties: {:?}",
|
||||||
origin, instructions, _max_weight, _weight_credit,
|
origin, instructions, _max_weight, _properties,
|
||||||
);
|
);
|
||||||
ensure!(T::contains(origin), ProcessMessageError::Unsupported);
|
ensure!(T::contains(origin), ProcessMessageError::Unsupported);
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -264,12 +285,12 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowExplicitUnpaidExecutionF
|
|||||||
origin: &MultiLocation,
|
origin: &MultiLocation,
|
||||||
instructions: &mut [Instruction<Call>],
|
instructions: &mut [Instruction<Call>],
|
||||||
max_weight: Weight,
|
max_weight: Weight,
|
||||||
_weight_credit: &mut Weight,
|
_properties: &mut Properties,
|
||||||
) -> Result<(), ProcessMessageError> {
|
) -> Result<(), ProcessMessageError> {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
target: "xcm::barriers",
|
target: "xcm::barriers",
|
||||||
"AllowExplicitUnpaidExecutionFrom origin: {:?}, instructions: {:?}, max_weight: {:?}, weight_credit: {:?}",
|
"AllowExplicitUnpaidExecutionFrom origin: {:?}, instructions: {:?}, max_weight: {:?}, properties: {:?}",
|
||||||
origin, instructions, max_weight, _weight_credit,
|
origin, instructions, max_weight, _properties,
|
||||||
);
|
);
|
||||||
ensure!(T::contains(origin), ProcessMessageError::Unsupported);
|
ensure!(T::contains(origin), ProcessMessageError::Unsupported);
|
||||||
instructions.matcher().match_next_inst(|inst| match inst {
|
instructions.matcher().match_next_inst(|inst| match inst {
|
||||||
@@ -300,12 +321,12 @@ impl<ResponseHandler: OnResponse> ShouldExecute for AllowKnownQueryResponses<Res
|
|||||||
origin: &MultiLocation,
|
origin: &MultiLocation,
|
||||||
instructions: &mut [Instruction<RuntimeCall>],
|
instructions: &mut [Instruction<RuntimeCall>],
|
||||||
_max_weight: Weight,
|
_max_weight: Weight,
|
||||||
_weight_credit: &mut Weight,
|
_properties: &mut Properties,
|
||||||
) -> Result<(), ProcessMessageError> {
|
) -> Result<(), ProcessMessageError> {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
target: "xcm::barriers",
|
target: "xcm::barriers",
|
||||||
"AllowKnownQueryResponses origin: {:?}, instructions: {:?}, max_weight: {:?}, weight_credit: {:?}",
|
"AllowKnownQueryResponses origin: {:?}, instructions: {:?}, max_weight: {:?}, properties: {:?}",
|
||||||
origin, instructions, _max_weight, _weight_credit,
|
origin, instructions, _max_weight, _properties,
|
||||||
);
|
);
|
||||||
instructions
|
instructions
|
||||||
.matcher()
|
.matcher()
|
||||||
@@ -328,12 +349,12 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowSubscriptionsFrom<T> {
|
|||||||
origin: &MultiLocation,
|
origin: &MultiLocation,
|
||||||
instructions: &mut [Instruction<RuntimeCall>],
|
instructions: &mut [Instruction<RuntimeCall>],
|
||||||
_max_weight: Weight,
|
_max_weight: Weight,
|
||||||
_weight_credit: &mut Weight,
|
_properties: &mut Properties,
|
||||||
) -> Result<(), ProcessMessageError> {
|
) -> Result<(), ProcessMessageError> {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
target: "xcm::barriers",
|
target: "xcm::barriers",
|
||||||
"AllowSubscriptionsFrom origin: {:?}, instructions: {:?}, max_weight: {:?}, weight_credit: {:?}",
|
"AllowSubscriptionsFrom origin: {:?}, instructions: {:?}, max_weight: {:?}, properties: {:?}",
|
||||||
origin, instructions, _max_weight, _weight_credit,
|
origin, instructions, _max_weight, _properties,
|
||||||
);
|
);
|
||||||
ensure!(T::contains(origin), ProcessMessageError::Unsupported);
|
ensure!(T::contains(origin), ProcessMessageError::Unsupported);
|
||||||
instructions
|
instructions
|
||||||
@@ -346,3 +367,72 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowSubscriptionsFrom<T> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deny executing the XCM if it matches any of the Deny filter regardless of anything else.
|
||||||
|
/// If it passes the Deny, and matches one of the Allow cases then it is let through.
|
||||||
|
pub struct DenyThenTry<Deny, Allow>(PhantomData<Deny>, PhantomData<Allow>)
|
||||||
|
where
|
||||||
|
Deny: ShouldExecute,
|
||||||
|
Allow: ShouldExecute;
|
||||||
|
|
||||||
|
impl<Deny, Allow> ShouldExecute for DenyThenTry<Deny, Allow>
|
||||||
|
where
|
||||||
|
Deny: ShouldExecute,
|
||||||
|
Allow: ShouldExecute,
|
||||||
|
{
|
||||||
|
fn should_execute<RuntimeCall>(
|
||||||
|
origin: &MultiLocation,
|
||||||
|
message: &mut [Instruction<RuntimeCall>],
|
||||||
|
max_weight: Weight,
|
||||||
|
properties: &mut Properties,
|
||||||
|
) -> Result<(), ProcessMessageError> {
|
||||||
|
Deny::should_execute(origin, message, max_weight, properties)?;
|
||||||
|
Allow::should_execute(origin, message, max_weight, properties)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See issue <https://github.com/paritytech/polkadot/issues/5233>
|
||||||
|
pub struct DenyReserveTransferToRelayChain;
|
||||||
|
impl ShouldExecute for DenyReserveTransferToRelayChain {
|
||||||
|
fn should_execute<RuntimeCall>(
|
||||||
|
origin: &MultiLocation,
|
||||||
|
message: &mut [Instruction<RuntimeCall>],
|
||||||
|
_max_weight: Weight,
|
||||||
|
_properties: &mut Properties,
|
||||||
|
) -> Result<(), ProcessMessageError> {
|
||||||
|
message.matcher().match_next_inst_while(
|
||||||
|
|_| true,
|
||||||
|
|inst| match inst {
|
||||||
|
InitiateReserveWithdraw {
|
||||||
|
reserve: MultiLocation { parents: 1, interior: Here },
|
||||||
|
..
|
||||||
|
} |
|
||||||
|
DepositReserveAsset {
|
||||||
|
dest: MultiLocation { parents: 1, interior: Here }, ..
|
||||||
|
} |
|
||||||
|
TransferReserveAsset {
|
||||||
|
dest: MultiLocation { parents: 1, interior: Here }, ..
|
||||||
|
} => {
|
||||||
|
Err(ProcessMessageError::Unsupported) // Deny
|
||||||
|
},
|
||||||
|
|
||||||
|
// An unexpected reserve transfer has arrived from the Relay Chain. Generally,
|
||||||
|
// `IsReserve` should not allow this, but we just log it here.
|
||||||
|
ReserveAssetDeposited { .. }
|
||||||
|
if matches!(origin, MultiLocation { parents: 1, interior: Here }) =>
|
||||||
|
{
|
||||||
|
log::warn!(
|
||||||
|
target: "xcm::barrier",
|
||||||
|
"Unexpected ReserveAssetDeposited from the Relay Chain",
|
||||||
|
);
|
||||||
|
Ok(ControlFlow::Continue(()))
|
||||||
|
},
|
||||||
|
|
||||||
|
_ => Ok(ControlFlow::Continue(())),
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Permit everything else
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -50,8 +50,9 @@ pub use asset_conversion::{ConvertedAbstractAssetId, ConvertedConcreteAssetId};
|
|||||||
mod barriers;
|
mod barriers;
|
||||||
pub use barriers::{
|
pub use barriers::{
|
||||||
AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom,
|
AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, AllowSubscriptionsFrom,
|
||||||
AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, IsChildSystemParachain,
|
AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, DenyReserveTransferToRelayChain,
|
||||||
RespectSuspension, TakeWeightCredit, WithComputedOrigin,
|
DenyThenTry, IsChildSystemParachain, RespectSuspension, TakeWeightCredit, TrailingSetTopicAsId,
|
||||||
|
WithComputedOrigin,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod process_xcm_message;
|
mod process_xcm_message;
|
||||||
@@ -85,6 +86,9 @@ pub use matcher::{CreateMatcher, MatchXcm, Matcher};
|
|||||||
mod filter_asset_location;
|
mod filter_asset_location;
|
||||||
pub use filter_asset_location::{Case, NativeAsset};
|
pub use filter_asset_location::{Case, NativeAsset};
|
||||||
|
|
||||||
|
mod routing;
|
||||||
|
pub use routing::{WithTopicSource, WithUniqueTopic};
|
||||||
|
|
||||||
mod universal_exports;
|
mod universal_exports;
|
||||||
pub use universal_exports::{
|
pub use universal_exports::{
|
||||||
ensure_is_remote, BridgeBlobDispatcher, BridgeMessage, DispatchBlob, DispatchBlobError,
|
ensure_is_remote, BridgeBlobDispatcher, BridgeMessage, DispatchBlob, DispatchBlobError,
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ impl<
|
|||||||
let required = pre.weight_of();
|
let required = pre.weight_of();
|
||||||
ensure!(meter.can_accrue(required), ProcessMessageError::Overweight(required));
|
ensure!(meter.can_accrue(required), ProcessMessageError::Overweight(required));
|
||||||
|
|
||||||
let (consumed, result) = match XcmExecutor::execute(origin.into(), pre, *id, Weight::zero())
|
let (consumed, result) = match XcmExecutor::execute(origin.into(), pre, id, Weight::zero())
|
||||||
{
|
{
|
||||||
Outcome::Complete(w) => (w, Ok(true)),
|
Outcome::Complete(w) => (w, Ok(true)),
|
||||||
Outcome::Incomplete(w, _) => (w, Ok(false)),
|
Outcome::Incomplete(w, _) => (w, Ok(false)),
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Various implementations for `SendXcm`.
|
||||||
|
|
||||||
|
use frame_system::unique;
|
||||||
|
use parity_scale_codec::Encode;
|
||||||
|
use sp_std::{marker::PhantomData, result::Result};
|
||||||
|
use xcm::prelude::*;
|
||||||
|
|
||||||
|
/// Wrapper router which, if the message does not already end with a `SetTopic` instruction,
|
||||||
|
/// appends one to the message filled with a universally unique ID. This ID is returned from a
|
||||||
|
/// successful `deliver`.
|
||||||
|
///
|
||||||
|
/// This is designed to be at the top-level of any routers, since it will always mutate the
|
||||||
|
/// passed `message` reference into a `None`. Don't try to combine it within a tuple except as the
|
||||||
|
/// last element.
|
||||||
|
pub struct WithUniqueTopic<Inner>(PhantomData<Inner>);
|
||||||
|
impl<Inner: SendXcm> SendXcm for WithUniqueTopic<Inner> {
|
||||||
|
type Ticket = (Inner::Ticket, [u8; 32]);
|
||||||
|
|
||||||
|
fn validate(
|
||||||
|
destination: &mut Option<MultiLocation>,
|
||||||
|
message: &mut Option<Xcm<()>>,
|
||||||
|
) -> SendResult<Self::Ticket> {
|
||||||
|
let mut message = message.take().ok_or(SendError::MissingArgument)?;
|
||||||
|
let unique_id = if let Some(SetTopic(id)) = message.last() {
|
||||||
|
*id
|
||||||
|
} else {
|
||||||
|
let unique_id = unique(&message);
|
||||||
|
message.0.push(SetTopic(unique_id.clone()));
|
||||||
|
unique_id
|
||||||
|
};
|
||||||
|
let (ticket, assets) = Inner::validate(destination, &mut Some(message))
|
||||||
|
.map_err(|_| SendError::NotApplicable)?;
|
||||||
|
Ok(((ticket, unique_id), assets))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deliver(ticket: Self::Ticket) -> Result<XcmHash, SendError> {
|
||||||
|
let (ticket, unique_id) = ticket;
|
||||||
|
Inner::deliver(ticket)?;
|
||||||
|
Ok(unique_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait SourceTopic {
|
||||||
|
fn source_topic(entropy: impl Encode) -> XcmHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SourceTopic for () {
|
||||||
|
fn source_topic(_: impl Encode) -> XcmHash {
|
||||||
|
[0u8; 32]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapper router which, if the message does not already end with a `SetTopic` instruction,
|
||||||
|
/// prepends one to the message filled with an ID from `TopicSource`. This ID is returned from a
|
||||||
|
/// successful `deliver`.
|
||||||
|
///
|
||||||
|
/// This is designed to be at the top-level of any routers, since it will always mutate the
|
||||||
|
/// passed `message` reference into a `None`. Don't try to combine it within a tuple except as the
|
||||||
|
/// last element.
|
||||||
|
pub struct WithTopicSource<Inner, TopicSource>(PhantomData<(Inner, TopicSource)>);
|
||||||
|
impl<Inner: SendXcm, TopicSource: SourceTopic> SendXcm for WithTopicSource<Inner, TopicSource> {
|
||||||
|
type Ticket = (Inner::Ticket, [u8; 32]);
|
||||||
|
|
||||||
|
fn validate(
|
||||||
|
destination: &mut Option<MultiLocation>,
|
||||||
|
message: &mut Option<Xcm<()>>,
|
||||||
|
) -> SendResult<Self::Ticket> {
|
||||||
|
let mut message = message.take().ok_or(SendError::MissingArgument)?;
|
||||||
|
let unique_id = if let Some(SetTopic(id)) = message.last() {
|
||||||
|
*id
|
||||||
|
} else {
|
||||||
|
let unique_id = TopicSource::source_topic(&message);
|
||||||
|
message.0.push(SetTopic(unique_id.clone()));
|
||||||
|
unique_id
|
||||||
|
};
|
||||||
|
let (ticket, assets) = Inner::validate(destination, &mut Some(message))
|
||||||
|
.map_err(|_| SendError::NotApplicable)?;
|
||||||
|
Ok(((ticket, unique_id), assets))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deliver(ticket: Self::Ticket) -> Result<XcmHash, SendError> {
|
||||||
|
let (ticket, unique_id) = ticket;
|
||||||
|
Inner::deliver(ticket)?;
|
||||||
|
Ok(unique_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,30 +14,36 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use xcm_executor::traits::Properties;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
fn props(weight_credit: Weight) -> Properties {
|
||||||
|
Properties { weight_credit, message_id: None }
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn take_weight_credit_barrier_should_work() {
|
fn take_weight_credit_barrier_should_work() {
|
||||||
let mut message =
|
let mut message =
|
||||||
Xcm::<()>(vec![TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() }]);
|
Xcm::<()>(vec![TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() }]);
|
||||||
let mut weight_credit = Weight::from_parts(10, 10);
|
let mut properties = props(Weight::from_parts(10, 10));
|
||||||
let r = TakeWeightCredit::should_execute(
|
let r = TakeWeightCredit::should_execute(
|
||||||
&Parent.into(),
|
&Parent.into(),
|
||||||
message.inner_mut(),
|
message.inner_mut(),
|
||||||
Weight::from_parts(10, 10),
|
Weight::from_parts(10, 10),
|
||||||
&mut weight_credit,
|
&mut properties,
|
||||||
);
|
);
|
||||||
assert_eq!(r, Ok(()));
|
assert_eq!(r, Ok(()));
|
||||||
assert_eq!(weight_credit, Weight::zero());
|
assert_eq!(properties.weight_credit, Weight::zero());
|
||||||
|
|
||||||
let r = TakeWeightCredit::should_execute(
|
let r = TakeWeightCredit::should_execute(
|
||||||
&Parent.into(),
|
&Parent.into(),
|
||||||
message.inner_mut(),
|
message.inner_mut(),
|
||||||
Weight::from_parts(10, 10),
|
Weight::from_parts(10, 10),
|
||||||
&mut weight_credit,
|
&mut properties,
|
||||||
);
|
);
|
||||||
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(10, 10))));
|
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(10, 10))));
|
||||||
assert_eq!(weight_credit, Weight::zero());
|
assert_eq!(properties.weight_credit, Weight::zero());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -67,7 +73,7 @@ fn computed_origin_should_work() {
|
|||||||
&Parent.into(),
|
&Parent.into(),
|
||||||
message.inner_mut(),
|
message.inner_mut(),
|
||||||
Weight::from_parts(100, 100),
|
Weight::from_parts(100, 100),
|
||||||
&mut Weight::zero(),
|
&mut props(Weight::zero()),
|
||||||
);
|
);
|
||||||
assert_eq!(r, Err(ProcessMessageError::Unsupported));
|
assert_eq!(r, Err(ProcessMessageError::Unsupported));
|
||||||
|
|
||||||
@@ -79,7 +85,7 @@ fn computed_origin_should_work() {
|
|||||||
&Parent.into(),
|
&Parent.into(),
|
||||||
message.inner_mut(),
|
message.inner_mut(),
|
||||||
Weight::from_parts(100, 100),
|
Weight::from_parts(100, 100),
|
||||||
&mut Weight::zero(),
|
&mut props(Weight::zero()),
|
||||||
);
|
);
|
||||||
assert_eq!(r, Err(ProcessMessageError::Unsupported));
|
assert_eq!(r, Err(ProcessMessageError::Unsupported));
|
||||||
|
|
||||||
@@ -91,7 +97,7 @@ fn computed_origin_should_work() {
|
|||||||
&Parent.into(),
|
&Parent.into(),
|
||||||
message.inner_mut(),
|
message.inner_mut(),
|
||||||
Weight::from_parts(100, 100),
|
Weight::from_parts(100, 100),
|
||||||
&mut Weight::zero(),
|
&mut props(Weight::zero()),
|
||||||
);
|
);
|
||||||
assert_eq!(r, Ok(()));
|
assert_eq!(r, Ok(()));
|
||||||
}
|
}
|
||||||
@@ -107,7 +113,7 @@ fn allow_unpaid_should_work() {
|
|||||||
&Parachain(1).into(),
|
&Parachain(1).into(),
|
||||||
message.inner_mut(),
|
message.inner_mut(),
|
||||||
Weight::from_parts(10, 10),
|
Weight::from_parts(10, 10),
|
||||||
&mut Weight::zero(),
|
&mut props(Weight::zero()),
|
||||||
);
|
);
|
||||||
assert_eq!(r, Err(ProcessMessageError::Unsupported));
|
assert_eq!(r, Err(ProcessMessageError::Unsupported));
|
||||||
|
|
||||||
@@ -115,7 +121,7 @@ fn allow_unpaid_should_work() {
|
|||||||
&Parent.into(),
|
&Parent.into(),
|
||||||
message.inner_mut(),
|
message.inner_mut(),
|
||||||
Weight::from_parts(10, 10),
|
Weight::from_parts(10, 10),
|
||||||
&mut Weight::zero(),
|
&mut props(Weight::zero()),
|
||||||
);
|
);
|
||||||
assert_eq!(r, Ok(()));
|
assert_eq!(r, Ok(()));
|
||||||
}
|
}
|
||||||
@@ -147,7 +153,7 @@ fn allow_explicit_unpaid_should_work() {
|
|||||||
&Parachain(1).into(),
|
&Parachain(1).into(),
|
||||||
good_message.inner_mut(),
|
good_message.inner_mut(),
|
||||||
Weight::from_parts(20, 20),
|
Weight::from_parts(20, 20),
|
||||||
&mut Weight::zero(),
|
&mut props(Weight::zero()),
|
||||||
);
|
);
|
||||||
assert_eq!(r, Err(ProcessMessageError::Unsupported));
|
assert_eq!(r, Err(ProcessMessageError::Unsupported));
|
||||||
|
|
||||||
@@ -155,7 +161,7 @@ fn allow_explicit_unpaid_should_work() {
|
|||||||
&Parent.into(),
|
&Parent.into(),
|
||||||
bad_message1.inner_mut(),
|
bad_message1.inner_mut(),
|
||||||
Weight::from_parts(20, 20),
|
Weight::from_parts(20, 20),
|
||||||
&mut Weight::zero(),
|
&mut props(Weight::zero()),
|
||||||
);
|
);
|
||||||
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(20, 20))));
|
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(20, 20))));
|
||||||
|
|
||||||
@@ -163,7 +169,7 @@ fn allow_explicit_unpaid_should_work() {
|
|||||||
&Parent.into(),
|
&Parent.into(),
|
||||||
bad_message2.inner_mut(),
|
bad_message2.inner_mut(),
|
||||||
Weight::from_parts(20, 20),
|
Weight::from_parts(20, 20),
|
||||||
&mut Weight::zero(),
|
&mut props(Weight::zero()),
|
||||||
);
|
);
|
||||||
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(20, 20))));
|
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(20, 20))));
|
||||||
|
|
||||||
@@ -171,7 +177,7 @@ fn allow_explicit_unpaid_should_work() {
|
|||||||
&Parent.into(),
|
&Parent.into(),
|
||||||
good_message.inner_mut(),
|
good_message.inner_mut(),
|
||||||
Weight::from_parts(20, 20),
|
Weight::from_parts(20, 20),
|
||||||
&mut Weight::zero(),
|
&mut props(Weight::zero()),
|
||||||
);
|
);
|
||||||
assert_eq!(r, Ok(()));
|
assert_eq!(r, Ok(()));
|
||||||
|
|
||||||
@@ -187,7 +193,7 @@ fn allow_explicit_unpaid_should_work() {
|
|||||||
&Parent.into(),
|
&Parent.into(),
|
||||||
message_with_different_weight_parts.inner_mut(),
|
message_with_different_weight_parts.inner_mut(),
|
||||||
Weight::from_parts(20, 20),
|
Weight::from_parts(20, 20),
|
||||||
&mut Weight::zero(),
|
&mut props(Weight::zero()),
|
||||||
);
|
);
|
||||||
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(20, 20))));
|
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(20, 20))));
|
||||||
|
|
||||||
@@ -195,7 +201,7 @@ fn allow_explicit_unpaid_should_work() {
|
|||||||
&Parent.into(),
|
&Parent.into(),
|
||||||
message_with_different_weight_parts.inner_mut(),
|
message_with_different_weight_parts.inner_mut(),
|
||||||
Weight::from_parts(10, 10),
|
Weight::from_parts(10, 10),
|
||||||
&mut Weight::zero(),
|
&mut props(Weight::zero()),
|
||||||
);
|
);
|
||||||
assert_eq!(r, Ok(()));
|
assert_eq!(r, Ok(()));
|
||||||
}
|
}
|
||||||
@@ -211,7 +217,7 @@ fn allow_paid_should_work() {
|
|||||||
&Parachain(1).into(),
|
&Parachain(1).into(),
|
||||||
message.inner_mut(),
|
message.inner_mut(),
|
||||||
Weight::from_parts(10, 10),
|
Weight::from_parts(10, 10),
|
||||||
&mut Weight::zero(),
|
&mut props(Weight::zero()),
|
||||||
);
|
);
|
||||||
assert_eq!(r, Err(ProcessMessageError::Unsupported));
|
assert_eq!(r, Err(ProcessMessageError::Unsupported));
|
||||||
|
|
||||||
@@ -226,7 +232,7 @@ fn allow_paid_should_work() {
|
|||||||
&Parent.into(),
|
&Parent.into(),
|
||||||
underpaying_message.inner_mut(),
|
underpaying_message.inner_mut(),
|
||||||
Weight::from_parts(30, 30),
|
Weight::from_parts(30, 30),
|
||||||
&mut Weight::zero(),
|
&mut props(Weight::zero()),
|
||||||
);
|
);
|
||||||
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(30, 30))));
|
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(30, 30))));
|
||||||
|
|
||||||
@@ -241,7 +247,7 @@ fn allow_paid_should_work() {
|
|||||||
&Parachain(1).into(),
|
&Parachain(1).into(),
|
||||||
paying_message.inner_mut(),
|
paying_message.inner_mut(),
|
||||||
Weight::from_parts(30, 30),
|
Weight::from_parts(30, 30),
|
||||||
&mut Weight::zero(),
|
&mut props(Weight::zero()),
|
||||||
);
|
);
|
||||||
assert_eq!(r, Err(ProcessMessageError::Unsupported));
|
assert_eq!(r, Err(ProcessMessageError::Unsupported));
|
||||||
|
|
||||||
@@ -249,7 +255,7 @@ fn allow_paid_should_work() {
|
|||||||
&Parent.into(),
|
&Parent.into(),
|
||||||
paying_message.inner_mut(),
|
paying_message.inner_mut(),
|
||||||
Weight::from_parts(30, 30),
|
Weight::from_parts(30, 30),
|
||||||
&mut Weight::zero(),
|
&mut props(Weight::zero()),
|
||||||
);
|
);
|
||||||
assert_eq!(r, Ok(()));
|
assert_eq!(r, Ok(()));
|
||||||
|
|
||||||
@@ -264,7 +270,7 @@ fn allow_paid_should_work() {
|
|||||||
&Parent.into(),
|
&Parent.into(),
|
||||||
paying_message_with_different_weight_parts.inner_mut(),
|
paying_message_with_different_weight_parts.inner_mut(),
|
||||||
Weight::from_parts(20, 20),
|
Weight::from_parts(20, 20),
|
||||||
&mut Weight::zero(),
|
&mut props(Weight::zero()),
|
||||||
);
|
);
|
||||||
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(20, 20))));
|
assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(20, 20))));
|
||||||
|
|
||||||
@@ -272,7 +278,7 @@ fn allow_paid_should_work() {
|
|||||||
&Parent.into(),
|
&Parent.into(),
|
||||||
paying_message_with_different_weight_parts.inner_mut(),
|
paying_message_with_different_weight_parts.inner_mut(),
|
||||||
Weight::from_parts(10, 10),
|
Weight::from_parts(10, 10),
|
||||||
&mut Weight::zero(),
|
&mut props(Weight::zero()),
|
||||||
);
|
);
|
||||||
assert_eq!(r, Ok(()))
|
assert_eq!(r, Ok(()))
|
||||||
}
|
}
|
||||||
@@ -288,7 +294,7 @@ fn suspension_should_work() {
|
|||||||
&Parent.into(),
|
&Parent.into(),
|
||||||
message.inner_mut(),
|
message.inner_mut(),
|
||||||
Weight::from_parts(10, 10),
|
Weight::from_parts(10, 10),
|
||||||
&mut Weight::zero(),
|
&mut props(Weight::zero()),
|
||||||
);
|
);
|
||||||
assert_eq!(r, Err(ProcessMessageError::Yield));
|
assert_eq!(r, Err(ProcessMessageError::Yield));
|
||||||
|
|
||||||
@@ -299,7 +305,7 @@ fn suspension_should_work() {
|
|||||||
&Parent.into(),
|
&Parent.into(),
|
||||||
message.inner_mut(),
|
message.inner_mut(),
|
||||||
Weight::from_parts(10, 10),
|
Weight::from_parts(10, 10),
|
||||||
&mut Weight::zero(),
|
&mut props(Weight::zero()),
|
||||||
);
|
);
|
||||||
assert_eq!(r, Ok(()));
|
assert_eq!(r, Ok(()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ parameter_types! {
|
|||||||
}
|
}
|
||||||
type TheBridge =
|
type TheBridge =
|
||||||
TestBridge<BridgeBlobDispatcher<TestRemoteIncomingRouter, RemoteUniversalLocation>>;
|
TestBridge<BridgeBlobDispatcher<TestRemoteIncomingRouter, RemoteUniversalLocation>>;
|
||||||
type Router = UnpaidLocalExporter<HaulBlobExporter<TheBridge, Remote, Price>, UniversalLocation>;
|
type Router =
|
||||||
|
TestTopic<UnpaidLocalExporter<HaulBlobExporter<TheBridge, Remote, Price>, UniversalLocation>>;
|
||||||
|
|
||||||
/// ```nocompile
|
/// ```nocompile
|
||||||
/// local | remote
|
/// local | remote
|
||||||
@@ -40,6 +41,7 @@ type Router = UnpaidLocalExporter<HaulBlobExporter<TheBridge, Remote, Price>, Un
|
|||||||
/// ```
|
/// ```
|
||||||
#[test]
|
#[test]
|
||||||
fn sending_to_bridged_chain_works() {
|
fn sending_to_bridged_chain_works() {
|
||||||
|
maybe_with_topic(|| {
|
||||||
let msg = Xcm(vec![Trap(1)]);
|
let msg = Xcm(vec![Trap(1)]);
|
||||||
let dest = (Parent, Parent, Remote::get(), Parachain(1)).into();
|
let dest = (Parent, Parent, Remote::get(), Parachain(1)).into();
|
||||||
assert_eq!(send_xcm::<Router>(dest, msg).unwrap().1, (Here, 100).into());
|
assert_eq!(send_xcm::<Router>(dest, msg).unwrap().1, (Here, 100).into());
|
||||||
@@ -48,13 +50,17 @@ fn sending_to_bridged_chain_works() {
|
|||||||
take_received_remote_messages(),
|
take_received_remote_messages(),
|
||||||
vec![(
|
vec![(
|
||||||
Here.into(),
|
Here.into(),
|
||||||
Xcm(vec![
|
xcm_with_topic(
|
||||||
|
[0; 32],
|
||||||
|
vec![
|
||||||
UniversalOrigin(Local::get().into()),
|
UniversalOrigin(Local::get().into()),
|
||||||
DescendOrigin(Parachain(1).into()),
|
DescendOrigin(Parachain(1).into()),
|
||||||
Trap(1),
|
Trap(1),
|
||||||
])
|
]
|
||||||
|
)
|
||||||
)]
|
)]
|
||||||
);
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ```nocompile
|
/// ```nocompile
|
||||||
@@ -69,19 +75,24 @@ fn sending_to_bridged_chain_works() {
|
|||||||
/// ```
|
/// ```
|
||||||
#[test]
|
#[test]
|
||||||
fn sending_to_parachain_of_bridged_chain_works() {
|
fn sending_to_parachain_of_bridged_chain_works() {
|
||||||
|
maybe_with_topic(|| {
|
||||||
let msg = Xcm(vec![Trap(1)]);
|
let msg = Xcm(vec![Trap(1)]);
|
||||||
let dest = (Parent, Parent, Remote::get(), Parachain(1000)).into();
|
let dest = (Parent, Parent, Remote::get(), Parachain(1000)).into();
|
||||||
assert_eq!(send_xcm::<Router>(dest, msg).unwrap().1, (Here, 100).into());
|
assert_eq!(send_xcm::<Router>(dest, msg).unwrap().1, (Here, 100).into());
|
||||||
assert_eq!(TheBridge::service(), 1);
|
assert_eq!(TheBridge::service(), 1);
|
||||||
let expected = vec![(
|
let expected = vec![(
|
||||||
(Parent, Parachain(1000)).into(),
|
(Parent, Parachain(1000)).into(),
|
||||||
Xcm(vec![
|
xcm_with_topic(
|
||||||
|
[0; 32],
|
||||||
|
vec![
|
||||||
UniversalOrigin(Local::get().into()),
|
UniversalOrigin(Local::get().into()),
|
||||||
DescendOrigin(Parachain(1).into()),
|
DescendOrigin(Parachain(1).into()),
|
||||||
Trap(1),
|
Trap(1),
|
||||||
]),
|
],
|
||||||
|
),
|
||||||
)];
|
)];
|
||||||
assert_eq!(take_received_remote_messages(), expected);
|
assert_eq!(take_received_remote_messages(), expected);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ```nocompile
|
/// ```nocompile
|
||||||
@@ -96,17 +107,22 @@ fn sending_to_parachain_of_bridged_chain_works() {
|
|||||||
/// ```
|
/// ```
|
||||||
#[test]
|
#[test]
|
||||||
fn sending_to_relay_chain_of_bridged_chain_works() {
|
fn sending_to_relay_chain_of_bridged_chain_works() {
|
||||||
|
maybe_with_topic(|| {
|
||||||
let msg = Xcm(vec![Trap(1)]);
|
let msg = Xcm(vec![Trap(1)]);
|
||||||
let dest = (Parent, Parent, Remote::get()).into();
|
let dest = (Parent, Parent, Remote::get()).into();
|
||||||
assert_eq!(send_xcm::<Router>(dest, msg).unwrap().1, (Here, 100).into());
|
assert_eq!(send_xcm::<Router>(dest, msg).unwrap().1, (Here, 100).into());
|
||||||
assert_eq!(TheBridge::service(), 1);
|
assert_eq!(TheBridge::service(), 1);
|
||||||
let expected = vec![(
|
let expected = vec![(
|
||||||
Parent.into(),
|
Parent.into(),
|
||||||
Xcm(vec![
|
xcm_with_topic(
|
||||||
|
[0; 32],
|
||||||
|
vec![
|
||||||
UniversalOrigin(Local::get().into()),
|
UniversalOrigin(Local::get().into()),
|
||||||
DescendOrigin(Parachain(1).into()),
|
DescendOrigin(Parachain(1).into()),
|
||||||
Trap(1),
|
Trap(1),
|
||||||
]),
|
],
|
||||||
|
),
|
||||||
)];
|
)];
|
||||||
assert_eq!(take_received_remote_messages(), expected);
|
assert_eq!(take_received_remote_messages(), expected);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ parameter_types! {
|
|||||||
}
|
}
|
||||||
type TheBridge =
|
type TheBridge =
|
||||||
TestBridge<BridgeBlobDispatcher<TestRemoteIncomingRouter, RemoteUniversalLocation>>;
|
TestBridge<BridgeBlobDispatcher<TestRemoteIncomingRouter, RemoteUniversalLocation>>;
|
||||||
type Router = UnpaidLocalExporter<HaulBlobExporter<TheBridge, Remote, Price>, UniversalLocation>;
|
type Router =
|
||||||
|
TestTopic<UnpaidLocalExporter<HaulBlobExporter<TheBridge, Remote, Price>, UniversalLocation>>;
|
||||||
|
|
||||||
/// ```nocompile
|
/// ```nocompile
|
||||||
/// local | remote
|
/// local | remote
|
||||||
@@ -36,16 +37,20 @@ type Router = UnpaidLocalExporter<HaulBlobExporter<TheBridge, Remote, Price>, Un
|
|||||||
/// ```
|
/// ```
|
||||||
#[test]
|
#[test]
|
||||||
fn sending_to_bridged_chain_works() {
|
fn sending_to_bridged_chain_works() {
|
||||||
|
maybe_with_topic(|| {
|
||||||
let msg = Xcm(vec![Trap(1)]);
|
let msg = Xcm(vec![Trap(1)]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
send_xcm::<Router>((Parent, Remote::get()).into(), msg).unwrap().1,
|
send_xcm::<Router>((Parent, Remote::get()).into(), msg).unwrap().1,
|
||||||
(Here, 100).into()
|
(Here, 100).into()
|
||||||
);
|
);
|
||||||
assert_eq!(TheBridge::service(), 1);
|
assert_eq!(TheBridge::service(), 1);
|
||||||
assert_eq!(
|
let expected = vec![(
|
||||||
take_received_remote_messages(),
|
Here.into(),
|
||||||
vec![(Here.into(), Xcm(vec![UniversalOrigin(Local::get().into()), Trap(1)]))]
|
xcm_with_topic([0; 32], vec![UniversalOrigin(Local::get().into()), Trap(1)]),
|
||||||
);
|
)];
|
||||||
|
assert_eq!(take_received_remote_messages(), expected);
|
||||||
|
assert_eq!(RoutingLog::take(), vec![]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ```nocompile
|
/// ```nocompile
|
||||||
@@ -60,11 +65,16 @@ fn sending_to_bridged_chain_works() {
|
|||||||
/// ```
|
/// ```
|
||||||
#[test]
|
#[test]
|
||||||
fn sending_to_parachain_of_bridged_chain_works() {
|
fn sending_to_parachain_of_bridged_chain_works() {
|
||||||
|
maybe_with_topic(|| {
|
||||||
let msg = Xcm(vec![Trap(1)]);
|
let msg = Xcm(vec![Trap(1)]);
|
||||||
let dest = (Parent, Remote::get(), Parachain(1000)).into();
|
let dest = (Parent, Remote::get(), Parachain(1000)).into();
|
||||||
assert_eq!(send_xcm::<Router>(dest, msg).unwrap().1, (Here, 100).into());
|
assert_eq!(send_xcm::<Router>(dest, msg).unwrap().1, (Here, 100).into());
|
||||||
assert_eq!(TheBridge::service(), 1);
|
assert_eq!(TheBridge::service(), 1);
|
||||||
let expected =
|
let expected = vec![(
|
||||||
vec![(Parachain(1000).into(), Xcm(vec![UniversalOrigin(Local::get().into()), Trap(1)]))];
|
Parachain(1000).into(),
|
||||||
|
xcm_with_topic([0; 32], vec![UniversalOrigin(Local::get().into()), Trap(1)]),
|
||||||
|
)];
|
||||||
assert_eq!(take_received_remote_messages(), expected);
|
assert_eq!(take_received_remote_messages(), expected);
|
||||||
|
assert_eq!(RoutingLog::take(), vec![]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
//! Tests specific to the bridging primitives
|
//! Tests specific to the bridging primitives
|
||||||
|
|
||||||
use super::mock::*;
|
use super::mock::*;
|
||||||
use crate::universal_exports::*;
|
use crate::{universal_exports::*, WithTopicSource};
|
||||||
use frame_support::{parameter_types, traits::Get};
|
use frame_support::{parameter_types, traits::Get};
|
||||||
use std::{cell::RefCell, marker::PhantomData};
|
use std::{cell::RefCell, marker::PhantomData};
|
||||||
use xcm_executor::{
|
use xcm_executor::{
|
||||||
@@ -37,12 +37,73 @@ parameter_types! {
|
|||||||
pub Local: NetworkId = ByGenesis([0; 32]);
|
pub Local: NetworkId = ByGenesis([0; 32]);
|
||||||
pub Remote: NetworkId = ByGenesis([1; 32]);
|
pub Remote: NetworkId = ByGenesis([1; 32]);
|
||||||
pub Price: MultiAssets = MultiAssets::from((Here, 100u128));
|
pub Price: MultiAssets = MultiAssets::from((Here, 100u128));
|
||||||
|
pub static UsingTopic: bool = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::thread_local! {
|
std::thread_local! {
|
||||||
static BRIDGE_TRAFFIC: RefCell<Vec<Vec<u8>>> = RefCell::new(Vec::new());
|
static BRIDGE_TRAFFIC: RefCell<Vec<Vec<u8>>> = RefCell::new(Vec::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn maybe_with_topic(f: impl Fn()) {
|
||||||
|
UsingTopic::set(false);
|
||||||
|
f();
|
||||||
|
UsingTopic::set(true);
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn xcm_with_topic<T>(topic: XcmHash, mut xcm: Vec<Instruction<T>>) -> Xcm<T> {
|
||||||
|
if UsingTopic::get() {
|
||||||
|
xcm.push(SetTopic(topic));
|
||||||
|
}
|
||||||
|
Xcm(xcm)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fake_id() -> XcmHash {
|
||||||
|
[255; 32]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_weight(mut count: u64) -> Weight {
|
||||||
|
if UsingTopic::get() {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
Weight::from_parts(count * 10, count * 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn maybe_forward_id_for(topic: &XcmHash) -> XcmHash {
|
||||||
|
match UsingTopic::get() {
|
||||||
|
true => forward_id_for(topic),
|
||||||
|
false => fake_id(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum TestTicket<T: SendXcm> {
|
||||||
|
Basic(T::Ticket),
|
||||||
|
Topic(<WithTopicSource<T, ()> as SendXcm>::Ticket),
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TestTopic<R>(PhantomData<R>);
|
||||||
|
impl<R: SendXcm> SendXcm for TestTopic<R> {
|
||||||
|
type Ticket = TestTicket<R>;
|
||||||
|
fn deliver(ticket: Self::Ticket) -> core::result::Result<XcmHash, SendError> {
|
||||||
|
match ticket {
|
||||||
|
TestTicket::Basic(t) => R::deliver(t),
|
||||||
|
TestTicket::Topic(t) => WithTopicSource::<R, ()>::deliver(t),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn validate(
|
||||||
|
destination: &mut Option<MultiLocation>,
|
||||||
|
message: &mut Option<Xcm<()>>,
|
||||||
|
) -> SendResult<Self::Ticket> {
|
||||||
|
Ok(if UsingTopic::get() {
|
||||||
|
let (t, a) = WithTopicSource::<R, ()>::validate(destination, message)?;
|
||||||
|
(TestTicket::Topic(t), a)
|
||||||
|
} else {
|
||||||
|
let (t, a) = R::validate(destination, message)?;
|
||||||
|
(TestTicket::Basic(t), a)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct TestBridge<D>(PhantomData<D>);
|
struct TestBridge<D>(PhantomData<D>);
|
||||||
impl<D: DispatchBlob> TestBridge<D> {
|
impl<D: DispatchBlob> TestBridge<D> {
|
||||||
fn service() -> u64 {
|
fn service() -> u64 {
|
||||||
@@ -71,7 +132,7 @@ impl SendXcm for TestRemoteIncomingRouter {
|
|||||||
Ok((pair, MultiAssets::new()))
|
Ok((pair, MultiAssets::new()))
|
||||||
}
|
}
|
||||||
fn deliver(pair: (MultiLocation, Xcm<()>)) -> Result<XcmHash, SendError> {
|
fn deliver(pair: (MultiLocation, Xcm<()>)) -> Result<XcmHash, SendError> {
|
||||||
let hash = fake_message_hash(&pair.1);
|
let hash = fake_id();
|
||||||
REMOTE_INCOMING_XCM.with(|q| q.borrow_mut().push(pair));
|
REMOTE_INCOMING_XCM.with(|q| q.borrow_mut().push(pair));
|
||||||
Ok(hash)
|
Ok(hash)
|
||||||
}
|
}
|
||||||
@@ -107,6 +168,20 @@ fn deliver<RemoteExporter: ExportXcm>(
|
|||||||
export_xcm::<RemoteExporter>(n, c, s, d, m).map(|(hash, _)| hash)
|
export_xcm::<RemoteExporter>(n, c, s, d, m).map(|(hash, _)| hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq, Clone, Debug)]
|
||||||
|
pub struct LogEntry {
|
||||||
|
local: Junctions,
|
||||||
|
remote: Junctions,
|
||||||
|
id: XcmHash,
|
||||||
|
message: Xcm<()>,
|
||||||
|
outcome: Outcome,
|
||||||
|
paid: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
parameter_types! {
|
||||||
|
pub static RoutingLog: Vec<LogEntry> = vec![];
|
||||||
|
}
|
||||||
|
|
||||||
impl<Local: Get<Junctions>, Remote: Get<Junctions>, RemoteExporter: ExportXcm> SendXcm
|
impl<Local: Get<Junctions>, Remote: Get<Junctions>, RemoteExporter: ExportXcm> SendXcm
|
||||||
for UnpaidExecutingRouter<Local, Remote, RemoteExporter>
|
for UnpaidExecutingRouter<Local, Remote, RemoteExporter>
|
||||||
{
|
{
|
||||||
@@ -133,15 +208,20 @@ impl<Local: Get<Junctions>, Remote: Get<Junctions>, RemoteExporter: ExportXcm> S
|
|||||||
AllowUnpaidFrom::set(vec![origin.clone()]);
|
AllowUnpaidFrom::set(vec![origin.clone()]);
|
||||||
set_exporter_override(price::<RemoteExporter>, deliver::<RemoteExporter>);
|
set_exporter_override(price::<RemoteExporter>, deliver::<RemoteExporter>);
|
||||||
// The we execute it:
|
// The we execute it:
|
||||||
let hash = fake_message_hash(&message);
|
let mut id = fake_id();
|
||||||
let outcome = XcmExecutor::<TestConfig>::execute_xcm(
|
let outcome = XcmExecutor::<TestConfig>::prepare_and_execute(
|
||||||
origin,
|
origin,
|
||||||
message.into(),
|
message.clone().into(),
|
||||||
hash,
|
&mut id,
|
||||||
Weight::from_parts(2_000_000_000_000, 2_000_000_000_000),
|
Weight::from_parts(2_000_000_000_000, 2_000_000_000_000),
|
||||||
|
Weight::zero(),
|
||||||
);
|
);
|
||||||
|
let local = Local::get();
|
||||||
|
let remote = Remote::get();
|
||||||
|
let entry = LogEntry { local, remote, id, message, outcome: outcome.clone(), paid: false };
|
||||||
|
RoutingLog::mutate(|l| l.push(entry));
|
||||||
match outcome {
|
match outcome {
|
||||||
Outcome::Complete(..) => Ok(hash),
|
Outcome::Complete(..) => Ok(id),
|
||||||
Outcome::Incomplete(..) => Err(Transport("Error executing")),
|
Outcome::Incomplete(..) => Err(Transport("Error executing")),
|
||||||
Outcome::Error(..) => Err(Transport("Unable to execute")),
|
Outcome::Error(..) => Err(Transport("Unable to execute")),
|
||||||
}
|
}
|
||||||
@@ -178,15 +258,20 @@ impl<Local: Get<Junctions>, Remote: Get<Junctions>, RemoteExporter: ExportXcm> S
|
|||||||
AllowPaidFrom::set(vec![origin.clone()]);
|
AllowPaidFrom::set(vec![origin.clone()]);
|
||||||
set_exporter_override(price::<RemoteExporter>, deliver::<RemoteExporter>);
|
set_exporter_override(price::<RemoteExporter>, deliver::<RemoteExporter>);
|
||||||
// Then we execute it:
|
// Then we execute it:
|
||||||
let hash = fake_message_hash(&message);
|
let mut id = fake_id();
|
||||||
let outcome = XcmExecutor::<TestConfig>::execute_xcm(
|
let outcome = XcmExecutor::<TestConfig>::prepare_and_execute(
|
||||||
origin,
|
origin,
|
||||||
message.into(),
|
message.clone().into(),
|
||||||
hash,
|
&mut id,
|
||||||
Weight::from_parts(2_000_000_000_000, 2_000_000_000_000),
|
Weight::from_parts(2_000_000_000_000, 2_000_000_000_000),
|
||||||
|
Weight::zero(),
|
||||||
);
|
);
|
||||||
|
let local = Local::get();
|
||||||
|
let remote = Remote::get();
|
||||||
|
let entry = LogEntry { local, remote, id, message, outcome: outcome.clone(), paid: true };
|
||||||
|
RoutingLog::mutate(|l| l.push(entry));
|
||||||
match outcome {
|
match outcome {
|
||||||
Outcome::Complete(..) => Ok(hash),
|
Outcome::Complete(..) => Ok(id),
|
||||||
Outcome::Incomplete(..) => Err(Transport("Error executing")),
|
Outcome::Incomplete(..) => Err(Transport("Error executing")),
|
||||||
Outcome::Error(..) => Err(Transport("Unable to execute")),
|
Outcome::Error(..) => Err(Transport("Unable to execute")),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ parameter_types! {
|
|||||||
pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(100));
|
pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(100));
|
||||||
pub RelayUniversalLocation: Junctions = X1(GlobalConsensus(Local::get()));
|
pub RelayUniversalLocation: Junctions = X1(GlobalConsensus(Local::get()));
|
||||||
pub RemoteUniversalLocation: Junctions = X1(GlobalConsensus(Remote::get()));
|
pub RemoteUniversalLocation: Junctions = X1(GlobalConsensus(Remote::get()));
|
||||||
pub static BridgeTable: Vec<(NetworkId, MultiLocation, Option<MultiAsset>)>
|
pub BridgeTable: Vec<(NetworkId, MultiLocation, Option<MultiAsset>)>
|
||||||
= vec![(Remote::get(), MultiLocation::parent(), Some((Parent, 200u128).into()))];
|
= vec![(Remote::get(), MultiLocation::parent(), Some((Parent, 200u128 + if UsingTopic::get() { 20 } else { 0 }).into()))];
|
||||||
// ^^^ 100 to use the bridge (export) and 100 for the remote execution weight (5 instructions
|
// ^^^ 100 to use the bridge (export) and 100 for the remote execution weight (5 instructions
|
||||||
// x (10 + 10) weight each).
|
// x (10 + 10) weight each).
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@ type LocalBridgeRouter = SovereignPaidRemoteExporter<
|
|||||||
LocalInnerRouter,
|
LocalInnerRouter,
|
||||||
UniversalLocation,
|
UniversalLocation,
|
||||||
>;
|
>;
|
||||||
type LocalRouter = (LocalInnerRouter, LocalBridgeRouter);
|
type LocalRouter = TestTopic<(LocalInnerRouter, LocalBridgeRouter)>;
|
||||||
|
|
||||||
/// ```nocompile
|
/// ```nocompile
|
||||||
/// local | remote
|
/// local | remote
|
||||||
@@ -55,33 +55,66 @@ type LocalRouter = (LocalInnerRouter, LocalBridgeRouter);
|
|||||||
/// ```
|
/// ```
|
||||||
#[test]
|
#[test]
|
||||||
fn sending_to_bridged_chain_works() {
|
fn sending_to_bridged_chain_works() {
|
||||||
|
maybe_with_topic(|| {
|
||||||
|
let dest: MultiLocation = (Parent, Parent, Remote::get()).into();
|
||||||
|
|
||||||
|
// Initialize the local relay so that our parachain has funds to pay for export.
|
||||||
|
clear_assets(Parachain(100));
|
||||||
|
add_asset(Parachain(100), (Here, 1000u128));
|
||||||
|
|
||||||
|
let price = 200u128 + if UsingTopic::get() { 20 } else { 0 };
|
||||||
|
|
||||||
|
let msg = Xcm(vec![Trap(1)]);
|
||||||
|
assert_eq!(send_xcm::<LocalRouter>(dest, msg).unwrap().1, (Parent, price).into());
|
||||||
|
assert_eq!(TheBridge::service(), 1);
|
||||||
|
let expected = vec![(
|
||||||
|
Here.into(),
|
||||||
|
xcm_with_topic(
|
||||||
|
[0; 32],
|
||||||
|
vec![
|
||||||
|
UniversalOrigin(Local::get().into()),
|
||||||
|
DescendOrigin(Parachain(100).into()),
|
||||||
|
Trap(1),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)];
|
||||||
|
assert_eq!(take_received_remote_messages(), expected);
|
||||||
|
|
||||||
|
// The export cost 50 ref time and 50 proof size weight units (and thus 100 units of balance).
|
||||||
|
assert_eq!(asset_list(Parachain(100)), vec![(Here, 1000u128 - price).into()]);
|
||||||
|
|
||||||
|
let entry = LogEntry {
|
||||||
|
local: UniversalLocation::get(),
|
||||||
|
remote: RelayUniversalLocation::get(),
|
||||||
|
id: maybe_forward_id_for(&[0; 32]),
|
||||||
|
message: xcm_with_topic(
|
||||||
|
maybe_forward_id_for(&[0; 32]),
|
||||||
|
vec![
|
||||||
|
WithdrawAsset(MultiAsset::from((Here, price)).into()),
|
||||||
|
BuyExecution { fees: (Here, price).into(), weight_limit: Unlimited },
|
||||||
|
ExportMessage {
|
||||||
|
network: ByGenesis([1; 32]),
|
||||||
|
destination: Here,
|
||||||
|
xcm: xcm_with_topic([0; 32], vec![Trap(1)]),
|
||||||
|
},
|
||||||
|
RefundSurplus,
|
||||||
|
DepositAsset { assets: Wild(All), beneficiary: Parachain(100).into() },
|
||||||
|
],
|
||||||
|
),
|
||||||
|
outcome: Outcome::Complete(test_weight(5)),
|
||||||
|
paid: true,
|
||||||
|
};
|
||||||
|
assert_eq!(RoutingLog::take(), vec![entry]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn sending_to_bridged_chain_without_funds_fails() {
|
||||||
let dest: MultiLocation = (Parent, Parent, Remote::get()).into();
|
let dest: MultiLocation = (Parent, Parent, Remote::get()).into();
|
||||||
// Routing won't work if we don't have enough funds.
|
// Routing won't work if we don't have enough funds.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
send_xcm::<LocalRouter>(dest.clone(), Xcm(vec![Trap(1)])),
|
send_xcm::<LocalRouter>(dest.clone(), Xcm(vec![Trap(1)])),
|
||||||
Err(SendError::Transport("Error executing")),
|
Err(SendError::Transport("Error executing")),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Initialize the local relay so that our parachain has funds to pay for export.
|
|
||||||
add_asset(Parachain(100), (Here, 1000u128));
|
|
||||||
|
|
||||||
let msg = Xcm(vec![Trap(1)]);
|
|
||||||
assert_eq!(send_xcm::<LocalRouter>(dest, msg).unwrap().1, (Parent, 200u128).into());
|
|
||||||
assert_eq!(TheBridge::service(), 1);
|
|
||||||
assert_eq!(
|
|
||||||
take_received_remote_messages(),
|
|
||||||
vec![(
|
|
||||||
Here.into(),
|
|
||||||
Xcm(vec![
|
|
||||||
UniversalOrigin(Local::get().into()),
|
|
||||||
DescendOrigin(Parachain(100).into()),
|
|
||||||
Trap(1),
|
|
||||||
])
|
|
||||||
)]
|
|
||||||
);
|
|
||||||
|
|
||||||
// The export cost 50 ref time and 50 proof size weight units (and thus 100 units of balance).
|
|
||||||
assert_eq!(asset_list(Parachain(100)), vec![(Here, 800u128).into()]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ```nocompile
|
/// ```nocompile
|
||||||
@@ -96,29 +129,64 @@ fn sending_to_bridged_chain_works() {
|
|||||||
/// ```
|
/// ```
|
||||||
#[test]
|
#[test]
|
||||||
fn sending_to_parachain_of_bridged_chain_works() {
|
fn sending_to_parachain_of_bridged_chain_works() {
|
||||||
|
maybe_with_topic(|| {
|
||||||
|
let dest: MultiLocation = (Parent, Parent, Remote::get(), Parachain(100)).into();
|
||||||
|
|
||||||
|
// Initialize the local relay so that our parachain has funds to pay for export.
|
||||||
|
clear_assets(Parachain(100));
|
||||||
|
add_asset(Parachain(100), (Here, 1000u128));
|
||||||
|
|
||||||
|
let price = 200u128 + if UsingTopic::get() { 20 } else { 0 };
|
||||||
|
|
||||||
|
let msg = Xcm(vec![Trap(1)]);
|
||||||
|
assert_eq!(send_xcm::<LocalRouter>(dest, msg).unwrap().1, (Parent, price).into());
|
||||||
|
assert_eq!(TheBridge::service(), 1);
|
||||||
|
let expected = vec![(
|
||||||
|
Parachain(100).into(),
|
||||||
|
xcm_with_topic(
|
||||||
|
[0; 32],
|
||||||
|
vec![
|
||||||
|
UniversalOrigin(Local::get().into()),
|
||||||
|
DescendOrigin(Parachain(100).into()),
|
||||||
|
Trap(1),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)];
|
||||||
|
assert_eq!(take_received_remote_messages(), expected);
|
||||||
|
|
||||||
|
// The export cost 50 ref time and 50 proof size weight units (and thus 100 units of balance).
|
||||||
|
assert_eq!(asset_list(Parachain(100)), vec![(Here, 1000u128 - price).into()]);
|
||||||
|
|
||||||
|
let entry = LogEntry {
|
||||||
|
local: UniversalLocation::get(),
|
||||||
|
remote: RelayUniversalLocation::get(),
|
||||||
|
id: maybe_forward_id_for(&[0; 32]),
|
||||||
|
message: xcm_with_topic(
|
||||||
|
maybe_forward_id_for(&[0; 32]),
|
||||||
|
vec![
|
||||||
|
WithdrawAsset(MultiAsset::from((Here, price)).into()),
|
||||||
|
BuyExecution { fees: (Here, price).into(), weight_limit: Unlimited },
|
||||||
|
ExportMessage {
|
||||||
|
network: ByGenesis([1; 32]),
|
||||||
|
destination: Parachain(100).into(),
|
||||||
|
xcm: xcm_with_topic([0; 32], vec![Trap(1)]),
|
||||||
|
},
|
||||||
|
RefundSurplus,
|
||||||
|
DepositAsset { assets: Wild(All), beneficiary: Parachain(100).into() },
|
||||||
|
],
|
||||||
|
),
|
||||||
|
outcome: Outcome::Complete(test_weight(5)),
|
||||||
|
paid: true,
|
||||||
|
};
|
||||||
|
assert_eq!(RoutingLog::take(), vec![entry]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn sending_to_parachain_of_bridged_chain_without_funds_fails() {
|
||||||
let dest: MultiLocation = (Parent, Parent, Remote::get(), Parachain(100)).into();
|
let dest: MultiLocation = (Parent, Parent, Remote::get(), Parachain(100)).into();
|
||||||
// Routing won't work if we don't have enough funds.
|
// Routing won't work if we don't have enough funds.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
send_xcm::<LocalRouter>(dest.clone(), Xcm(vec![Trap(1)])),
|
send_xcm::<LocalRouter>(dest.clone(), Xcm(vec![Trap(1)])),
|
||||||
Err(SendError::Transport("Error executing")),
|
Err(SendError::Transport("Error executing")),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Initialize the local relay so that our parachain has funds to pay for export.
|
|
||||||
add_asset(Parachain(100), (Here, 1000u128));
|
|
||||||
|
|
||||||
let msg = Xcm(vec![Trap(1)]);
|
|
||||||
assert_eq!(send_xcm::<LocalRouter>(dest, msg).unwrap().1, (Parent, 200u128).into());
|
|
||||||
assert_eq!(TheBridge::service(), 1);
|
|
||||||
let expected = vec![(
|
|
||||||
Parachain(100).into(),
|
|
||||||
Xcm(vec![
|
|
||||||
UniversalOrigin(Local::get().into()),
|
|
||||||
DescendOrigin(Parachain(100).into()),
|
|
||||||
Trap(1),
|
|
||||||
]),
|
|
||||||
)];
|
|
||||||
assert_eq!(take_received_remote_messages(), expected);
|
|
||||||
|
|
||||||
// The export cost 50 ref time and 50 proof size weight units (and thus 100 units of balance).
|
|
||||||
assert_eq!(asset_list(Parachain(100)), vec![(Here, 800u128).into()]);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ type LocalInnerRouter =
|
|||||||
UnpaidExecutingRouter<UniversalLocation, ParaBridgeUniversalLocation, RelayExporter>;
|
UnpaidExecutingRouter<UniversalLocation, ParaBridgeUniversalLocation, RelayExporter>;
|
||||||
type LocalBridgingRouter =
|
type LocalBridgingRouter =
|
||||||
UnpaidRemoteExporter<NetworkExportTable<BridgeTable>, LocalInnerRouter, UniversalLocation>;
|
UnpaidRemoteExporter<NetworkExportTable<BridgeTable>, LocalInnerRouter, UniversalLocation>;
|
||||||
type LocalRouter = (LocalInnerRouter, LocalBridgingRouter);
|
type LocalRouter = TestTopic<(LocalInnerRouter, LocalBridgingRouter)>;
|
||||||
|
|
||||||
/// ```nocompile
|
/// ```nocompile
|
||||||
/// local | remote
|
/// local | remote
|
||||||
@@ -48,6 +48,7 @@ type LocalRouter = (LocalInnerRouter, LocalBridgingRouter);
|
|||||||
/// ```
|
/// ```
|
||||||
#[test]
|
#[test]
|
||||||
fn sending_to_bridged_chain_works() {
|
fn sending_to_bridged_chain_works() {
|
||||||
|
maybe_with_topic(|| {
|
||||||
let msg = Xcm(vec![Trap(1)]);
|
let msg = Xcm(vec![Trap(1)]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
send_xcm::<LocalRouter>((Parent, Parent, Remote::get(), Parachain(1)).into(), msg)
|
send_xcm::<LocalRouter>((Parent, Parent, Remote::get(), Parachain(1)).into(), msg)
|
||||||
@@ -60,13 +61,36 @@ fn sending_to_bridged_chain_works() {
|
|||||||
take_received_remote_messages(),
|
take_received_remote_messages(),
|
||||||
vec![(
|
vec![(
|
||||||
Here.into(),
|
Here.into(),
|
||||||
Xcm(vec![
|
xcm_with_topic(
|
||||||
|
[0; 32],
|
||||||
|
vec![
|
||||||
UniversalOrigin(Local::get().into()),
|
UniversalOrigin(Local::get().into()),
|
||||||
DescendOrigin(Parachain(1000).into()),
|
DescendOrigin(Parachain(1000).into()),
|
||||||
Trap(1)
|
Trap(1)
|
||||||
])
|
]
|
||||||
|
)
|
||||||
)]
|
)]
|
||||||
);
|
);
|
||||||
|
let entry = LogEntry {
|
||||||
|
local: UniversalLocation::get(),
|
||||||
|
remote: ParaBridgeUniversalLocation::get(),
|
||||||
|
id: maybe_forward_id_for(&[0; 32]),
|
||||||
|
message: xcm_with_topic(
|
||||||
|
maybe_forward_id_for(&[0; 32]),
|
||||||
|
vec![
|
||||||
|
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
|
||||||
|
ExportMessage {
|
||||||
|
network: ByGenesis([1; 32]),
|
||||||
|
destination: Parachain(1).into(),
|
||||||
|
xcm: xcm_with_topic([0; 32], vec![Trap(1)]),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
outcome: Outcome::Complete(test_weight(2)),
|
||||||
|
paid: false,
|
||||||
|
};
|
||||||
|
assert_eq!(RoutingLog::take(), vec![entry]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ```nocompile
|
/// ```nocompile
|
||||||
@@ -81,19 +105,43 @@ fn sending_to_bridged_chain_works() {
|
|||||||
/// ```
|
/// ```
|
||||||
#[test]
|
#[test]
|
||||||
fn sending_to_sibling_of_bridged_chain_works() {
|
fn sending_to_sibling_of_bridged_chain_works() {
|
||||||
|
maybe_with_topic(|| {
|
||||||
let msg = Xcm(vec![Trap(1)]);
|
let msg = Xcm(vec![Trap(1)]);
|
||||||
let dest = (Parent, Parent, Remote::get(), Parachain(1000)).into();
|
let dest = (Parent, Parent, Remote::get(), Parachain(1000)).into();
|
||||||
assert_eq!(send_xcm::<LocalRouter>(dest, msg).unwrap().1, MultiAssets::new());
|
assert_eq!(send_xcm::<LocalRouter>(dest, msg).unwrap().1, MultiAssets::new());
|
||||||
assert_eq!(TheBridge::service(), 1);
|
assert_eq!(TheBridge::service(), 1);
|
||||||
let expected = vec![(
|
let expected = vec![(
|
||||||
(Parent, Parachain(1000)).into(),
|
(Parent, Parachain(1000)).into(),
|
||||||
Xcm(vec![
|
xcm_with_topic(
|
||||||
|
[0; 32],
|
||||||
|
vec![
|
||||||
UniversalOrigin(Local::get().into()),
|
UniversalOrigin(Local::get().into()),
|
||||||
DescendOrigin(Parachain(1000).into()),
|
DescendOrigin(Parachain(1000).into()),
|
||||||
Trap(1),
|
Trap(1),
|
||||||
]),
|
],
|
||||||
|
),
|
||||||
)];
|
)];
|
||||||
assert_eq!(take_received_remote_messages(), expected);
|
assert_eq!(take_received_remote_messages(), expected);
|
||||||
|
let entry = LogEntry {
|
||||||
|
local: UniversalLocation::get(),
|
||||||
|
remote: ParaBridgeUniversalLocation::get(),
|
||||||
|
id: maybe_forward_id_for(&[0; 32]),
|
||||||
|
message: xcm_with_topic(
|
||||||
|
maybe_forward_id_for(&[0; 32]),
|
||||||
|
vec![
|
||||||
|
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
|
||||||
|
ExportMessage {
|
||||||
|
network: ByGenesis([1; 32]),
|
||||||
|
destination: Parachain(1000).into(),
|
||||||
|
xcm: xcm_with_topic([0; 32], vec![Trap(1)]),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
outcome: Outcome::Complete(test_weight(2)),
|
||||||
|
paid: false,
|
||||||
|
};
|
||||||
|
assert_eq!(RoutingLog::take(), vec![entry]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ```nocompile
|
/// ```nocompile
|
||||||
@@ -108,17 +156,41 @@ fn sending_to_sibling_of_bridged_chain_works() {
|
|||||||
/// ```
|
/// ```
|
||||||
#[test]
|
#[test]
|
||||||
fn sending_to_relay_of_bridged_chain_works() {
|
fn sending_to_relay_of_bridged_chain_works() {
|
||||||
|
maybe_with_topic(|| {
|
||||||
let msg = Xcm(vec![Trap(1)]);
|
let msg = Xcm(vec![Trap(1)]);
|
||||||
let dest = (Parent, Parent, Remote::get()).into();
|
let dest = (Parent, Parent, Remote::get()).into();
|
||||||
assert_eq!(send_xcm::<LocalRouter>(dest, msg).unwrap().1, MultiAssets::new());
|
assert_eq!(send_xcm::<LocalRouter>(dest, msg).unwrap().1, MultiAssets::new());
|
||||||
assert_eq!(TheBridge::service(), 1);
|
assert_eq!(TheBridge::service(), 1);
|
||||||
let expected = vec![(
|
let expected = vec![(
|
||||||
Parent.into(),
|
Parent.into(),
|
||||||
Xcm(vec![
|
xcm_with_topic(
|
||||||
|
[0; 32],
|
||||||
|
vec![
|
||||||
UniversalOrigin(Local::get().into()),
|
UniversalOrigin(Local::get().into()),
|
||||||
DescendOrigin(Parachain(1000).into()),
|
DescendOrigin(Parachain(1000).into()),
|
||||||
Trap(1),
|
Trap(1),
|
||||||
]),
|
],
|
||||||
|
),
|
||||||
)];
|
)];
|
||||||
assert_eq!(take_received_remote_messages(), expected);
|
assert_eq!(take_received_remote_messages(), expected);
|
||||||
|
let entry = LogEntry {
|
||||||
|
local: UniversalLocation::get(),
|
||||||
|
remote: ParaBridgeUniversalLocation::get(),
|
||||||
|
id: maybe_forward_id_for(&[0; 32]),
|
||||||
|
message: xcm_with_topic(
|
||||||
|
maybe_forward_id_for(&[0; 32]),
|
||||||
|
vec![
|
||||||
|
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
|
||||||
|
ExportMessage {
|
||||||
|
network: ByGenesis([1; 32]),
|
||||||
|
destination: Here,
|
||||||
|
xcm: xcm_with_topic([0; 32], vec![Trap(1)]),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
outcome: Outcome::Complete(test_weight(2)),
|
||||||
|
paid: false,
|
||||||
|
};
|
||||||
|
assert_eq!(RoutingLog::take(), vec![entry]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ type LocalInnerRouter =
|
|||||||
UnpaidExecutingRouter<UniversalLocation, ParaBridgeUniversalLocation, RelayExporter>;
|
UnpaidExecutingRouter<UniversalLocation, ParaBridgeUniversalLocation, RelayExporter>;
|
||||||
type LocalBridgingRouter =
|
type LocalBridgingRouter =
|
||||||
UnpaidRemoteExporter<NetworkExportTable<BridgeTable>, LocalInnerRouter, UniversalLocation>;
|
UnpaidRemoteExporter<NetworkExportTable<BridgeTable>, LocalInnerRouter, UniversalLocation>;
|
||||||
type LocalRouter = (LocalInnerRouter, LocalBridgingRouter);
|
type LocalRouter = TestTopic<(LocalInnerRouter, LocalBridgingRouter)>;
|
||||||
|
|
||||||
/// ```nocompile
|
/// ```nocompile
|
||||||
/// local | remote
|
/// local | remote
|
||||||
@@ -48,6 +48,7 @@ type LocalRouter = (LocalInnerRouter, LocalBridgingRouter);
|
|||||||
/// ```
|
/// ```
|
||||||
#[test]
|
#[test]
|
||||||
fn sending_to_bridged_chain_works() {
|
fn sending_to_bridged_chain_works() {
|
||||||
|
maybe_with_topic(|| {
|
||||||
let msg = Xcm(vec![Trap(1)]);
|
let msg = Xcm(vec![Trap(1)]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
send_xcm::<LocalRouter>((Parent, Remote::get(), Parachain(1)).into(), msg)
|
send_xcm::<LocalRouter>((Parent, Remote::get(), Parachain(1)).into(), msg)
|
||||||
@@ -56,10 +57,31 @@ fn sending_to_bridged_chain_works() {
|
|||||||
MultiAssets::new()
|
MultiAssets::new()
|
||||||
);
|
);
|
||||||
assert_eq!(TheBridge::service(), 1);
|
assert_eq!(TheBridge::service(), 1);
|
||||||
assert_eq!(
|
let expected = vec![(
|
||||||
take_received_remote_messages(),
|
Here.into(),
|
||||||
vec![(Here.into(), Xcm(vec![UniversalOrigin(Local::get().into()), Trap(1)]))]
|
xcm_with_topic([0; 32], vec![UniversalOrigin(Local::get().into()), Trap(1)]),
|
||||||
);
|
)];
|
||||||
|
assert_eq!(take_received_remote_messages(), expected);
|
||||||
|
let entry = LogEntry {
|
||||||
|
local: UniversalLocation::get(),
|
||||||
|
remote: ParaBridgeUniversalLocation::get(),
|
||||||
|
id: maybe_forward_id_for(&[0; 32]),
|
||||||
|
message: xcm_with_topic(
|
||||||
|
maybe_forward_id_for(&[0; 32]),
|
||||||
|
vec![
|
||||||
|
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
|
||||||
|
ExportMessage {
|
||||||
|
network: ByGenesis([1; 32]),
|
||||||
|
destination: Parachain(1).into(),
|
||||||
|
xcm: xcm_with_topic([0; 32], vec![Trap(1)]),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
outcome: Outcome::Complete(test_weight(2)),
|
||||||
|
paid: false,
|
||||||
|
};
|
||||||
|
assert_eq!(RoutingLog::take(), vec![entry]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ```nocompile
|
/// ```nocompile
|
||||||
@@ -74,15 +96,36 @@ fn sending_to_bridged_chain_works() {
|
|||||||
/// ```
|
/// ```
|
||||||
#[test]
|
#[test]
|
||||||
fn sending_to_sibling_of_bridged_chain_works() {
|
fn sending_to_sibling_of_bridged_chain_works() {
|
||||||
|
maybe_with_topic(|| {
|
||||||
let msg = Xcm(vec![Trap(1)]);
|
let msg = Xcm(vec![Trap(1)]);
|
||||||
let dest = (Parent, Remote::get(), Parachain(1000)).into();
|
let dest = (Parent, Remote::get(), Parachain(1000)).into();
|
||||||
assert_eq!(send_xcm::<LocalRouter>(dest, msg).unwrap().1, MultiAssets::new());
|
assert_eq!(send_xcm::<LocalRouter>(dest, msg).unwrap().1, MultiAssets::new());
|
||||||
assert_eq!(TheBridge::service(), 1);
|
assert_eq!(TheBridge::service(), 1);
|
||||||
let expected = vec![(
|
let expected = vec![(
|
||||||
(Parent, Parachain(1000)).into(),
|
(Parent, Parachain(1000)).into(),
|
||||||
Xcm(vec![UniversalOrigin(Local::get().into()), Trap(1)]),
|
xcm_with_topic([0; 32], vec![UniversalOrigin(Local::get().into()), Trap(1)]),
|
||||||
)];
|
)];
|
||||||
assert_eq!(take_received_remote_messages(), expected);
|
assert_eq!(take_received_remote_messages(), expected);
|
||||||
|
let entry = LogEntry {
|
||||||
|
local: UniversalLocation::get(),
|
||||||
|
remote: ParaBridgeUniversalLocation::get(),
|
||||||
|
id: maybe_forward_id_for(&[0; 32]),
|
||||||
|
message: xcm_with_topic(
|
||||||
|
maybe_forward_id_for(&[0; 32]),
|
||||||
|
vec![
|
||||||
|
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
|
||||||
|
ExportMessage {
|
||||||
|
network: ByGenesis([1; 32]),
|
||||||
|
destination: Parachain(1000).into(),
|
||||||
|
xcm: xcm_with_topic([0; 32], vec![Trap(1)]),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
outcome: Outcome::Complete(test_weight(2)),
|
||||||
|
paid: false,
|
||||||
|
};
|
||||||
|
assert_eq!(RoutingLog::take(), vec![entry]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ```nocompile
|
/// ```nocompile
|
||||||
@@ -97,10 +140,34 @@ fn sending_to_sibling_of_bridged_chain_works() {
|
|||||||
/// ```
|
/// ```
|
||||||
#[test]
|
#[test]
|
||||||
fn sending_to_relay_of_bridged_chain_works() {
|
fn sending_to_relay_of_bridged_chain_works() {
|
||||||
|
maybe_with_topic(|| {
|
||||||
let msg = Xcm(vec![Trap(1)]);
|
let msg = Xcm(vec![Trap(1)]);
|
||||||
let dest = (Parent, Remote::get()).into();
|
let dest = (Parent, Remote::get()).into();
|
||||||
assert_eq!(send_xcm::<LocalRouter>(dest, msg).unwrap().1, MultiAssets::new());
|
assert_eq!(send_xcm::<LocalRouter>(dest, msg).unwrap().1, MultiAssets::new());
|
||||||
assert_eq!(TheBridge::service(), 1);
|
assert_eq!(TheBridge::service(), 1);
|
||||||
let expected = vec![(Parent.into(), Xcm(vec![UniversalOrigin(Local::get().into()), Trap(1)]))];
|
let expected = vec![(
|
||||||
|
Parent.into(),
|
||||||
|
xcm_with_topic([0; 32], vec![UniversalOrigin(Local::get().into()), Trap(1)]),
|
||||||
|
)];
|
||||||
assert_eq!(take_received_remote_messages(), expected);
|
assert_eq!(take_received_remote_messages(), expected);
|
||||||
|
let entry = LogEntry {
|
||||||
|
local: UniversalLocation::get(),
|
||||||
|
remote: ParaBridgeUniversalLocation::get(),
|
||||||
|
id: maybe_forward_id_for(&[0; 32]),
|
||||||
|
message: xcm_with_topic(
|
||||||
|
maybe_forward_id_for(&[0; 32]),
|
||||||
|
vec![
|
||||||
|
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
|
||||||
|
ExportMessage {
|
||||||
|
network: ByGenesis([1; 32]),
|
||||||
|
destination: Here,
|
||||||
|
xcm: xcm_with_topic([0; 32], vec![Trap(1)]),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
outcome: Outcome::Complete(test_weight(2)),
|
||||||
|
paid: false,
|
||||||
|
};
|
||||||
|
assert_eq!(RoutingLog::take(), vec![entry]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ type LocalInnerRouter =
|
|||||||
UnpaidExecutingRouter<UniversalLocation, RelayUniversalLocation, RelayExporter>;
|
UnpaidExecutingRouter<UniversalLocation, RelayUniversalLocation, RelayExporter>;
|
||||||
type LocalBridgeRouter =
|
type LocalBridgeRouter =
|
||||||
UnpaidRemoteExporter<NetworkExportTable<BridgeTable>, LocalInnerRouter, UniversalLocation>;
|
UnpaidRemoteExporter<NetworkExportTable<BridgeTable>, LocalInnerRouter, UniversalLocation>;
|
||||||
type LocalRouter = (LocalInnerRouter, LocalBridgeRouter);
|
type LocalRouter = TestTopic<(LocalInnerRouter, LocalBridgeRouter)>;
|
||||||
|
|
||||||
/// ```nocompile
|
/// ```nocompile
|
||||||
/// local | remote
|
/// local | remote
|
||||||
@@ -48,6 +48,7 @@ type LocalRouter = (LocalInnerRouter, LocalBridgeRouter);
|
|||||||
/// ```
|
/// ```
|
||||||
#[test]
|
#[test]
|
||||||
fn sending_to_bridged_chain_works() {
|
fn sending_to_bridged_chain_works() {
|
||||||
|
maybe_with_topic(|| {
|
||||||
let msg = Xcm(vec![Trap(1)]);
|
let msg = Xcm(vec![Trap(1)]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
send_xcm::<LocalRouter>((Parent, Parent, Remote::get()).into(), msg).unwrap().1,
|
send_xcm::<LocalRouter>((Parent, Parent, Remote::get()).into(), msg).unwrap().1,
|
||||||
@@ -58,13 +59,36 @@ fn sending_to_bridged_chain_works() {
|
|||||||
take_received_remote_messages(),
|
take_received_remote_messages(),
|
||||||
vec![(
|
vec![(
|
||||||
Here.into(),
|
Here.into(),
|
||||||
Xcm(vec![
|
xcm_with_topic(
|
||||||
|
[0; 32],
|
||||||
|
vec![
|
||||||
UniversalOrigin(Local::get().into()),
|
UniversalOrigin(Local::get().into()),
|
||||||
DescendOrigin(Parachain(1000).into()),
|
DescendOrigin(Parachain(1000).into()),
|
||||||
Trap(1)
|
Trap(1)
|
||||||
])
|
]
|
||||||
|
)
|
||||||
)]
|
)]
|
||||||
);
|
);
|
||||||
|
let entry = LogEntry {
|
||||||
|
local: UniversalLocation::get(),
|
||||||
|
remote: RelayUniversalLocation::get(),
|
||||||
|
id: maybe_forward_id_for(&[0; 32]),
|
||||||
|
message: xcm_with_topic(
|
||||||
|
maybe_forward_id_for(&[0; 32]),
|
||||||
|
vec![
|
||||||
|
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
|
||||||
|
ExportMessage {
|
||||||
|
network: ByGenesis([1; 32]),
|
||||||
|
destination: Here,
|
||||||
|
xcm: xcm_with_topic([0; 32], vec![Trap(1)]),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
outcome: Outcome::Complete(test_weight(2)),
|
||||||
|
paid: false,
|
||||||
|
};
|
||||||
|
assert_eq!(RoutingLog::take(), vec![entry]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ```nocompile
|
/// ```nocompile
|
||||||
@@ -79,17 +103,41 @@ fn sending_to_bridged_chain_works() {
|
|||||||
/// ```
|
/// ```
|
||||||
#[test]
|
#[test]
|
||||||
fn sending_to_parachain_of_bridged_chain_works() {
|
fn sending_to_parachain_of_bridged_chain_works() {
|
||||||
|
maybe_with_topic(|| {
|
||||||
let msg = Xcm(vec![Trap(1)]);
|
let msg = Xcm(vec![Trap(1)]);
|
||||||
let dest = (Parent, Parent, Remote::get(), Parachain(1000)).into();
|
let dest = (Parent, Parent, Remote::get(), Parachain(1000)).into();
|
||||||
assert_eq!(send_xcm::<LocalRouter>(dest, msg).unwrap().1, MultiAssets::new());
|
assert_eq!(send_xcm::<LocalRouter>(dest, msg).unwrap().1, MultiAssets::new());
|
||||||
assert_eq!(TheBridge::service(), 1);
|
assert_eq!(TheBridge::service(), 1);
|
||||||
let expected = vec![(
|
let expected = vec![(
|
||||||
Parachain(1000).into(),
|
Parachain(1000).into(),
|
||||||
Xcm(vec![
|
xcm_with_topic(
|
||||||
|
[0; 32],
|
||||||
|
vec![
|
||||||
UniversalOrigin(Local::get().into()),
|
UniversalOrigin(Local::get().into()),
|
||||||
DescendOrigin(Parachain(1000).into()),
|
DescendOrigin(Parachain(1000).into()),
|
||||||
Trap(1),
|
Trap(1),
|
||||||
]),
|
],
|
||||||
|
),
|
||||||
)];
|
)];
|
||||||
assert_eq!(take_received_remote_messages(), expected);
|
assert_eq!(take_received_remote_messages(), expected);
|
||||||
|
let entry = LogEntry {
|
||||||
|
local: UniversalLocation::get(),
|
||||||
|
remote: RelayUniversalLocation::get(),
|
||||||
|
id: maybe_forward_id_for(&[0; 32]),
|
||||||
|
message: xcm_with_topic(
|
||||||
|
maybe_forward_id_for(&[0; 32]),
|
||||||
|
vec![
|
||||||
|
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
|
||||||
|
ExportMessage {
|
||||||
|
network: ByGenesis([1; 32]),
|
||||||
|
destination: Parachain(1000).into(),
|
||||||
|
xcm: xcm_with_topic([0; 32], vec![Trap(1)]),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
outcome: Outcome::Complete(test_weight(2)),
|
||||||
|
paid: false,
|
||||||
|
};
|
||||||
|
assert_eq!(RoutingLog::take(), vec![entry]);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
barriers::{AllowSubscriptionsFrom, RespectSuspension},
|
barriers::{AllowSubscriptionsFrom, RespectSuspension, TrailingSetTopicAsId},
|
||||||
test_utils::*,
|
test_utils::*,
|
||||||
};
|
};
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
@@ -41,6 +41,7 @@ pub use sp_std::{
|
|||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
};
|
};
|
||||||
pub use xcm::latest::{prelude::*, Weight};
|
pub use xcm::latest::{prelude::*, Weight};
|
||||||
|
use xcm_executor::traits::Properties;
|
||||||
pub use xcm_executor::{
|
pub use xcm_executor::{
|
||||||
traits::{
|
traits::{
|
||||||
AssetExchange, AssetLock, CheckSuspension, ConvertOrigin, Enact, ExportXcm, FeeManager,
|
AssetExchange, AssetLock, CheckSuspension, ConvertOrigin, Enact, ExportXcm, FeeManager,
|
||||||
@@ -241,6 +242,9 @@ pub fn asset_list(who: impl Into<MultiLocation>) -> Vec<MultiAsset> {
|
|||||||
pub fn add_asset(who: impl Into<MultiLocation>, what: impl Into<MultiAsset>) {
|
pub fn add_asset(who: impl Into<MultiLocation>, what: impl Into<MultiAsset>) {
|
||||||
ASSETS.with(|a| a.borrow_mut().entry(who.into()).or_insert(Assets::new()).subsume(what.into()));
|
ASSETS.with(|a| a.borrow_mut().entry(who.into()).or_insert(Assets::new()).subsume(what.into()));
|
||||||
}
|
}
|
||||||
|
pub fn clear_assets(who: impl Into<MultiLocation>) {
|
||||||
|
ASSETS.with(|a| a.borrow_mut().remove(&who.into()));
|
||||||
|
}
|
||||||
|
|
||||||
pub struct TestAssetTransactor;
|
pub struct TestAssetTransactor;
|
||||||
impl TransactAsset for TestAssetTransactor {
|
impl TransactAsset for TestAssetTransactor {
|
||||||
@@ -429,7 +433,7 @@ impl CheckSuspension for TestSuspender {
|
|||||||
_origin: &MultiLocation,
|
_origin: &MultiLocation,
|
||||||
_instructions: &mut [Instruction<Call>],
|
_instructions: &mut [Instruction<Call>],
|
||||||
_max_weight: Weight,
|
_max_weight: Weight,
|
||||||
_weight_credit: &mut Weight,
|
_properties: &mut Properties,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
SUSPENDED.with(|s| s.get())
|
SUSPENDED.with(|s| s.get())
|
||||||
}
|
}
|
||||||
@@ -651,7 +655,7 @@ impl Config for TestConfig {
|
|||||||
type IsReserve = TestIsReserve;
|
type IsReserve = TestIsReserve;
|
||||||
type IsTeleporter = TestIsTeleporter;
|
type IsTeleporter = TestIsTeleporter;
|
||||||
type UniversalLocation = ExecutorUniversalLocation;
|
type UniversalLocation = ExecutorUniversalLocation;
|
||||||
type Barrier = RespectSuspension<TestBarrier, TestSuspender>;
|
type Barrier = TrailingSetTopicAsId<RespectSuspension<TestBarrier, TestSuspender>>;
|
||||||
type Weigher = FixedWeightBounds<UnitWeightCost, TestCall, MaxInstructions>;
|
type Weigher = FixedWeightBounds<UnitWeightCost, TestCall, MaxInstructions>;
|
||||||
type Trader = FixedRateOfFungible<WeightPrice, ()>;
|
type Trader = FixedRateOfFungible<WeightPrice, ()>;
|
||||||
type ResponseHandler = TestResponseHandler;
|
type ResponseHandler = TestResponseHandler;
|
||||||
|
|||||||
@@ -130,6 +130,10 @@ impl<T: Get<Vec<(NetworkId, MultiLocation, Option<MultiAsset>)>>> ExporterFor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn forward_id_for(original_id: &XcmHash) -> XcmHash {
|
||||||
|
(b"forward_id_for", original_id).using_encoded(sp_io::hashing::blake2_256)
|
||||||
|
}
|
||||||
|
|
||||||
/// Implementation of `SendXcm` which wraps the message inside an `ExportMessage` instruction
|
/// Implementation of `SendXcm` which wraps the message inside an `ExportMessage` instruction
|
||||||
/// and sends it to a destination known to be able to handle it.
|
/// and sends it to a destination known to be able to handle it.
|
||||||
///
|
///
|
||||||
@@ -139,6 +143,16 @@ impl<T: Get<Vec<(NetworkId, MultiLocation, Option<MultiAsset>)>>> ExporterFor
|
|||||||
///
|
///
|
||||||
/// This is only useful if we have special dispensation by the remote bridges to have the
|
/// This is only useful if we have special dispensation by the remote bridges to have the
|
||||||
/// `ExportMessage` instruction executed without payment.
|
/// `ExportMessage` instruction executed without payment.
|
||||||
|
///
|
||||||
|
/// The `XcmHash` value returned by `deliver` will always be the same as that returned by the
|
||||||
|
/// message exporter (`Bridges`). Generally this should take notice of the message should it
|
||||||
|
/// end with the `SetTopic` instruction.
|
||||||
|
///
|
||||||
|
/// In the case that the message ends with a `SetTopic(T)` (as should be the case if the top-level
|
||||||
|
/// router is `EnsureUniqueTopic`), then the forwarding message (i.e. the one carrying the
|
||||||
|
/// export instruction *to* the bridge in local consensus) will also end with a `SetTopic` whose
|
||||||
|
/// inner is `forward_id_for(T)`. If this is not the case then the onward message will not be given
|
||||||
|
/// the `SetTopic` afterword.
|
||||||
pub struct UnpaidRemoteExporter<Bridges, Router, UniversalLocation>(
|
pub struct UnpaidRemoteExporter<Bridges, Router, UniversalLocation>(
|
||||||
PhantomData<(Bridges, Router, UniversalLocation)>,
|
PhantomData<(Bridges, Router, UniversalLocation)>,
|
||||||
);
|
);
|
||||||
@@ -155,21 +169,32 @@ impl<Bridges: ExporterFor, Router: SendXcm, UniversalLocation: Get<InteriorMulti
|
|||||||
let devolved = ensure_is_remote(UniversalLocation::get(), d).map_err(|_| NotApplicable)?;
|
let devolved = ensure_is_remote(UniversalLocation::get(), d).map_err(|_| NotApplicable)?;
|
||||||
let (remote_network, remote_location) = devolved;
|
let (remote_network, remote_location) = devolved;
|
||||||
let xcm = xcm.take().ok_or(MissingArgument)?;
|
let xcm = xcm.take().ok_or(MissingArgument)?;
|
||||||
|
|
||||||
let (bridge, maybe_payment) =
|
let (bridge, maybe_payment) =
|
||||||
Bridges::exporter_for(&remote_network, &remote_location, &xcm).ok_or(NotApplicable)?;
|
Bridges::exporter_for(&remote_network, &remote_location, &xcm).ok_or(NotApplicable)?;
|
||||||
ensure!(maybe_payment.is_none(), Unroutable);
|
ensure!(maybe_payment.is_none(), Unroutable);
|
||||||
|
|
||||||
|
// `xcm` should already end with `SetTopic` - if it does, then extract and derive into
|
||||||
|
// an onward topic ID.
|
||||||
|
let maybe_forward_id = match xcm.last() {
|
||||||
|
Some(SetTopic(t)) => Some(forward_id_for(t)),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
// We then send a normal message to the bridge asking it to export the prepended
|
// We then send a normal message to the bridge asking it to export the prepended
|
||||||
// message to the remote chain. This will only work if the bridge will do the message
|
// message to the remote chain. This will only work if the bridge will do the message
|
||||||
// export for free. Common-good chains will typically be afforded this.
|
// export for free. Common-good chains will typically be afforded this.
|
||||||
let message = Xcm(vec![
|
let mut message = Xcm(vec![
|
||||||
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
|
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
|
||||||
ExportMessage { network: remote_network, destination: remote_location, xcm },
|
ExportMessage { network: remote_network, destination: remote_location, xcm },
|
||||||
]);
|
]);
|
||||||
|
if let Some(forward_id) = maybe_forward_id {
|
||||||
|
message.0.push(SetTopic(forward_id));
|
||||||
|
}
|
||||||
validate_send::<Router>(bridge, message)
|
validate_send::<Router>(bridge, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deliver(validation: Router::Ticket) -> Result<XcmHash, SendError> {
|
fn deliver(validation: Self::Ticket) -> Result<XcmHash, SendError> {
|
||||||
Router::deliver(validation)
|
Router::deliver(validation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,6 +204,16 @@ impl<Bridges: ExporterFor, Router: SendXcm, UniversalLocation: Get<InteriorMulti
|
|||||||
///
|
///
|
||||||
/// The `ExportMessage` instruction on the bridge is paid for from the local chain's sovereign
|
/// The `ExportMessage` instruction on the bridge is paid for from the local chain's sovereign
|
||||||
/// account on the bridge. The amount paid is determined through the `ExporterFor` trait.
|
/// account on the bridge. The amount paid is determined through the `ExporterFor` trait.
|
||||||
|
///
|
||||||
|
/// The `XcmHash` value returned by `deliver` will always be the same as that returned by the
|
||||||
|
/// message exporter (`Bridges`). Generally this should take notice of the message should it
|
||||||
|
/// end with the `SetTopic` instruction.
|
||||||
|
///
|
||||||
|
/// In the case that the message ends with a `SetTopic(T)` (as should be the case if the top-level
|
||||||
|
/// router is `EnsureUniqueTopic`), then the forwarding message (i.e. the one carrying the
|
||||||
|
/// export instruction *to* the bridge in local consensus) will also end with a `SetTopic` whose
|
||||||
|
/// inner is `forward_id_for(T)`. If this is not the case then the onward message will not be given
|
||||||
|
/// the `SetTopic` afterword.
|
||||||
pub struct SovereignPaidRemoteExporter<Bridges, Router, UniversalLocation>(
|
pub struct SovereignPaidRemoteExporter<Bridges, Router, UniversalLocation>(
|
||||||
PhantomData<(Bridges, Router, UniversalLocation)>,
|
PhantomData<(Bridges, Router, UniversalLocation)>,
|
||||||
);
|
);
|
||||||
@@ -196,6 +231,14 @@ impl<Bridges: ExporterFor, Router: SendXcm, UniversalLocation: Get<InteriorMulti
|
|||||||
let (remote_network, remote_location) = devolved;
|
let (remote_network, remote_location) = devolved;
|
||||||
|
|
||||||
let xcm = xcm.take().ok_or(MissingArgument)?;
|
let xcm = xcm.take().ok_or(MissingArgument)?;
|
||||||
|
|
||||||
|
// `xcm` should already end with `SetTopic` - if it does, then extract and derive into
|
||||||
|
// an onward topic ID.
|
||||||
|
let maybe_forward_id = match xcm.last() {
|
||||||
|
Some(SetTopic(t)) => Some(forward_id_for(t)),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
let (bridge, maybe_payment) =
|
let (bridge, maybe_payment) =
|
||||||
Bridges::exporter_for(&remote_network, &remote_location, &xcm).ok_or(NotApplicable)?;
|
Bridges::exporter_for(&remote_network, &remote_location, &xcm).ok_or(NotApplicable)?;
|
||||||
|
|
||||||
@@ -204,7 +247,7 @@ impl<Bridges: ExporterFor, Router: SendXcm, UniversalLocation: Get<InteriorMulti
|
|||||||
let export_instruction =
|
let export_instruction =
|
||||||
ExportMessage { network: remote_network, destination: remote_location, xcm };
|
ExportMessage { network: remote_network, destination: remote_location, xcm };
|
||||||
|
|
||||||
let message = Xcm(if let Some(ref payment) = maybe_payment {
|
let mut message = Xcm(if let Some(ref payment) = maybe_payment {
|
||||||
let fees = payment
|
let fees = payment
|
||||||
.clone()
|
.clone()
|
||||||
.reanchored(&bridge, UniversalLocation::get())
|
.reanchored(&bridge, UniversalLocation::get())
|
||||||
@@ -219,6 +262,9 @@ impl<Bridges: ExporterFor, Router: SendXcm, UniversalLocation: Get<InteriorMulti
|
|||||||
} else {
|
} else {
|
||||||
vec![export_instruction]
|
vec![export_instruction]
|
||||||
});
|
});
|
||||||
|
if let Some(forward_id) = maybe_forward_id {
|
||||||
|
message.0.push(SetTopic(forward_id));
|
||||||
|
}
|
||||||
|
|
||||||
// We then send a normal message to the bridge asking it to export the prepended
|
// We then send a normal message to the bridge asking it to export the prepended
|
||||||
// message to the remote chain.
|
// message to the remote chain.
|
||||||
@@ -344,22 +390,24 @@ impl<Bridge: HaulBlob, BridgedNetwork: Get<NetworkId>, Price: Get<MultiAssets>>
|
|||||||
.ok_or(SendError::MissingArgument)?
|
.ok_or(SendError::MissingArgument)?
|
||||||
.split_global()
|
.split_global()
|
||||||
.map_err(|()| SendError::Unroutable)?;
|
.map_err(|()| SendError::Unroutable)?;
|
||||||
let mut inner: Xcm<()> = vec![UniversalOrigin(GlobalConsensus(local_net))].into();
|
let mut message = message.take().ok_or(SendError::MissingArgument)?;
|
||||||
|
let maybe_id = match message.last() {
|
||||||
|
Some(SetTopic(t)) => Some(*t),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
message.0.insert(0, UniversalOrigin(GlobalConsensus(local_net)));
|
||||||
if local_sub != Here {
|
if local_sub != Here {
|
||||||
inner.inner_mut().push(DescendOrigin(local_sub));
|
message.0.insert(1, DescendOrigin(local_sub));
|
||||||
}
|
}
|
||||||
inner
|
let message = VersionedXcm::from(message);
|
||||||
.inner_mut()
|
let id = maybe_id.unwrap_or_else(|| message.using_encoded(sp_io::hashing::blake2_256));
|
||||||
.extend(message.take().ok_or(SendError::MissingArgument)?.into_iter());
|
|
||||||
let message = VersionedXcm::from(inner);
|
|
||||||
let hash = message.using_encoded(sp_io::hashing::blake2_256);
|
|
||||||
let blob = BridgeMessage { universal_dest, message }.encode();
|
let blob = BridgeMessage { universal_dest, message }.encode();
|
||||||
Ok(((blob, hash), Price::get()))
|
Ok(((blob, id), Price::get()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deliver((blob, hash): (Vec<u8>, XcmHash)) -> Result<XcmHash, SendError> {
|
fn deliver((blob, id): (Vec<u8>, XcmHash)) -> Result<XcmHash, SendError> {
|
||||||
Bridge::haul_blob(blob)?;
|
Bridge::haul_blob(blob)?;
|
||||||
Ok(hash)
|
Ok(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
mod mock;
|
mod mock;
|
||||||
|
|
||||||
use frame_support::weights::Weight;
|
|
||||||
use mock::{
|
use mock::{
|
||||||
fake_message_hash, kusama_like_with_balances, AccountId, Balance, Balances, BaseXcmWeight,
|
fake_message_hash, kusama_like_with_balances, AccountId, Balance, Balances, BaseXcmWeight,
|
||||||
System, XcmConfig, CENTS,
|
System, XcmConfig, CENTS,
|
||||||
|
|||||||
@@ -65,9 +65,9 @@ fn basic_buy_fees_message_executes() {
|
|||||||
client.state_at(block_hash).expect("state should exist").inspect_state(|| {
|
client.state_at(block_hash).expect("state should exist").inspect_state(|| {
|
||||||
assert!(polkadot_test_runtime::System::events().iter().any(|r| matches!(
|
assert!(polkadot_test_runtime::System::events().iter().any(|r| matches!(
|
||||||
r.event,
|
r.event,
|
||||||
polkadot_test_runtime::RuntimeEvent::Xcm(pallet_xcm::Event::Attempted(
|
polkadot_test_runtime::RuntimeEvent::Xcm(pallet_xcm::Event::Attempted {
|
||||||
Outcome::Complete(_)
|
outcome: Outcome::Complete(_)
|
||||||
)),
|
}),
|
||||||
)));
|
)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -118,9 +118,9 @@ fn transact_recursion_limit_works() {
|
|||||||
client.state_at(block_hash).expect("state should exist").inspect_state(|| {
|
client.state_at(block_hash).expect("state should exist").inspect_state(|| {
|
||||||
assert!(polkadot_test_runtime::System::events().iter().any(|r| matches!(
|
assert!(polkadot_test_runtime::System::events().iter().any(|r| matches!(
|
||||||
r.event,
|
r.event,
|
||||||
polkadot_test_runtime::RuntimeEvent::Xcm(pallet_xcm::Event::Attempted(
|
polkadot_test_runtime::RuntimeEvent::Xcm(pallet_xcm::Event::Attempted {
|
||||||
Outcome::Incomplete(_, XcmError::ExceedsStackLimit)
|
outcome: Outcome::Incomplete(_, XcmError::ExceedsStackLimit)
|
||||||
)),
|
}),
|
||||||
)));
|
)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -195,10 +195,10 @@ fn query_response_fires() {
|
|||||||
client.state_at(block_hash).expect("state should exist").inspect_state(|| {
|
client.state_at(block_hash).expect("state should exist").inspect_state(|| {
|
||||||
assert!(polkadot_test_runtime::System::events().iter().any(|r| matches!(
|
assert!(polkadot_test_runtime::System::events().iter().any(|r| matches!(
|
||||||
r.event,
|
r.event,
|
||||||
polkadot_test_runtime::RuntimeEvent::Xcm(pallet_xcm::Event::ResponseReady(
|
polkadot_test_runtime::RuntimeEvent::Xcm(pallet_xcm::Event::ResponseReady {
|
||||||
q,
|
query_id: q,
|
||||||
Response::ExecutionResult(None),
|
response: Response::ExecutionResult(None),
|
||||||
)) if q == query_id,
|
}) if q == query_id,
|
||||||
)));
|
)));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
polkadot_test_runtime::Xcm::query(query_id),
|
polkadot_test_runtime::Xcm::query(query_id),
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ use xcm::latest::prelude::*;
|
|||||||
pub mod traits;
|
pub mod traits;
|
||||||
use traits::{
|
use traits::{
|
||||||
validate_export, AssetExchange, AssetLock, CallDispatcher, ClaimAssets, ConvertOrigin,
|
validate_export, AssetExchange, AssetLock, CallDispatcher, ClaimAssets, ConvertOrigin,
|
||||||
DropAssets, Enact, ExportXcm, FeeManager, FeeReason, OnResponse, ShouldExecute, TransactAsset,
|
DropAssets, Enact, ExportXcm, FeeManager, FeeReason, OnResponse, Properties, ShouldExecute,
|
||||||
VersionChangeNotifier, WeightBounds, WeightTrader,
|
TransactAsset, VersionChangeNotifier, WeightBounds, WeightTrader,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod assets;
|
mod assets;
|
||||||
@@ -193,8 +193,8 @@ impl<Config: config::Config> ExecuteXcm<Config::RuntimeCall> for XcmExecutor<Con
|
|||||||
fn execute(
|
fn execute(
|
||||||
origin: impl Into<MultiLocation>,
|
origin: impl Into<MultiLocation>,
|
||||||
WeighedMessage(xcm_weight, mut message): WeighedMessage<Config::RuntimeCall>,
|
WeighedMessage(xcm_weight, mut message): WeighedMessage<Config::RuntimeCall>,
|
||||||
message_hash: XcmHash,
|
id: &mut XcmHash,
|
||||||
mut weight_credit: Weight,
|
weight_credit: Weight,
|
||||||
) -> Outcome {
|
) -> Outcome {
|
||||||
let origin = origin.into();
|
let origin = origin.into();
|
||||||
log::trace!(
|
log::trace!(
|
||||||
@@ -204,24 +204,27 @@ impl<Config: config::Config> ExecuteXcm<Config::RuntimeCall> for XcmExecutor<Con
|
|||||||
message,
|
message,
|
||||||
weight_credit,
|
weight_credit,
|
||||||
);
|
);
|
||||||
|
let mut properties = Properties { weight_credit, message_id: None };
|
||||||
if let Err(e) = Config::Barrier::should_execute(
|
if let Err(e) = Config::Barrier::should_execute(
|
||||||
&origin,
|
&origin,
|
||||||
message.inner_mut(),
|
message.inner_mut(),
|
||||||
xcm_weight,
|
xcm_weight,
|
||||||
&mut weight_credit,
|
&mut properties,
|
||||||
) {
|
) {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
target: "xcm::execute_xcm_in_credit",
|
target: "xcm::execute_xcm_in_credit",
|
||||||
"Barrier blocked execution! Error: {:?}. (origin: {:?}, message: {:?}, weight_credit: {:?})",
|
"Barrier blocked execution! Error: {:?}. (origin: {:?}, message: {:?}, properties: {:?})",
|
||||||
e,
|
e,
|
||||||
origin,
|
origin,
|
||||||
message,
|
message,
|
||||||
weight_credit,
|
properties,
|
||||||
);
|
);
|
||||||
return Outcome::Error(XcmError::Barrier)
|
return Outcome::Error(XcmError::Barrier)
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut vm = Self::new(origin, message_hash);
|
*id = properties.message_id.unwrap_or(*id);
|
||||||
|
|
||||||
|
let mut vm = Self::new(origin, *id);
|
||||||
|
|
||||||
while !message.0.is_empty() {
|
while !message.0.is_empty() {
|
||||||
let result = vm.process(message);
|
let result = vm.process(message);
|
||||||
@@ -272,12 +275,12 @@ impl From<ExecutorError> for frame_benchmarking::BenchmarkError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<Config: config::Config> XcmExecutor<Config> {
|
impl<Config: config::Config> XcmExecutor<Config> {
|
||||||
pub fn new(origin: impl Into<MultiLocation>, message_hash: XcmHash) -> Self {
|
pub fn new(origin: impl Into<MultiLocation>, message_id: XcmHash) -> Self {
|
||||||
let origin = origin.into();
|
let origin = origin.into();
|
||||||
Self {
|
Self {
|
||||||
holding: Assets::new(),
|
holding: Assets::new(),
|
||||||
holding_limit: Config::MaxAssetsIntoHolding::get() as usize,
|
holding_limit: Config::MaxAssetsIntoHolding::get() as usize,
|
||||||
context: XcmContext { origin: Some(origin), message_hash, topic: None },
|
context: XcmContext { origin: Some(origin), message_id, topic: None },
|
||||||
original_origin: origin,
|
original_origin: origin,
|
||||||
trader: Config::Trader::new(),
|
trader: Config::Trader::new(),
|
||||||
error: None,
|
error: None,
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ pub use token_matching::{
|
|||||||
mod on_response;
|
mod on_response;
|
||||||
pub use on_response::{OnResponse, VersionChangeNotifier};
|
pub use on_response::{OnResponse, VersionChangeNotifier};
|
||||||
mod should_execute;
|
mod should_execute;
|
||||||
pub use should_execute::{CheckSuspension, ShouldExecute};
|
pub use should_execute::{CheckSuspension, Properties, ShouldExecute};
|
||||||
mod transact_asset;
|
mod transact_asset;
|
||||||
pub use transact_asset::TransactAsset;
|
pub use transact_asset::TransactAsset;
|
||||||
mod weight;
|
mod weight;
|
||||||
|
|||||||
@@ -16,7 +16,19 @@
|
|||||||
|
|
||||||
use frame_support::traits::ProcessMessageError;
|
use frame_support::traits::ProcessMessageError;
|
||||||
use sp_std::result::Result;
|
use sp_std::result::Result;
|
||||||
use xcm::latest::{Instruction, MultiLocation, Weight};
|
use xcm::latest::{Instruction, MultiLocation, Weight, XcmHash};
|
||||||
|
|
||||||
|
/// Properyies of an XCM message and its imminent execution.
|
||||||
|
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||||
|
pub struct Properties {
|
||||||
|
/// The amount of weight that the system has determined this
|
||||||
|
/// message may utilize in its execution. Typically non-zero only because of prior fee
|
||||||
|
/// payment, but could in principle be due to other factors.
|
||||||
|
pub weight_credit: Weight,
|
||||||
|
/// The identity of the message, if one is known. If left as `None`, then it will generally
|
||||||
|
/// default to the hash of the message which may be non-unique.
|
||||||
|
pub message_id: Option<XcmHash>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Trait to determine whether the execution engine should actually execute a given XCM.
|
/// Trait to determine whether the execution engine should actually execute a given XCM.
|
||||||
///
|
///
|
||||||
@@ -28,14 +40,13 @@ pub trait ShouldExecute {
|
|||||||
/// - `origin`: The origin (sender) of the message.
|
/// - `origin`: The origin (sender) of the message.
|
||||||
/// - `instructions`: The message itself.
|
/// - `instructions`: The message itself.
|
||||||
/// - `max_weight`: The (possibly over-) estimation of the weight of execution of the message.
|
/// - `max_weight`: The (possibly over-) estimation of the weight of execution of the message.
|
||||||
/// - `weight_credit`: The pre-established amount of weight that the system has determined this
|
/// - `properties`: Various pre-established properties of the message which may be mutated by
|
||||||
/// message may utilize in its execution. Typically non-zero only because of prior fee
|
/// this API.
|
||||||
/// payment, but could in principle be due to other factors.
|
|
||||||
fn should_execute<RuntimeCall>(
|
fn should_execute<RuntimeCall>(
|
||||||
origin: &MultiLocation,
|
origin: &MultiLocation,
|
||||||
instructions: &mut [Instruction<RuntimeCall>],
|
instructions: &mut [Instruction<RuntimeCall>],
|
||||||
max_weight: Weight,
|
max_weight: Weight,
|
||||||
weight_credit: &mut Weight,
|
properties: &mut Properties,
|
||||||
) -> Result<(), ProcessMessageError>;
|
) -> Result<(), ProcessMessageError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,21 +56,21 @@ impl ShouldExecute for Tuple {
|
|||||||
origin: &MultiLocation,
|
origin: &MultiLocation,
|
||||||
instructions: &mut [Instruction<RuntimeCall>],
|
instructions: &mut [Instruction<RuntimeCall>],
|
||||||
max_weight: Weight,
|
max_weight: Weight,
|
||||||
weight_credit: &mut Weight,
|
properties: &mut Properties,
|
||||||
) -> Result<(), ProcessMessageError> {
|
) -> Result<(), ProcessMessageError> {
|
||||||
for_tuples!( #(
|
for_tuples!( #(
|
||||||
match Tuple::should_execute(origin, instructions, max_weight, weight_credit) {
|
match Tuple::should_execute(origin, instructions, max_weight, properties) {
|
||||||
Ok(()) => return Ok(()),
|
Ok(()) => return Ok(()),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
)* );
|
)* );
|
||||||
log::trace!(
|
log::trace!(
|
||||||
target: "xcm::should_execute",
|
target: "xcm::should_execute",
|
||||||
"did not pass barrier: origin: {:?}, instructions: {:?}, max_weight: {:?}, weight_credit: {:?}",
|
"did not pass barrier: origin: {:?}, instructions: {:?}, max_weight: {:?}, properties: {:?}",
|
||||||
origin,
|
origin,
|
||||||
instructions,
|
instructions,
|
||||||
max_weight,
|
max_weight,
|
||||||
weight_credit,
|
properties,
|
||||||
);
|
);
|
||||||
Err(ProcessMessageError::Unsupported)
|
Err(ProcessMessageError::Unsupported)
|
||||||
}
|
}
|
||||||
@@ -79,7 +90,7 @@ pub trait CheckSuspension {
|
|||||||
origin: &MultiLocation,
|
origin: &MultiLocation,
|
||||||
instructions: &mut [Instruction<Call>],
|
instructions: &mut [Instruction<Call>],
|
||||||
max_weight: Weight,
|
max_weight: Weight,
|
||||||
weight_credit: &mut Weight,
|
properties: &mut Properties,
|
||||||
) -> bool;
|
) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,10 +100,10 @@ impl CheckSuspension for Tuple {
|
|||||||
origin: &MultiLocation,
|
origin: &MultiLocation,
|
||||||
instruction: &mut [Instruction<Call>],
|
instruction: &mut [Instruction<Call>],
|
||||||
max_weight: Weight,
|
max_weight: Weight,
|
||||||
weight_credit: &mut Weight,
|
properties: &mut Properties,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
for_tuples!( #(
|
for_tuples!( #(
|
||||||
if Tuple::is_suspended(origin, instruction, max_weight, weight_credit) {
|
if Tuple::is_suspended(origin, instruction, max_weight, properties) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
)* );
|
)* );
|
||||||
|
|||||||
@@ -397,7 +397,7 @@ mod tests {
|
|||||||
MultiTransactor::deposit_asset(
|
MultiTransactor::deposit_asset(
|
||||||
&(Here, 1u128).into(),
|
&(Here, 1u128).into(),
|
||||||
&Here.into(),
|
&Here.into(),
|
||||||
&XcmContext::with_message_hash([0; 32]),
|
&XcmContext::with_message_id([0; 32]),
|
||||||
),
|
),
|
||||||
Err(XcmError::AssetNotFound)
|
Err(XcmError::AssetNotFound)
|
||||||
);
|
);
|
||||||
@@ -411,7 +411,7 @@ mod tests {
|
|||||||
MultiTransactor::deposit_asset(
|
MultiTransactor::deposit_asset(
|
||||||
&(Here, 1u128).into(),
|
&(Here, 1u128).into(),
|
||||||
&Here.into(),
|
&Here.into(),
|
||||||
&XcmContext::with_message_hash([0; 32]),
|
&XcmContext::with_message_id([0; 32]),
|
||||||
),
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
@@ -425,7 +425,7 @@ mod tests {
|
|||||||
MultiTransactor::deposit_asset(
|
MultiTransactor::deposit_asset(
|
||||||
&(Here, 1u128).into(),
|
&(Here, 1u128).into(),
|
||||||
&Here.into(),
|
&Here.into(),
|
||||||
&XcmContext::with_message_hash([0; 32]),
|
&XcmContext::with_message_id([0; 32]),
|
||||||
),
|
),
|
||||||
Err(XcmError::Overflow)
|
Err(XcmError::Overflow)
|
||||||
);
|
);
|
||||||
@@ -439,7 +439,7 @@ mod tests {
|
|||||||
MultiTransactor::deposit_asset(
|
MultiTransactor::deposit_asset(
|
||||||
&(Here, 1u128).into(),
|
&(Here, 1u128).into(),
|
||||||
&Here.into(),
|
&Here.into(),
|
||||||
&XcmContext::with_message_hash([0; 32]),
|
&XcmContext::with_message_id([0; 32]),
|
||||||
),
|
),
|
||||||
Ok(()),
|
Ok(()),
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user