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

Commit

Permalink
Return a Result in invert_location (#3730)
Browse files Browse the repository at this point in the history
* Return a Result in invert_location

* Add invertible to spellcheck dictionary

* Fix Some -> Ok
  • Loading branch information
KiChjang committed Aug 28, 2021
1 parent 8ea7669 commit 54d1cb9
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 28 deletions.
4 changes: 2 additions & 2 deletions runtime/test-runtime/src/xcm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ impl WeightTrader for DummyWeightTrader {

pub struct InvertNothing;
impl InvertLocation for InvertNothing {
fn invert_location(_: &MultiLocation) -> MultiLocation {
Here.into()
fn invert_location(_: &MultiLocation) -> sp_std::result::Result<MultiLocation, ()> {
Ok(Here.into())
}
}

Expand Down
1 change: 1 addition & 0 deletions scripts/gitlab/lingua.dic
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ intrinsics
invariant/MS
invariants
inverter/MS
invertible
io
IP/S
isn
Expand Down
26 changes: 19 additions & 7 deletions xcm/pallet-xcm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use sp_std::{
convert::{TryFrom, TryInto},
marker::PhantomData,
prelude::*,
result::Result,
vec,
};
use xcm::{
Expand Down Expand Up @@ -206,6 +207,8 @@ pub mod pallet {
Filtered,
/// The message's weight could not be determined.
UnweighableMessage,
/// The destination `MultiLocation` provided cannot be inverted.
DestinationNotInvertible,
/// The assets to be sent are empty.
Empty,
/// Could not re-anchor the assets to declare the fees for the destination chain.
Expand Down Expand Up @@ -322,7 +325,8 @@ pub mod pallet {
let value = (origin_location, assets.drain());
ensure!(T::XcmTeleportFilter::contains(&value), Error::<T>::Filtered);
let (origin_location, assets) = value;
let inv_dest = T::LocationInverter::invert_location(&dest);
let inv_dest = T::LocationInverter::invert_location(&dest)
.map_err(|()| Error::<T>::DestinationNotInvertible)?;
let fees = assets
.get(fee_asset_item as usize)
.ok_or(Error::<T>::Empty)?
Expand Down Expand Up @@ -392,7 +396,8 @@ pub mod pallet {
let value = (origin_location, assets.drain());
ensure!(T::XcmReserveTransferFilter::contains(&value), Error::<T>::Filtered);
let (origin_location, assets) = value;
let inv_dest = T::LocationInverter::invert_location(&dest);
let inv_dest = T::LocationInverter::invert_location(&dest)
.map_err(|()| Error::<T>::DestinationNotInvertible)?;
let fees = assets
.get(fee_asset_item as usize)
.ok_or(Error::<T>::Empty)?
Expand Down Expand Up @@ -489,18 +494,21 @@ pub mod pallet {
/// - `timeout`: The block number after which it is permissible for `notify` not to be
/// called even if a response is received.
///
/// `report_outcome` may return an error if the `responder` is not invertible.
///
/// To check the status of the query, use `fn query()` passing the resultant `QueryId`
/// value.
pub fn report_outcome(
message: &mut Xcm<()>,
responder: MultiLocation,
timeout: T::BlockNumber,
) -> QueryId {
let dest = T::LocationInverter::invert_location(&responder);
) -> Result<QueryId, XcmError> {
let dest = T::LocationInverter::invert_location(&responder)
.map_err(|()| XcmError::MultiLocationNotInvertible)?;
let query_id = Self::new_query(responder, timeout);
let report_error = Xcm(vec![ReportError { dest, query_id, max_response_weight: 0 }]);
message.0.insert(0, SetAppendix(report_error));
query_id
Ok(query_id)
}

/// Consume `message` and return another which is equivalent to it except that it reports
Expand All @@ -516,6 +524,8 @@ pub mod pallet {
/// - `timeout`: The block number after which it is permissible for `notify` not to be
/// called even if a response is received.
///
/// `report_outcome_notify` may return an error if the `responder` is not invertible.
///
/// NOTE: `notify` gets called as part of handling an incoming message, so it should be
/// lightweight. Its weight is estimated during this function and stored ready for
/// weighing `ReportOutcome` on the way back. If it turns out to be heavier once it returns
Expand All @@ -526,13 +536,15 @@ pub mod pallet {
responder: MultiLocation,
notify: impl Into<<T as Config>::Call>,
timeout: T::BlockNumber,
) {
let dest = T::LocationInverter::invert_location(&responder);
) -> Result<(), XcmError> {
let dest = T::LocationInverter::invert_location(&responder)
.map_err(|()| XcmError::MultiLocationNotInvertible)?;
let notify: <T as Config>::Call = notify.into();
let max_response_weight = notify.get_dispatch_info().weight;
let query_id = Self::new_notify_query(responder, notify, timeout);
let report_error = Xcm(vec![ReportError { dest, query_id, max_response_weight }]);
message.0.insert(0, SetAppendix(report_error));
Ok(())
}

/// Attempt to create a new query ID and register it as a query that is yet to respond.
Expand Down
5 changes: 3 additions & 2 deletions xcm/pallet-xcm/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ fn report_outcome_notify_works() {
let call = pallet_test_notifier::Call::notification_received(0, Default::default());
let notify = Call::TestNotifier(call);
new_test_ext_with_balances(balances).execute_with(|| {
XcmPallet::report_outcome_notify(&mut message, Parachain(PARA_ID).into(), notify, 100);
XcmPallet::report_outcome_notify(&mut message, Parachain(PARA_ID).into(), notify, 100)
.unwrap();
assert_eq!(
message,
Xcm(vec![
Expand Down Expand Up @@ -94,7 +95,7 @@ fn report_outcome_works() {
beneficiary: sender.clone(),
}]);
new_test_ext_with_balances(balances).execute_with(|| {
XcmPallet::report_outcome(&mut message, Parachain(PARA_ID).into(), 100);
XcmPallet::report_outcome(&mut message, Parachain(PARA_ID).into(), 100).unwrap();
assert_eq!(
message,
Xcm(vec![
Expand Down
1 change: 1 addition & 0 deletions xcm/src/v2/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub enum Error {
UntrustedTeleportLocation,
DestinationBufferOverflow,
MultiLocationFull,
MultiLocationNotInvertible,
FailedToDecode,
BadOrigin,
ExceedsMaxMessageSize,
Expand Down
27 changes: 19 additions & 8 deletions xcm/xcm-builder/src/location_conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,24 +174,24 @@ impl<Network: Get<NetworkId>, AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone
///
/// let input = MultiLocation::new(2, X2(Parachain(2), AccountId32 { network: Any, id: Default::default() }));
/// let inverted = LocationInverter::<Ancestry>::invert_location(&input);
/// assert_eq!(inverted, MultiLocation::new(
/// assert_eq!(inverted, Ok(MultiLocation::new(
/// 2,
/// X2(Parachain(1), AccountKey20 { network: Any, key: Default::default() }),
/// ));
/// )));
/// # }
/// ```
pub struct LocationInverter<Ancestry>(PhantomData<Ancestry>);
impl<Ancestry: Get<MultiLocation>> InvertLocation for LocationInverter<Ancestry> {
fn invert_location(location: &MultiLocation) -> MultiLocation {
fn invert_location(location: &MultiLocation) -> Result<MultiLocation, ()> {
let mut ancestry = Ancestry::get();
let mut junctions = Here;
for _ in 0..location.parent_count() {
junctions = junctions
.pushed_with(ancestry.take_first_interior().unwrap_or(OnlyChild))
.expect("ancestry is well-formed and has less than 8 non-parent junctions; qed");
.map_err(|_| ())?;
}
let parents = location.interior().len() as u8;
MultiLocation::new(parents, junctions)
Ok(MultiLocation::new(parents, junctions))
}
}

Expand Down Expand Up @@ -229,7 +229,7 @@ mod tests {
}

let input = MultiLocation::new(3, X2(Parachain(2), account32()));
let inverted = LocationInverter::<Ancestry>::invert_location(&input);
let inverted = LocationInverter::<Ancestry>::invert_location(&input).unwrap();
assert_eq!(inverted, MultiLocation::new(2, X3(Parachain(1), account20(), account20())));
}

Expand All @@ -244,7 +244,7 @@ mod tests {
}

let input = MultiLocation::grandparent();
let inverted = LocationInverter::<Ancestry>::invert_location(&input);
let inverted = LocationInverter::<Ancestry>::invert_location(&input).unwrap();
assert_eq!(inverted, X2(account20(), account20()).into());
}

Expand All @@ -259,7 +259,18 @@ mod tests {
}

let input = MultiLocation::grandparent();
let inverted = LocationInverter::<Ancestry>::invert_location(&input);
let inverted = LocationInverter::<Ancestry>::invert_location(&input).unwrap();
assert_eq!(inverted, X2(PalletInstance(5), OnlyChild).into());
}

#[test]
fn inverter_errors_when_location_is_too_large() {
parameter_types! {
pub Ancestry: MultiLocation = Here.into();
}

let input = MultiLocation { parents: 99, interior: X1(Parachain(88)) };
let inverted = LocationInverter::<Ancestry>::invert_location(&input);
assert_eq!(inverted, Err(()));
}
}
18 changes: 10 additions & 8 deletions xcm/xcm-executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,8 @@ impl<Config: config::Config> XcmExecutor<Config> {
TransferReserveAsset { mut assets, dest, xcm } => {
let origin = self.origin.as_ref().ok_or(XcmError::BadOrigin)?;
// Take `assets` from the origin account (on-chain) and place into dest account.
let inv_dest = Config::LocationInverter::invert_location(&dest);
let inv_dest = Config::LocationInverter::invert_location(&dest)
.map_err(|()| XcmError::MultiLocationNotInvertible)?;
for asset in assets.inner() {
Config::AssetTransactor::beam_asset(asset, origin, &dest)?;
}
Expand Down Expand Up @@ -343,13 +344,13 @@ impl<Config: config::Config> XcmExecutor<Config> {
for asset in deposited.assets_iter() {
Config::AssetTransactor::deposit_asset(&asset, &dest)?;
}
let assets = Self::reanchored(deposited, &dest);
let assets = Self::reanchored(deposited, &dest)?;
let mut message = vec![ReserveAssetDeposited(assets), ClearOrigin];
message.extend(xcm.0.into_iter());
Config::XcmSender::send_xcm(dest, Xcm(message)).map_err(Into::into)
},
InitiateReserveWithdraw { assets, reserve, xcm } => {
let assets = Self::reanchored(self.holding.saturating_take(assets), &reserve);
let assets = Self::reanchored(self.holding.saturating_take(assets), &reserve)?;
let mut message = vec![WithdrawAsset(assets), ClearOrigin];
message.extend(xcm.0.into_iter());
Config::XcmSender::send_xcm(reserve, Xcm(message)).map_err(Into::into)
Expand All @@ -360,13 +361,13 @@ impl<Config: config::Config> XcmExecutor<Config> {
for asset in assets.assets_iter() {
Config::AssetTransactor::check_out(&dest, &asset);
}
let assets = Self::reanchored(assets, &dest);
let assets = Self::reanchored(assets, &dest)?;
let mut message = vec![ReceiveTeleportedAsset(assets), ClearOrigin];
message.extend(xcm.0.into_iter());
Config::XcmSender::send_xcm(dest, Xcm(message)).map_err(Into::into)
},
QueryHolding { query_id, dest, assets, max_response_weight } => {
let assets = Self::reanchored(self.holding.min(&assets), &dest);
let assets = Self::reanchored(self.holding.min(&assets), &dest)?;
let max_weight = max_response_weight;
let response = Response::Assets(assets);
let instruction = QueryResponse { query_id, response, max_weight };
Expand Down Expand Up @@ -425,9 +426,10 @@ impl<Config: config::Config> XcmExecutor<Config> {
}
}

fn reanchored(mut assets: Assets, dest: &MultiLocation) -> MultiAssets {
let inv_dest = Config::LocationInverter::invert_location(&dest);
fn reanchored(mut assets: Assets, dest: &MultiLocation) -> Result<MultiAssets, XcmError> {
let inv_dest = Config::LocationInverter::invert_location(&dest)
.map_err(|()| XcmError::MultiLocationNotInvertible)?;
assets.prepend_location(&inv_dest);
assets.into_assets_iter().collect::<Vec<_>>().into()
Ok(assets.into_assets_iter().collect::<Vec<_>>().into())
}
}
2 changes: 1 addition & 1 deletion xcm/xcm-executor/src/traits/conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,5 +200,5 @@ impl<O> ConvertOrigin<O> for Tuple {
/// Means of inverting a location: given a location which describes a `target` interpreted from the
/// `source`, this will provide the corresponding location which describes the `source`.
pub trait InvertLocation {
fn invert_location(l: &MultiLocation) -> MultiLocation;
fn invert_location(l: &MultiLocation) -> Result<MultiLocation, ()>;
}

0 comments on commit 54d1cb9

Please sign in to comment.