mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 05:51:02 +00:00
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:
Generated
+179
-174
File diff suppressed because it is too large
Load Diff
@@ -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 = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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"]
|
||||||
|
|||||||
@@ -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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -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};
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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`.
|
||||||
|
|||||||
Reference in New Issue
Block a user