Add XCM Origin and converter (#2896)

* Add XCM Origin and converter

* IsMajority filter can be location-prefixed

* Update xcm/pallet-xcm/src/lib.rs

Co-authored-by: Alexander Popiak <alexander.popiak@parity.io>

* Update xcm/src/v0/multi_location.rs

Co-authored-by: Alexander Popiak <alexander.popiak@parity.io>

* Introduce UsingComponents to allow reuse of fee payment in XCM

* Use Drop rather than finalize

* Add errors for weight.

* Apply suggestions from code review

Co-authored-by: Alexander Popiak <alexander.popiak@parity.io>

* Fixes

* Update xcm/xcm-builder/src/weight.rs

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* Various XCM fixes and improvements

* Fixes

* Update xcm/xcm-builder/src/weight.rs

Co-authored-by: Alexander Popiak <alexander.popiak@parity.io>

* Update xcm/xcm-builder/src/weight.rs

Co-authored-by: Alexander Popiak <alexander.popiak@parity.io>

* Update xcm/xcm-builder/src/weight.rs

Co-authored-by: Alexander Popiak <alexander.popiak@parity.io>

* Fixes

Co-authored-by: Alexander Popiak <alexander.popiak@parity.io>
Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
This commit is contained in:
Gavin Wood
2021-04-27 14:33:40 +02:00
committed by GitHub
parent 8e0963e533
commit 9194219586
13 changed files with 357 additions and 218 deletions
+179 -174
View File
File diff suppressed because it is too large Load Diff
+6 -5
View File
@@ -92,7 +92,7 @@ use xcm_builder::{
AccountId32Aliases, ChildParachainConvertsVia, SovereignSignedViaLocation, AccountId32Aliases, ChildParachainConvertsVia, SovereignSignedViaLocation,
CurrencyAdapter as XcmCurrencyAdapter, ChildParachainAsNative, SignedAccountId32AsNative, CurrencyAdapter as XcmCurrencyAdapter, ChildParachainAsNative, SignedAccountId32AsNative,
ChildSystemParachainAsSuperuser, LocationInverter, IsConcrete, FixedWeightBounds, ChildSystemParachainAsSuperuser, LocationInverter, IsConcrete, FixedWeightBounds,
FixedRateOfConcreteFungible, BackingToPlurality, SignedToAccountId32 BackingToPlurality, SignedToAccountId32, UsingComponents,
}; };
use constants::{time::*, currency::*, fee::*, size::*}; use constants::{time::*, currency::*, fee::*, size::*};
use frame_support::traits::InstanceFilter; use frame_support::traits::InstanceFilter;
@@ -110,7 +110,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("rococo"), spec_name: create_runtime_str!("rococo"),
impl_name: create_runtime_str!("parity-rococo-v1.5"), impl_name: create_runtime_str!("parity-rococo-v1.5"),
authoring_version: 0, authoring_version: 0,
spec_version: 231, spec_version: 232,
impl_version: 0, impl_version: 0,
#[cfg(not(feature = "disable-runtime-api"))] #[cfg(not(feature = "disable-runtime-api"))]
apis: RUNTIME_API_VERSIONS, apis: RUNTIME_API_VERSIONS,
@@ -646,7 +646,7 @@ impl xcm_executor::Config for XcmConfig {
type LocationInverter = LocationInverter<Ancestry>; type LocationInverter = LocationInverter<Ancestry>;
type Barrier = Barrier; type Barrier = Barrier;
type Weigher = FixedWeightBounds<BaseXcmWeight, Call>; type Weigher = FixedWeightBounds<BaseXcmWeight, Call>;
type Trader = FixedRateOfConcreteFungible<RocFee>; type Trader = UsingComponents<WeightToFee, RocLocation, AccountId, Balances, ToAuthor<Runtime>>;
type ResponseHandler = (); type ResponseHandler = ();
} }
@@ -657,7 +657,8 @@ parameter_types! {
/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior location /// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior location
/// of this chain. /// of this chain.
pub type LocalOriginToLocation = ( pub type LocalOriginToLocation = (
// We allow an origin from the Collective pallet to be used in XCM as a corresponding Plurality // We allow an origin from the Collective pallet to be used in XCM as a corresponding Plurality of the
// `Unit` body.
BackingToPlurality<Origin, pallet_collective::Origin<Runtime>, CollectiveBodyId>, BackingToPlurality<Origin, pallet_collective::Origin<Runtime>, CollectiveBodyId>,
// And a usual Signed origin to be used in XCM as a corresponding AccountId32 // And a usual Signed origin to be used in XCM as a corresponding AccountId32
SignedToAccountId32<Origin, AccountId, RococoNetwork>, SignedToAccountId32<Origin, AccountId, RococoNetwork>,
@@ -881,8 +882,8 @@ impl pallet_collective::Config for Runtime {
type Event = Event; type Event = Event;
type MotionDuration = MotionDuration; type MotionDuration = MotionDuration;
type MaxProposals = MaxProposals; type MaxProposals = MaxProposals;
type MaxMembers = MaxMembers;
type DefaultVote = pallet_collective::PrimeDefaultVote; type DefaultVote = pallet_collective::PrimeDefaultVote;
type MaxMembers = MaxMembers;
type WeightInfo = (); type WeightInfo = ();
} }
+1
View File
@@ -14,6 +14,7 @@ frame-support = { git = "https://github.com/paritytech/substrate", default-featu
frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
xcm = { path = "..", default-features = false } xcm = { path = "..", default-features = false }
xcm-executor = { path = "../xcm-executor", default-features = false }
[features] [features]
default = ["std"] default = ["std"]
+23 -5
View File
@@ -20,7 +20,8 @@
use sp_std::{marker::PhantomData, convert::TryInto, boxed::Box}; use sp_std::{marker::PhantomData, convert::TryInto, boxed::Box};
use codec::{Encode, Decode}; use codec::{Encode, Decode};
use xcm::v0::{BodyId, MultiLocation::{self, X1}, Junction::Plurality}; use xcm::v0::{BodyId, OriginKind, MultiLocation, Junction::Plurality};
use xcm_executor::traits::ConvertOrigin;
use sp_runtime::{RuntimeDebug, traits::BadOrigin}; use sp_runtime::{RuntimeDebug, traits::BadOrigin};
use frame_support::traits::{EnsureOrigin, OriginTrait, Filter, Get}; use frame_support::traits::{EnsureOrigin, OriginTrait, Filter, Get};
@@ -62,6 +63,7 @@ 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> {
Attempted(xcm::v0::Outcome), Attempted(xcm::v0::Outcome),
Sent(MultiLocation, MultiLocation, Xcm<()>),
} }
#[pallet::error] #[pallet::error]
@@ -78,11 +80,12 @@ pub mod pallet {
#[pallet::weight(1_000)] #[pallet::weight(1_000)]
fn send(origin: OriginFor<T>, dest: MultiLocation, message: Xcm<()>) -> DispatchResult { fn send(origin: OriginFor<T>, dest: MultiLocation, message: Xcm<()>) -> DispatchResult {
let origin_location = T::SendXcmOrigin::ensure_origin(origin)?; let origin_location = T::SendXcmOrigin::ensure_origin(origin)?;
Self::send_xcm(origin_location, dest, message) Self::send_xcm(origin_location.clone(), dest.clone(), message.clone())
.map_err(|e| match e { .map_err(|e| match e {
XcmError::CannotReachDestination(..) => Error::<T>::Unreachable, XcmError::CannotReachDestination(..) => Error::<T>::Unreachable,
_ => Error::<T>::SendFailure, _ => Error::<T>::SendFailure,
})?; })?;
Self::deposit_event(Event::Sent(origin_location, dest, message));
Ok(()) Ok(())
} }
@@ -149,10 +152,11 @@ pub fn ensure_xcm<OuterOrigin>(o: OuterOrigin) -> Result<MultiLocation, BadOrigi
/// plurality. /// plurality.
/// ///
/// May reasonably be used with `EnsureXcm`. /// May reasonably be used with `EnsureXcm`.
pub struct IsMajorityOfBody<Body>(PhantomData<Body>); pub struct IsMajorityOfBody<Prefix, Body>(PhantomData<(Prefix, Body)>);
impl<Body: Get<BodyId>> Filter<MultiLocation> for IsMajorityOfBody<Body> { impl<Prefix: Get<MultiLocation>, Body: Get<BodyId>> Filter<MultiLocation> for IsMajorityOfBody<Prefix, Body> {
fn filter(l: &MultiLocation) -> bool { fn filter(l: &MultiLocation) -> bool {
matches!(l, X1(Plurality { id, part }) if id == &Body::get() && part.is_majority()) let maybe_suffix = l.match_and_split(&Prefix::get());
matches!(maybe_suffix, Some(Plurality { id, part }) if id == &Body::get() && part.is_majority())
} }
} }
@@ -180,3 +184,17 @@ impl<O: OriginTrait + From<Origin>, F: Filter<MultiLocation>> EnsureOrigin<O> fo
O::from(Origin::Xcm(MultiLocation::Null)) O::from(Origin::Xcm(MultiLocation::Null))
} }
} }
/// A simple passthrough where we reuse the `MultiLocation`-typed XCM origin as the inner value of
/// this crate's `Origin::Xcm` value.
pub struct XcmPassthrough<Origin>(PhantomData<Origin>);
impl<
Origin: From<crate::Origin>,
> ConvertOrigin<Origin> for XcmPassthrough<Origin> {
fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> {
match (kind, origin) {
(OriginKind::Xcm, l) => Ok(crate::Origin::Xcm(l).into()),
(_, origin) => Err(origin),
}
}
}
+9 -2
View File
@@ -39,8 +39,10 @@ pub use traits::{Error, Result, SendXcm, ExecuteXcm, Outcome};
/// Basically just the XCM (more general) version of `ParachainDispatchOrigin`. /// Basically just the XCM (more general) version of `ParachainDispatchOrigin`.
#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, Debug)] #[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, Debug)]
pub enum OriginKind { pub enum OriginKind {
/// Origin should just be the native origin for the sender. For Cumulus/Frame chains this is /// Origin should just be the native dispatch origin representation for the sender in the
/// the `Parachain` origin. /// local runtime framework. For Cumulus/Frame chains this is the `Parachain` or `Relay` origin
/// if coming from a chain, though there may be others if the `MultiLocation` XCM origin has a
/// primary/native dispatch origin form.
Native, Native,
/// Origin should just be the standard account-based origin with the sovereign account of /// Origin should just be the standard account-based origin with the sovereign account of
@@ -50,6 +52,11 @@ pub enum OriginKind {
/// Origin should be the super-user. For Cumulus/Frame chains, this is the `Root` origin. /// Origin should be the super-user. For Cumulus/Frame chains, this is the `Root` origin.
/// This will not usually be an available option. /// This will not usually be an available option.
Superuser, Superuser,
/// Origin should be interpreted as an XCM native origin and the `MultiLocation` should be
/// encoded directly in the dispatch origin unchanged. For Cumulus/Frame chains, this will be
/// the `pallet_xcm::Origin::Xcm` type.
Xcm,
} }
/// Response data to a query. /// Response data to a query.
+14
View File
@@ -442,6 +442,20 @@ impl MultiLocation {
MultiLocationReverseIterator(self) MultiLocationReverseIterator(self)
} }
/// Ensures that self begins with `prefix` and that it has a single `Junction` item following. If
/// so, returns a reference to this `Junction` item.
pub fn match_and_split(&self, prefix: &MultiLocation) -> Option<&Junction> {
if prefix.len() + 1 != self.len() {
return None
}
for i in 0..prefix.len() {
if prefix.at(i) != self.at(i) {
return None
}
}
return self.at(prefix.len())
}
/// Mutates `self`, suffixing it with `new`. Returns `Err` in case of overflow. /// Mutates `self`, suffixing it with `new`. Returns `Err` in case of overflow.
pub fn push(&mut self, new: Junction) -> result::Result<(), ()> { pub fn push(&mut self, new: Junction) -> result::Result<(), ()> {
let mut n = MultiLocation::Null; let mut n = MultiLocation::Null;
+2
View File
@@ -72,6 +72,8 @@ pub enum Error {
NotWithdrawable, NotWithdrawable,
/// Indicates that the consensus system cannot deposit an asset under the ownership of a particular location. /// Indicates that the consensus system cannot deposit an asset under the ownership of a particular location.
LocationCannotHold, LocationCannotHold,
/// The assets given to purchase weight is are insufficient for the weight desired.
TooExpensive,
} }
impl From<()> for Error { impl From<()> for Error {
+2
View File
@@ -16,6 +16,7 @@ sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", de
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
# Polkadot dependencies # Polkadot dependencies
polkadot-parachain = { path = "../../parachain", default-features = false } polkadot-parachain = { path = "../../parachain", default-features = false }
@@ -33,4 +34,5 @@ std = [
"sp-runtime/std", "sp-runtime/std",
"frame-support/std", "frame-support/std",
"polkadot-parachain/std", "polkadot-parachain/std",
"pallet-transaction-payment/std",
] ]
+1 -1
View File
@@ -46,7 +46,7 @@ mod fungibles_adapter;
pub use fungibles_adapter::FungiblesAdapter; pub use fungibles_adapter::FungiblesAdapter;
mod weight; mod weight;
pub use weight::{FixedRateOfConcreteFungible, FixedWeightBounds}; pub use weight::{FixedRateOfConcreteFungible, FixedWeightBounds, UsingComponents};
mod matches_fungible; mod matches_fungible;
pub use matches_fungible::{IsAbstract, IsConcrete}; pub use matches_fungible::{IsAbstract, IsConcrete};
+1 -1
View File
@@ -272,6 +272,6 @@ impl Config for TestConfig {
type LocationInverter = LocationInverter<TestAncestry>; type LocationInverter = LocationInverter<TestAncestry>;
type Barrier = TestBarrier; type Barrier = TestBarrier;
type Weigher = FixedWeightBounds<UnitWeightCost, TestCall>; type Weigher = FixedWeightBounds<UnitWeightCost, TestCall>;
type Trader = FixedRateOfConcreteFungible<WeightPrice>; type Trader = FixedRateOfConcreteFungible<WeightPrice, ()>;
type ResponseHandler = TestResponseHandler; type ResponseHandler = TestResponseHandler;
} }
+107 -22
View File
@@ -14,19 +14,22 @@
// 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 sp_std::{result::Result, marker::PhantomData}; use sp_std::{result::Result, marker::PhantomData, convert::TryInto};
use parity_scale_codec::Decode; use parity_scale_codec::Decode;
use xcm::v0::{Xcm, Order, MultiAsset, MultiLocation}; use xcm::v0::{Xcm, Order, MultiAsset, MultiLocation, Error};
use frame_support::{traits::Get, weights::{Weight, GetDispatchInfo}}; use sp_runtime::traits::{Zero, Saturating, SaturatedConversion};
use frame_support::traits::{Get, OnUnbalanced as OnUnbalancedT, tokens::currency::Currency as CurrencyT};
use frame_support::weights::{Weight, GetDispatchInfo, WeightToFeePolynomial};
use xcm_executor::{Assets, traits::{WeightBounds, WeightTrader}}; use xcm_executor::{Assets, traits::{WeightBounds, WeightTrader}};
pub struct FixedWeightBounds<T, C>(PhantomData<(T, C)>); pub struct FixedWeightBounds<T, C>(PhantomData<(T, C)>);
impl<T: Get<Weight>, C: Decode + GetDispatchInfo> WeightBounds<C> for FixedWeightBounds<T, C> { impl<T: Get<Weight>, C: Decode + GetDispatchInfo> WeightBounds<C> for FixedWeightBounds<T, C> {
fn shallow(message: &mut Xcm<C>) -> Result<Weight, ()> { fn shallow(message: &mut Xcm<C>) -> Result<Weight, ()> {
let min = match message { Ok(match message {
Xcm::Transact { call, .. } => { Xcm::Transact { call, .. } => {
call.ensure_decoded()?.get_dispatch_info().weight + T::get() call.ensure_decoded()?.get_dispatch_info().weight + T::get()
} }
Xcm::RelayedFrom { ref mut message, .. } => T::get() + Self::shallow(message.as_mut())?,
Xcm::WithdrawAsset { effects, .. } Xcm::WithdrawAsset { effects, .. }
| Xcm::ReserveAssetDeposit { effects, .. } | Xcm::ReserveAssetDeposit { effects, .. }
| Xcm::TeleportAsset { effects, .. } => { | Xcm::TeleportAsset { effects, .. } => {
@@ -45,16 +48,16 @@ impl<T: Get<Weight>, C: Decode + GetDispatchInfo> WeightBounds<C> for FixedWeigh
T::get() + inner T::get() + inner
} }
_ => T::get(), _ => T::get(),
}; })
Ok(min)
} }
fn deep(message: &mut Xcm<C>) -> Result<Weight, ()> { fn deep(message: &mut Xcm<C>) -> Result<Weight, ()> {
let mut extra = 0; Ok(match message {
match message { Xcm::RelayedFrom { ref mut message, .. } => Self::deep(message.as_mut())?,
Xcm::Transact { .. } => {}
Xcm::WithdrawAsset { effects, .. } Xcm::WithdrawAsset { effects, .. }
| Xcm::ReserveAssetDeposit { effects, .. } | Xcm::ReserveAssetDeposit { effects, .. }
| Xcm::TeleportAsset { effects, .. } => { | Xcm::TeleportAsset { effects, .. }
=> {
let mut extra = 0;
for effect in effects.iter_mut() { for effect in effects.iter_mut() {
match effect { match effect {
Order::BuyExecution { xcm, .. } => { Order::BuyExecution { xcm, .. } => {
@@ -65,34 +68,116 @@ impl<T: Get<Weight>, C: Decode + GetDispatchInfo> WeightBounds<C> for FixedWeigh
_ => {} _ => {}
} }
} }
extra
},
_ => 0,
})
} }
_ => {}
};
Ok(extra)
} }
/// Function trait for handling some revenue. Similar to a negative imbalance (credit) handler, but for a
/// `MultiAsset`. Sensible implementations will deposit the asset in some known treasury or block-author account.
pub trait TakeRevenue {
/// Do something with the given `revenue`, which is a single non-wildcard `MultiAsset`.
fn take_revenue(revenue: MultiAsset);
}
/// Null implementation just burns the revenue.
impl TakeRevenue for () {
fn take_revenue(_revenue: MultiAsset) {}
} }
/// Simple fee calculator that requires payment in a single concrete fungible at a fixed rate. /// Simple fee calculator that requires payment in a single concrete fungible at a fixed rate.
/// ///
/// The constant `Get` type parameter should be the concrete fungible ID and the amount of it required for /// The constant `Get` type parameter should be the concrete fungible ID and the amount of it required for
/// one second of weight. /// one second of weight.
pub struct FixedRateOfConcreteFungible<T>(Weight, PhantomData<T>); pub struct FixedRateOfConcreteFungible<
impl<T: Get<(MultiLocation, u128)>> WeightTrader for FixedRateOfConcreteFungible<T> { T: Get<(MultiLocation, u128)>,
fn new() -> Self { Self(0, PhantomData) } R: TakeRevenue,
fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, ()> { >(Weight, u128, PhantomData<(T, R)>);
impl<T: Get<(MultiLocation, u128)>, R: TakeRevenue> WeightTrader for FixedRateOfConcreteFungible<T, R> {
fn new() -> Self { Self(0, 0, PhantomData) }
fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, Error> {
let (id, units_per_second) = T::get(); let (id, units_per_second) = T::get();
let amount = units_per_second * (weight as u128) / 1_000_000_000_000u128; use frame_support::weights::constants::WEIGHT_PER_SECOND;
let amount = units_per_second * (weight as u128) / (WEIGHT_PER_SECOND as u128);
let required = MultiAsset::ConcreteFungible { amount, id }; let required = MultiAsset::ConcreteFungible { amount, id };
let (used, _) = payment.less(required).map_err(|_| ())?; let (unused, _) = payment.less(required).map_err(|_| Error::TooExpensive)?;
self.0 = self.0.saturating_add(weight); self.0 = self.0.saturating_add(weight);
Ok(used) self.1 = self.1.saturating_add(amount);
Ok(unused)
} }
fn refund_weight(&mut self, weight: Weight) -> MultiAsset { fn refund_weight(&mut self, weight: Weight) -> MultiAsset {
let weight = weight.min(self.0);
self.0 -= weight;
let (id, units_per_second) = T::get(); let (id, units_per_second) = T::get();
let weight = weight.min(self.0);
let amount = units_per_second * (weight as u128) / 1_000_000_000_000u128; let amount = units_per_second * (weight as u128) / 1_000_000_000_000u128;
self.0 -= weight;
self.1 = self.1.saturating_sub(amount);
let result = MultiAsset::ConcreteFungible { amount, id }; let result = MultiAsset::ConcreteFungible { amount, id };
result result
} }
} }
impl<T: Get<(MultiLocation, u128)>, R: TakeRevenue> Drop for FixedRateOfConcreteFungible<T, R> {
fn drop(&mut self) {
let revenue = MultiAsset::ConcreteFungible { amount: self.1, id: T::get().0 };
R::take_revenue(revenue);
}
}
/// Weight trader which uses the TransactionPayment pallet to set the right price for weight and then
/// places any weight bought into the right account.
pub struct UsingComponents<
WeightToFee: WeightToFeePolynomial<Balance=Currency::Balance>,
AssetId: Get<MultiLocation>,
AccountId,
Currency: CurrencyT<AccountId>,
OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
>(Weight, Currency::Balance, PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>);
impl<
WeightToFee: WeightToFeePolynomial<Balance=Currency::Balance>,
AssetId: Get<MultiLocation>,
AccountId,
Currency: CurrencyT<AccountId>,
OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
> WeightTrader for UsingComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced> {
fn new() -> Self { Self(0, Zero::zero(), PhantomData) }
fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, Error> {
let amount = WeightToFee::calc(&weight);
let required = MultiAsset::ConcreteFungible {
amount: amount.try_into().map_err(|_| Error::Overflow)?,
id: AssetId::get(),
};
let (unused, _) = payment.less(required).map_err(|_| Error::TooExpensive)?;
self.0 = self.0.saturating_add(weight);
self.1 = self.1.saturating_add(amount);
Ok(unused)
}
fn refund_weight(&mut self, weight: Weight) -> MultiAsset {
let weight = weight.min(self.0);
let amount = WeightToFee::calc(&weight);
self.0 -= weight;
self.1 = self.1.saturating_sub(amount);
let result = MultiAsset::ConcreteFungible {
amount: amount.saturated_into(),
id: AssetId::get(),
};
result
}
}
impl<
WeightToFee: WeightToFeePolynomial<Balance=Currency::Balance>,
AssetId: Get<MultiLocation>,
AccountId,
Currency: CurrencyT<AccountId>,
OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,
> Drop for UsingComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced> {
fn drop(&mut self) {
OnUnbalanced::on_unbalanced(Currency::issue(self.1));
}
}
+8 -4
View File
@@ -60,7 +60,9 @@ impl<Config: config::Config> ExecuteXcm<Config::Call> for XcmExecutor<Config> {
return Outcome::Error(XcmError::WeightLimitReached); return Outcome::Error(XcmError::WeightLimitReached);
} }
let mut trader = Config::Trader::new(); let mut trader = Config::Trader::new();
match Self::do_execute_xcm(origin, true, message, &mut 0, Some(shallow_weight), &mut trader) { let result = Self::do_execute_xcm(origin, true, message, &mut 0, Some(shallow_weight), &mut trader);
drop(trader);
match result {
Ok(surplus) => Outcome::Complete(maximum_weight.saturating_sub(surplus)), Ok(surplus) => Outcome::Complete(maximum_weight.saturating_sub(surplus)),
// TODO: #2841 #REALWEIGHT We can do better than returning `maximum_weight` here, and we should otherwise // TODO: #2841 #REALWEIGHT We can do better than returning `maximum_weight` here, and we should otherwise
// we'll needlessly be disregarding block execution time. // we'll needlessly be disregarding block execution time.
@@ -76,7 +78,9 @@ impl<Config: config::Config> XcmExecutor<Config> {
assets.into_assets_iter().collect::<Vec<_>>() assets.into_assets_iter().collect::<Vec<_>>()
} }
/// Execute the XCM and return any unexpected and unknowable surplus weight. /// Execute the XCM and return the portion of weight of `shallow_weight + deep_weight` that `message` did not use.
///
/// NOTE: The amount returned must be less than `shallow_weight + deep_weight` of `message`.
fn do_execute_xcm( fn do_execute_xcm(
origin: MultiLocation, origin: MultiLocation,
top_level: bool, top_level: bool,
@@ -95,8 +99,8 @@ impl<Config: config::Config> XcmExecutor<Config> {
.map_err(|()| XcmError::Barrier)?; .map_err(|()| XcmError::Barrier)?;
// The surplus weight, defined as the amount by which `shallow_weight` plus all nested // The surplus weight, defined as the amount by which `shallow_weight` plus all nested
// `shallow_weight` values (ensuring no double-counting) is an overestimate of the actual weight // `shallow_weight` values (ensuring no double-counting and also known as `deep_weight`) is an
// consumed. // over-estimate of the actual weight consumed.
let mut total_surplus: Weight = 0; let mut total_surplus: Weight = 0;
let maybe_holding_effects = match (origin.clone(), message) { let maybe_holding_effects = match (origin.clone(), message) {
@@ -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 sp_std::result::Result; use sp_std::result::Result;
use xcm::v0::{Xcm, MultiAsset}; use xcm::v0::{Xcm, MultiAsset, Error};
use frame_support::weights::Weight; use frame_support::weights::Weight;
use crate::Assets; use crate::Assets;
@@ -46,14 +46,14 @@ pub trait WeightBounds<Call> {
} }
/// Charge for weight in order to execute XCM. /// Charge for weight in order to execute XCM.
pub trait WeightTrader { pub trait WeightTrader: Sized {
/// Create a new trader instance. /// Create a new trader instance.
fn new() -> Self; fn new() -> Self;
/// Purchase execution weight credit in return for up to a given `fee`. If less of the fee is required /// Purchase execution weight credit in return for up to a given `fee`. If less of the fee is required
/// then the surplus is returned. If the `fee` cannot be used to pay for the `weight`, then an error is /// then the surplus is returned. If the `fee` cannot be used to pay for the `weight`, then an error is
/// returned. /// returned.
fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, ()>; fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, Error>;
/// Attempt a refund of `weight` into some asset. The caller does not guarantee that the weight was /// Attempt a refund of `weight` into some asset. The caller does not guarantee that the weight was
/// purchased using `buy_weight`. /// purchased using `buy_weight`.