Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit b7a42f7

Browse files
franciscoaguirretonyalaribemuharemgavofyork
authored
XCM: PayOverXcm config (#6900)
* Move XCM query functionality to trait * Fix tests * Add PayOverXcm implementation * fix the PayOverXcm trait to compile * moved doc comment out of trait implmeentation and to the trait * PayOverXCM documentation * Change documentation a bit * Added empty benchmark methods implementation and changed docs * update PayOverXCM to convert AccountIds to MultiLocations * Implement benchmarking method * Change v3 to latest * Descend origin to an asset sender (#6970) * descend origin to an asset sender * sender as tuple of dest and sender * Add more variants to the QueryResponseStatus enum * Change Beneficiary to Into<[u8; 32]> * update PayOverXcm to return concrete errors and use AccountId as sender * use polkadot-primitives for AccountId * fix dependency to use polkadot-core-primitives * force Unpaid instruction to the top of the instructions list * modify report_outcome to accept interior argument * use new_query directly for building final xcm query, instead of report_outcome * fix usage of new_query to use the XcmQueryHandler * fix usage of new_query to use the XcmQueryHandler * tiny method calling fix * xcm query handler (#7198) * drop redundant query status * rename ReportQueryStatus to OuterQueryStatus * revert rename of QueryResponseStatus * update mapping * Update xcm/xcm-builder/src/pay.rs Co-authored-by: Gavin Wood <gavin@parity.io> * Updates * Docs * Fix benchmarking stuff * Destination can be determined based on asset_kind * Tweaking API to minimise clones * Some repotting and docs --------- Co-authored-by: Anthony Alaribe <anthonyalaribe@gmail.com> Co-authored-by: Muharem Ismailov <ismailov.m.h@gmail.com> Co-authored-by: Anthony Alaribe <anthony.alaribe@parity.io> Co-authored-by: Gavin Wood <gavin@parity.io>
1 parent ba1f654 commit b7a42f7

File tree

10 files changed

+375
-65
lines changed

10 files changed

+375
-65
lines changed

runtime/test-runtime/src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,7 @@ pub mod pallet_test_notifier {
546546
use pallet_xcm::ensure_response;
547547
use sp_runtime::DispatchResult;
548548
use xcm::latest::prelude::*;
549+
use xcm_executor::traits::QueryHandler as XcmQueryHandler;
549550

550551
#[pallet::pallet]
551552
pub struct Pallet<T>(_);
@@ -581,7 +582,7 @@ pub mod pallet_test_notifier {
581582
let id = who
582583
.using_encoded(|mut d| <[u8; 32]>::decode(&mut d))
583584
.map_err(|_| Error::<T>::BadAccountFormat)?;
584-
let qid = pallet_xcm::Pallet::<T>::new_query(
585+
let qid = <pallet_xcm::Pallet<T> as XcmQueryHandler>::new_query(
585586
Junction::AccountId32 { network: None, id },
586587
100u32.into(),
587588
Here,

xcm/pallet-xcm/src/lib.rs

+62-55
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ use frame_system::pallet_prelude::*;
5252
pub use pallet::*;
5353
use xcm_executor::{
5454
traits::{
55-
CheckSuspension, ClaimAssets, DropAssets, MatchesFungible, OnResponse,
56-
VersionChangeNotifier, WeightBounds,
55+
CheckSuspension, ClaimAssets, DropAssets, MatchesFungible, OnResponse, QueryHandler,
56+
QueryResponseStatus, VersionChangeNotifier, WeightBounds,
5757
},
5858
Assets,
5959
};
@@ -1126,6 +1126,66 @@ pub mod pallet {
11261126
/// The maximum number of distinct assets allowed to be transferred in a single helper extrinsic.
11271127
const MAX_ASSETS_FOR_TRANSFER: usize = 2;
11281128

1129+
impl<T: Config> QueryHandler for Pallet<T> {
1130+
type QueryId = u64;
1131+
type BlockNumber = T::BlockNumber;
1132+
type Error = XcmError;
1133+
type UniversalLocation = T::UniversalLocation;
1134+
1135+
/// Attempt to create a new query ID and register it as a query that is yet to respond.
1136+
fn new_query(
1137+
responder: impl Into<MultiLocation>,
1138+
timeout: T::BlockNumber,
1139+
match_querier: impl Into<MultiLocation>,
1140+
) -> Self::QueryId {
1141+
Self::do_new_query(responder, None, timeout, match_querier).into()
1142+
}
1143+
1144+
/// To check the status of the query, use `fn query()` passing the resultant `QueryId`
1145+
/// value.
1146+
fn report_outcome(
1147+
message: &mut Xcm<()>,
1148+
responder: impl Into<MultiLocation>,
1149+
timeout: Self::BlockNumber,
1150+
) -> Result<Self::QueryId, Self::Error> {
1151+
let responder = responder.into();
1152+
let destination = Self::UniversalLocation::get()
1153+
.invert_target(&responder)
1154+
.map_err(|()| XcmError::LocationNotInvertible)?;
1155+
let query_id = Self::new_query(responder, timeout, Here);
1156+
let response_info = QueryResponseInfo { destination, query_id, max_weight: Weight::zero() };
1157+
let report_error = Xcm(vec![ReportError(response_info)]);
1158+
message.0.insert(0, SetAppendix(report_error));
1159+
Ok(query_id)
1160+
}
1161+
1162+
/// Removes response when ready and emits [Event::ResponseTaken] event.
1163+
fn take_response(query_id: Self::QueryId) -> QueryResponseStatus<Self::BlockNumber> {
1164+
match Queries::<T>::get(query_id) {
1165+
Some(QueryStatus::Ready { response, at }) => match response.try_into() {
1166+
Ok(response) => {
1167+
Queries::<T>::remove(query_id);
1168+
Self::deposit_event(Event::ResponseTaken { query_id });
1169+
QueryResponseStatus::Ready { response, at }
1170+
},
1171+
Err(_) => QueryResponseStatus::UnexpectedVersion,
1172+
},
1173+
Some(QueryStatus::Pending { timeout, .. }) => QueryResponseStatus::Pending { timeout },
1174+
Some(_) => QueryResponseStatus::UnexpectedVersion,
1175+
None => QueryResponseStatus::NotFound,
1176+
}
1177+
}
1178+
1179+
#[cfg(feature = "runtime-benchmarks")]
1180+
fn expect_response(id: Self::QueryId, response: Response) {
1181+
let response = response.into();
1182+
Queries::<T>::insert(
1183+
id,
1184+
QueryStatus::Ready { response, at: frame_system::Pallet::<T>::block_number() },
1185+
);
1186+
}
1187+
}
1188+
11291189
impl<T: Config> Pallet<T> {
11301190
fn do_reserve_transfer_assets(
11311191
origin: OriginFor<T>,
@@ -1497,36 +1557,6 @@ impl<T: Config> Pallet<T> {
14971557
})
14981558
}
14991559

1500-
/// Consume `message` and return another which is equivalent to it except that it reports
1501-
/// back the outcome.
1502-
///
1503-
/// - `message`: The message whose outcome should be reported.
1504-
/// - `responder`: The origin from which a response should be expected.
1505-
/// - `timeout`: The block number after which it is permissible for `notify` not to be
1506-
/// called even if a response is received.
1507-
///
1508-
/// `report_outcome` may return an error if the `responder` is not invertible.
1509-
///
1510-
/// It is assumed that the querier of the response will be `Here`.
1511-
///
1512-
/// To check the status of the query, use `fn query()` passing the resultant `QueryId`
1513-
/// value.
1514-
pub fn report_outcome(
1515-
message: &mut Xcm<()>,
1516-
responder: impl Into<MultiLocation>,
1517-
timeout: T::BlockNumber,
1518-
) -> Result<QueryId, XcmError> {
1519-
let responder = responder.into();
1520-
let destination = T::UniversalLocation::get()
1521-
.invert_target(&responder)
1522-
.map_err(|()| XcmError::LocationNotInvertible)?;
1523-
let query_id = Self::new_query(responder, timeout, Here);
1524-
let response_info = QueryResponseInfo { destination, query_id, max_weight: Weight::zero() };
1525-
let report_error = Xcm(vec![ReportError(response_info)]);
1526-
message.0.insert(0, SetAppendix(report_error));
1527-
Ok(query_id)
1528-
}
1529-
15301560
/// Consume `message` and return another which is equivalent to it except that it reports
15311561
/// back the outcome and dispatches `notify` on this chain.
15321562
///
@@ -1568,15 +1598,6 @@ impl<T: Config> Pallet<T> {
15681598
Ok(())
15691599
}
15701600

1571-
/// Attempt to create a new query ID and register it as a query that is yet to respond.
1572-
pub fn new_query(
1573-
responder: impl Into<MultiLocation>,
1574-
timeout: T::BlockNumber,
1575-
match_querier: impl Into<MultiLocation>,
1576-
) -> u64 {
1577-
Self::do_new_query(responder, None, timeout, match_querier)
1578-
}
1579-
15801601
/// Attempt to create a new query ID and register it as a query that is yet to respond, and
15811602
/// which will call a dispatchable when a response happens.
15821603
pub fn new_notify_query(
@@ -1591,20 +1612,6 @@ impl<T: Config> Pallet<T> {
15911612
Self::do_new_query(responder, Some(notify), timeout, match_querier)
15921613
}
15931614

1594-
/// Attempt to remove and return the response of query with ID `query_id`.
1595-
///
1596-
/// Returns `None` if the response is not (yet) available.
1597-
pub fn take_response(query_id: QueryId) -> Option<(Response, T::BlockNumber)> {
1598-
if let Some(QueryStatus::Ready { response, at }) = Queries::<T>::get(query_id) {
1599-
let response = response.try_into().ok()?;
1600-
Queries::<T>::remove(query_id);
1601-
Self::deposit_event(Event::ResponseTaken { query_id });
1602-
Some((response, at))
1603-
} else {
1604-
None
1605-
}
1606-
}
1607-
16081615
/// Note that a particular destination to whom we would like to send a message is unknown
16091616
/// and queue it for version discovery.
16101617
fn note_unknown_version(dest: &MultiLocation) {

xcm/pallet-xcm/src/mock.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ pub mod pallet_test_notifier {
5050
use frame_system::pallet_prelude::*;
5151
use sp_runtime::DispatchResult;
5252
use xcm::latest::prelude::*;
53+
use xcm_executor::traits::QueryHandler;
5354

5455
#[pallet::pallet]
5556
pub struct Pallet<T>(_);
@@ -85,7 +86,7 @@ pub mod pallet_test_notifier {
8586
let id = who
8687
.using_encoded(|mut d| <[u8; 32]>::decode(&mut d))
8788
.map_err(|_| Error::<T>::BadAccountFormat)?;
88-
let qid = crate::Pallet::<T>::new_query(
89+
let qid = <crate::Pallet<T> as QueryHandler>::new_query(
8990
Junction::AccountId32 { network: None, id },
9091
100u32.into(),
9192
querier,

xcm/pallet-xcm/src/tests.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use sp_runtime::traits::{AccountIdConversion, BlakeTwo256, Hash};
2828
use xcm::{latest::QueryResponseInfo, prelude::*};
2929
use xcm_builder::AllowKnownQueryResponses;
3030
use xcm_executor::{
31-
traits::{Properties, ShouldExecute},
31+
traits::{Properties, QueryHandler, QueryResponseStatus, ShouldExecute},
3232
XcmExecutor,
3333
};
3434

@@ -170,7 +170,8 @@ fn report_outcome_works() {
170170
})
171171
);
172172

173-
let response = Some((Response::ExecutionResult(None), 1));
173+
let response =
174+
QueryResponseStatus::Ready { response: Response::ExecutionResult(None), at: 1 };
174175
assert_eq!(XcmPallet::take_response(0), response);
175176
});
176177
}
@@ -270,7 +271,8 @@ fn custom_querier_works() {
270271
})
271272
);
272273

273-
let response = Some((Response::ExecutionResult(None), 1));
274+
let response =
275+
QueryResponseStatus::Ready { response: Response::ExecutionResult(None), at: 1 };
274276
assert_eq!(XcmPallet::take_response(0), response);
275277
});
276278
}

xcm/xcm-builder/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ polkadot-test-runtime = { path = "../../runtime/test-runtime" }
3636
default = ["std"]
3737
runtime-benchmarks = [
3838
"frame-support/runtime-benchmarks",
39-
"frame-system/runtime-benchmarks"
39+
"frame-system/runtime-benchmarks",
40+
"xcm-executor/runtime-benchmarks",
4041
]
4142
std = [
4243
"log/std",

xcm/xcm-builder/src/lib.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ pub mod test_utils;
2828

2929
mod location_conversion;
3030
pub use location_conversion::{
31-
Account32Hash, AccountId32Aliases, AccountKey20Aliases, ChildParachainConvertsVia,
32-
GlobalConsensusParachainConvertsFor, ParentIsPreset, SiblingParachainConvertsVia,
31+
Account32Hash, AccountId32Aliases, AccountKey20Aliases, AliasesIntoAccountId32,
32+
ChildParachainConvertsVia, GlobalConsensusParachainConvertsFor, ParentIsPreset,
33+
SiblingParachainConvertsVia,
3334
};
3435

3536
mod origin_conversion;
@@ -95,3 +96,6 @@ pub use universal_exports::{
9596
ExporterFor, HaulBlob, HaulBlobError, HaulBlobExporter, NetworkExportTable,
9697
SovereignPaidRemoteExporter, UnpaidLocalExporter, UnpaidRemoteExporter,
9798
};
99+
100+
mod pay;
101+
pub use pay::{FixedLocation, LocatableAssetId, PayAccountId32OnChainOverXcm, PayOverXcm};

xcm/xcm-builder/src/location_conversion.rs

+20
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,26 @@ impl<Network: Get<Option<NetworkId>>, AccountId: From<[u8; 32]> + Into<[u8; 32]>
232232
}
233233
}
234234

235+
/// Conversion implementation which converts from a `[u8; 32]`-based `AccountId` into a
236+
/// `MultiLocation` consisting solely of a `AccountId32` junction with a fixed value for its
237+
/// network (provided by `Network`) and the `AccountId`'s `[u8; 32]` datum for the `id`.
238+
pub struct AliasesIntoAccountId32<Network, AccountId>(PhantomData<(Network, AccountId)>);
239+
impl<'a, Network: Get<Option<NetworkId>>, AccountId: Clone + Into<[u8; 32]> + Clone>
240+
Convert<&'a AccountId, MultiLocation> for AliasesIntoAccountId32<Network, AccountId>
241+
{
242+
fn convert(who: &AccountId) -> Result<MultiLocation, &'a AccountId> {
243+
Ok(AccountId32 { network: Network::get(), id: who.clone().into() }.into())
244+
}
245+
}
246+
247+
impl<Network: Get<Option<NetworkId>>, AccountId: Into<[u8; 32]> + Clone>
248+
Convert<AccountId, MultiLocation> for AliasesIntoAccountId32<Network, AccountId>
249+
{
250+
fn convert(who: AccountId) -> Result<MultiLocation, AccountId> {
251+
Ok(AccountId32 { network: Network::get(), id: who.into() }.into())
252+
}
253+
}
254+
235255
pub struct AccountKey20Aliases<Network, AccountId>(PhantomData<(Network, AccountId)>);
236256
impl<Network: Get<Option<NetworkId>>, AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone>
237257
Convert<MultiLocation, AccountId> for AccountKey20Aliases<Network, AccountId>

0 commit comments

Comments
 (0)