mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 04:41:03 +00:00
Dispatchable for teleporting assets (#2995)
* Dispatchable for teleporting assets * Fixes * Fixes * Fixes * Fixes * Fixes * Update node/network/protocol/src/peer_set.rs Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> * Update xcm/src/v0/traits.rs Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
This commit is contained in:
Generated
+149
-149
File diff suppressed because it is too large
Load Diff
@@ -52,7 +52,7 @@ use runtime_parachains::scheduler as parachains_scheduler;
|
||||
use runtime_parachains::reward_points as parachains_reward_points;
|
||||
use runtime_parachains::runtime_api_impl::v1 as parachains_runtime_api_impl;
|
||||
|
||||
use xcm::v0::{MultiLocation, NetworkId, BodyId, Xcm};
|
||||
use xcm::v0::{MultiLocation, NetworkId, BodyId, Xcm, MultiAsset};
|
||||
use xcm_builder::{
|
||||
AccountId32Aliases, ChildParachainConvertsVia, SovereignSignedViaLocation, CurrencyAdapter as XcmCurrencyAdapter,
|
||||
ChildParachainAsNative, SignedAccountId32AsNative, ChildSystemParachainAsSuperuser, LocationInverter,
|
||||
@@ -1217,6 +1217,8 @@ impl pallet_xcm::Config for Runtime {
|
||||
// ...but they must match our filter, which requires them to be a simple withdraw + teleport.
|
||||
type XcmExecuteFilter = OnlyWithdrawTeleportForAccounts;
|
||||
type XcmExecutor = XcmExecutor<XcmConfig>;
|
||||
type XcmTeleportFilter = All<(MultiLocation, Vec<MultiAsset>)>;
|
||||
type Weigher = FixedWeightBounds<BaseXcmWeight, Call>;
|
||||
}
|
||||
|
||||
construct_runtime! {
|
||||
|
||||
@@ -110,7 +110,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
spec_name: create_runtime_str!("rococo"),
|
||||
impl_name: create_runtime_str!("parity-rococo-v1.5"),
|
||||
authoring_version: 0,
|
||||
spec_version: 9000,
|
||||
spec_version: 9001,
|
||||
impl_version: 0,
|
||||
#[cfg(not(feature = "disable-runtime-api"))]
|
||||
apis: RUNTIME_API_VERSIONS,
|
||||
@@ -714,6 +714,8 @@ impl pallet_xcm::Config for Runtime {
|
||||
// ...but they must match our filter, which requires them to be a simple withdraw + teleport.
|
||||
type XcmExecuteFilter = OnlyWithdrawTeleportForAccounts;
|
||||
type XcmExecutor = XcmExecutor<XcmConfig>;
|
||||
type XcmTeleportFilter = All<(MultiLocation, Vec<MultiAsset>)>;
|
||||
type Weigher = FixedWeightBounds<BaseXcmWeight, Call>;
|
||||
}
|
||||
|
||||
impl parachains_session_info::Config for Runtime {}
|
||||
|
||||
@@ -53,7 +53,7 @@ use runtime_parachains::scheduler as parachains_scheduler;
|
||||
use runtime_parachains::reward_points as parachains_reward_points;
|
||||
use runtime_parachains::runtime_api_impl::v1 as parachains_runtime_api_impl;
|
||||
|
||||
use xcm::v0::{MultiLocation, NetworkId, Xcm};
|
||||
use xcm::v0::{MultiLocation, NetworkId, Xcm, MultiAsset};
|
||||
use xcm_executor::XcmExecutor;
|
||||
use xcm_builder::{
|
||||
AccountId32Aliases, ChildParachainConvertsVia, SovereignSignedViaLocation, CurrencyAdapter as XcmCurrencyAdapter,
|
||||
@@ -922,6 +922,8 @@ impl pallet_xcm::Config for Runtime {
|
||||
// ...but they must match our filter, which requires them to be a simple withdraw + teleport.
|
||||
type XcmExecuteFilter = OnlyWithdrawTeleportForAccounts;
|
||||
type XcmExecutor = XcmExecutor<XcmConfig>;
|
||||
type XcmTeleportFilter = All<(MultiLocation, Vec<MultiAsset>)>;
|
||||
type Weigher = FixedWeightBounds<BaseXcmWeight, Call>;
|
||||
}
|
||||
|
||||
construct_runtime! {
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use sp_std::{marker::PhantomData, convert::TryInto, boxed::Box};
|
||||
use sp_std::{prelude::*, marker::PhantomData, convert::TryInto, boxed::Box, vec};
|
||||
use codec::{Encode, Decode};
|
||||
use xcm::v0::{BodyId, OriginKind, MultiLocation, Junction::Plurality};
|
||||
use xcm::v0::prelude::*;
|
||||
use xcm_executor::traits::ConvertOrigin;
|
||||
use sp_runtime::{RuntimeDebug, traits::BadOrigin};
|
||||
use frame_support::traits::{EnsureOrigin, OriginTrait, Filter, Get, Contains};
|
||||
@@ -32,7 +32,7 @@ pub mod pallet {
|
||||
use super::*;
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
use xcm::v0::{Xcm, MultiLocation, Error as XcmError, SendXcm, ExecuteXcm};
|
||||
use xcm_executor::traits::WeightBounds;
|
||||
|
||||
#[pallet::pallet]
|
||||
#[pallet::generate_store(pub(super) trait Store)]
|
||||
@@ -51,8 +51,9 @@ pub mod pallet {
|
||||
/// The type used to actually dispatch an XCM to its destination.
|
||||
type XcmRouter: SendXcm;
|
||||
|
||||
/// Required origin for executing XCM messages. If successful, the it resolves to `MultiLocation`
|
||||
/// which exists as an interior location within this chain's XCM context.
|
||||
/// Required origin for executing XCM messages, includng the teleport functionality. If successful,
|
||||
/// the it resolves to `MultiLocation` which exists as an interior location within this chain's XCM
|
||||
/// context.
|
||||
type ExecuteXcmOrigin: EnsureOrigin<Self::Origin, Success=MultiLocation>;
|
||||
|
||||
/// Our XCM filter which messages to be executed using `XcmExecutor` must pass.
|
||||
@@ -60,6 +61,12 @@ pub mod pallet {
|
||||
|
||||
/// Something to execute an XCM message.
|
||||
type XcmExecutor: ExecuteXcm<Self::Call>;
|
||||
|
||||
/// Our XCM filter which messages to be executed using `XcmExecutor` must pass.
|
||||
type XcmTeleportFilter: Contains<(MultiLocation, Vec<MultiAsset>)>;
|
||||
|
||||
/// Means of measuring the weight consumed by an XCM message locally.
|
||||
type Weigher: WeightBounds<Self::Call>;
|
||||
}
|
||||
|
||||
#[pallet::event]
|
||||
@@ -75,6 +82,8 @@ pub mod pallet {
|
||||
SendFailure,
|
||||
/// The message execution fails the filter.
|
||||
Filtered,
|
||||
/// The message's weight could not be determined.
|
||||
UnweighableMessage,
|
||||
}
|
||||
|
||||
#[pallet::hooks]
|
||||
@@ -82,7 +91,7 @@ pub mod pallet {
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
#[pallet::weight(1_000)]
|
||||
#[pallet::weight(100_000_000)]
|
||||
fn send(origin: OriginFor<T>, dest: MultiLocation, message: Xcm<()>) -> DispatchResult {
|
||||
let origin_location = T::SendXcmOrigin::ensure_origin(origin)?;
|
||||
Self::send_xcm(origin_location.clone(), dest.clone(), message.clone())
|
||||
@@ -94,6 +103,66 @@ pub mod pallet {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Teleport some assets from the local chain to some destination chain.
|
||||
///
|
||||
/// - `origin`: Must be capable of withdrawing the `assets` and executing XCM.
|
||||
/// - `dest`: Destination context for the assets. Will typically be `X2(Parent, Parachain(..))` to send
|
||||
/// from parachain to parachain, or `X1(Parachain(..))` to send from relay to parachain.
|
||||
/// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will generally be
|
||||
/// an `AccountId32` value.
|
||||
/// - `assets`: The assets to be withdrawn. This should include the assets used to pay the fee on the
|
||||
/// `dest` side.
|
||||
/// - `dest_weight`: Equal to the total weight on `dest` of the XCM message
|
||||
/// `Teleport { assets, effects: [ BuyExecution{..}, DepositAsset{..} ] }`.
|
||||
#[pallet::weight({
|
||||
let mut message = Xcm::WithdrawAsset {
|
||||
assets: assets.clone(),
|
||||
effects: sp_std::vec![ InitiateTeleport {
|
||||
assets: sp_std::vec![ All ],
|
||||
dest: dest.clone(),
|
||||
effects: sp_std::vec![],
|
||||
} ]
|
||||
};
|
||||
T::Weigher::weight(&mut message).map_or(Weight::max_value(), |w| 100_000_000 + w)
|
||||
})]
|
||||
fn teleport_assets(
|
||||
origin: OriginFor<T>,
|
||||
dest: MultiLocation,
|
||||
beneficiary: MultiLocation,
|
||||
assets: Vec<MultiAsset>,
|
||||
dest_weight: Weight,
|
||||
) -> DispatchResult {
|
||||
let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?;
|
||||
let value = (origin_location, assets);
|
||||
ensure!(T::XcmTeleportFilter::contains(&value), Error::<T>::Filtered);
|
||||
let (origin_location, assets) = value;
|
||||
let mut message = Xcm::WithdrawAsset {
|
||||
assets,
|
||||
effects: vec![
|
||||
InitiateTeleport {
|
||||
assets: vec![ All ],
|
||||
dest,
|
||||
effects: vec![
|
||||
BuyExecution {
|
||||
fees: All,
|
||||
// Zero weight for additional XCM (since there are none to execute)
|
||||
weight: 0,
|
||||
debt: dest_weight,
|
||||
halt_on_error: false,
|
||||
xcm: vec![],
|
||||
},
|
||||
DepositAsset { assets: vec![ All ], dest: beneficiary },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
let weight = T::Weigher::weight(&mut message)
|
||||
.map_err(|()| Error::<T>::UnweighableMessage)?;
|
||||
let outcome = T::XcmExecutor::execute_xcm_in_credit(origin_location, message, weight, weight);
|
||||
Self::deposit_event(Event::Attempted(outcome));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Execute an XCM message from a local, signed, origin.
|
||||
///
|
||||
/// An event is deposited indicating whether `msg` could be executed completely or only
|
||||
@@ -105,7 +174,7 @@ pub mod pallet {
|
||||
///
|
||||
/// NOTE: A successful return to this does *not* imply that the `msg` was executed successfully
|
||||
/// to completion; only that *some* of it was executed.
|
||||
#[pallet::weight(max_weight.saturating_add(1_000u64))]
|
||||
#[pallet::weight(max_weight.saturating_add(100_000_000u64))]
|
||||
fn execute(origin: OriginFor<T>, message: Box<Xcm<T::Call>>, max_weight: Weight)
|
||||
-> DispatchResult
|
||||
{
|
||||
|
||||
@@ -33,6 +33,16 @@ pub use multi_location::MultiLocation;
|
||||
pub use order::Order;
|
||||
pub use traits::{Error, Result, SendXcm, ExecuteXcm, Outcome};
|
||||
|
||||
/// A prelude for importing all types typically used when interacting with XCM messages.
|
||||
pub mod prelude {
|
||||
pub use super::junction::{Junction::*, NetworkId, BodyId, BodyPart};
|
||||
pub use super::multi_asset::{MultiAsset::{self, *}, AssetInstance::{self, *}};
|
||||
pub use super::multi_location::MultiLocation::{self, *};
|
||||
pub use super::order::Order::{self, *};
|
||||
pub use super::traits::{Error as XcmError, Result as XcmResult, SendXcm, ExecuteXcm, Outcome};
|
||||
pub use super::{Xcm::{self, *}, OriginKind};
|
||||
}
|
||||
|
||||
// TODO: #2841 #XCMENCODE Efficient encodings for Vec<MultiAsset>, Vec<Order>, using initial byte values 128+ to encode
|
||||
// the number of items in the vector.
|
||||
|
||||
|
||||
@@ -126,14 +126,34 @@ impl Outcome {
|
||||
}
|
||||
}
|
||||
|
||||
/// Type of XCM message executor.
|
||||
pub trait ExecuteXcm<Call> {
|
||||
type Call;
|
||||
fn execute_xcm(origin: MultiLocation, message: Xcm<Call>, weight_limit: Weight) -> Outcome;
|
||||
/// Execute some XCM `message` from `origin` using no more than `weight_limit` weight. The weight limit is
|
||||
/// a basic hard-limit and the implementation may place further restrictions or requirements on weight and
|
||||
/// other aspects.
|
||||
fn execute_xcm(origin: MultiLocation, message: Xcm<Call>, weight_limit: Weight) -> Outcome {
|
||||
Self::execute_xcm_in_credit(origin, message, weight_limit, 0)
|
||||
}
|
||||
|
||||
/// Execute some XCM `message` from `origin` using no more than `weight_limit` weight.
|
||||
///
|
||||
/// Some amount of `weight_credit` may be provided which, depending on the implementation, may allow
|
||||
/// execution without associated payment.
|
||||
fn execute_xcm_in_credit(
|
||||
origin: MultiLocation,
|
||||
message: Xcm<Call>,
|
||||
weight_limit: Weight,
|
||||
weight_credit: Weight,
|
||||
) -> Outcome;
|
||||
}
|
||||
|
||||
impl<C> ExecuteXcm<C> for () {
|
||||
type Call = C;
|
||||
fn execute_xcm(_origin: MultiLocation, _message: Xcm<C>, _weight_limit: Weight) -> Outcome {
|
||||
fn execute_xcm_in_credit(
|
||||
_origin: MultiLocation,
|
||||
_message: Xcm<C>,
|
||||
_weight_limit: Weight,
|
||||
_weight_credit: Weight,
|
||||
) -> Outcome {
|
||||
Outcome::Error(Error::Unimplemented)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,8 @@ impl<T: Get<Weight>, C: Decode + GetDispatchInfo> WeightBounds<C> for FixedWeigh
|
||||
Xcm::RelayedFrom { ref mut message, .. } => T::get() + Self::shallow(message.as_mut())?,
|
||||
Xcm::WithdrawAsset { effects, .. }
|
||||
| Xcm::ReserveAssetDeposit { effects, .. }
|
||||
| Xcm::TeleportAsset { effects, .. } => {
|
||||
| Xcm::TeleportAsset { effects, .. }
|
||||
=> {
|
||||
let inner: Weight = effects.iter_mut()
|
||||
.map(|effect| match effect {
|
||||
Order::BuyExecution { .. } => {
|
||||
|
||||
@@ -40,8 +40,12 @@ pub use config::Config;
|
||||
pub struct XcmExecutor<Config>(PhantomData<Config>);
|
||||
|
||||
impl<Config: config::Config> ExecuteXcm<Config::Call> for XcmExecutor<Config> {
|
||||
type Call = Config::Call;
|
||||
fn execute_xcm(origin: MultiLocation, message: Xcm<Config::Call>, weight_limit: Weight) -> Outcome {
|
||||
fn execute_xcm_in_credit(
|
||||
origin: MultiLocation,
|
||||
message: Xcm<Config::Call>,
|
||||
weight_limit: Weight,
|
||||
mut weight_credit: Weight,
|
||||
) -> Outcome {
|
||||
// TODO: #2841 #HARDENXCM We should identify recursive bombs here and bail.
|
||||
let mut message = Xcm::<Config::Call>::from(message);
|
||||
let shallow_weight = match Config::Weigher::shallow(&mut message) {
|
||||
@@ -60,7 +64,7 @@ impl<Config: config::Config> ExecuteXcm<Config::Call> for XcmExecutor<Config> {
|
||||
return Outcome::Error(XcmError::WeightLimitReached(maximum_weight));
|
||||
}
|
||||
let mut trader = Config::Trader::new();
|
||||
let result = Self::do_execute_xcm(origin, true, message, &mut 0, Some(shallow_weight), &mut trader);
|
||||
let result = Self::do_execute_xcm(origin, true, message, &mut weight_credit, Some(shallow_weight), &mut trader);
|
||||
drop(trader);
|
||||
match result {
|
||||
Ok(surplus) => Outcome::Complete(maximum_weight.saturating_sub(surplus)),
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use sp_std::result::Result;
|
||||
use xcm::v0::{Xcm, MultiAsset, Error};
|
||||
use xcm::v0::{Xcm, MultiAsset, MultiLocation, Error};
|
||||
use frame_support::weights::Weight;
|
||||
use crate::Assets;
|
||||
|
||||
@@ -43,6 +43,18 @@ pub trait WeightBounds<Call> {
|
||||
/// any internal effects. Inner XCM messages may be executed by:
|
||||
/// - Order::BuyExecution
|
||||
fn deep(message: &mut Xcm<Call>) -> Result<Weight, ()>;
|
||||
|
||||
/// Return the total weight for executing `message`.
|
||||
fn weight(message: &mut Xcm<Call>) -> Result<Weight, ()> {
|
||||
Self::shallow(message)?.checked_add(Self::deep(message)?).ok_or(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A means of getting approximate weight consumption for a given destination message executor and a
|
||||
/// message.
|
||||
pub trait UniversalWeigher {
|
||||
/// Get the upper limit of weight required for `dest` to execute `message`.
|
||||
fn weigh(dest: MultiLocation, message: Xcm<()>) -> Result<Weight, ()>;
|
||||
}
|
||||
|
||||
/// Charge for weight in order to execute XCM.
|
||||
|
||||
Reference in New Issue
Block a user