Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions runtime/kusama/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1288,6 +1288,7 @@ impl xcm_executor::Config for XcmConfig {
type Call = Call;
type XcmSender = XcmRouter;
type AssetTransactor = LocalAssetTransactor;
type HrmpChannelManager = Hrmp;
type OriginConverter = LocalOriginConverter;
type IsReserve = ();
type IsTeleporter = TrustedTeleporters;
Expand Down
21 changes: 21 additions & 0 deletions runtime/parachains/src/hrmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use sp_std::{
fmt, mem,
prelude::*,
};
use xcm::v0::{Error as XcmError, HrmpChannelManagementHooks};

pub use pallet::*;

Expand Down Expand Up @@ -467,6 +468,26 @@ pub mod pallet {
}
}

impl HrmpChannelManagementHooks for Pallet<T> {
type HrmpCall = pallet::Call<T>>;
fn hrmp_init_open_channel(
recipient: u32,
max_message_size: u32,
max_capacity: u32,
) -> Result<Self::HrmpCall, XcmError> {
Ok(pallet::Call::hrmp_init_open_channel(recipient.into(), max_capacity, max_message_size))
}
fn hrmp_accept_open_channel(sender: u32) -> Result<Self::HrmpCall, XcmError> {
Ok(pallet::Call::hrmp_accept_open_channel(sender.into()))
}
fn hrmp_close_channel(sender: u32, recipient: u32) -> Result<Self::HrmpCall, XcmError> {
Ok(pallet::Call::hrmp_close_channel(HrmpChannelId {
sender: sender.into(),
recipient: recipient.into(),
}))
}
}

#[cfg(feature = "std")]
fn initialize_storage<T: Config>(preopen_hrmp_channels: &[(ParaId, ParaId, u32, u32)]) {
let host_config = configuration::Pallet::<T>::config();
Expand Down
1 change: 1 addition & 0 deletions runtime/rococo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,7 @@ impl xcm_executor::Config for XcmConfig {
type Call = Call;
type XcmSender = XcmRouter;
type AssetTransactor = LocalAssetTransactor;
type HrmpChannelManager = Hrmp;
type OriginConverter = LocalOriginConverter;
type IsReserve = ();
type IsTeleporter = TrustedTeleporters;
Expand Down
1 change: 1 addition & 0 deletions runtime/westend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,7 @@ impl xcm_executor::Config for XcmConfig {
type Call = Call;
type XcmSender = XcmRouter;
type AssetTransactor = LocalAssetTransactor;
type HrmpChannelManager = Hrmp;
type OriginConverter = LocalOriginConverter;
type IsReserve = ();
type IsTeleporter = TrustedTeleporters;
Expand Down
4 changes: 4 additions & 0 deletions xcm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@ impl-trait-for-tuples = "0.2.0"
parity-scale-codec = { version = "2.0.0", default-features = false, features = [ "derive" ] }
derivative = {version = "2.2.0", default-features = false, features = [ "use_core" ] }
log = { version = "0.4.14", 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 }

[features]
default = ["std"]
wasm-api = []
std = [
"parity-scale-codec/std",
"sp-runtime/std",
"frame-support/std",
]
1 change: 1 addition & 0 deletions xcm/pallet-xcm/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ impl xcm_executor::Config for XcmConfig {
type Call = Call;
type XcmSender = TestSendXcm;
type AssetTransactor = LocalAssetTransactor;
type HrmpChannelManager = ();
type OriginConverter = LocalOriginConverter;
type IsReserve = ();
type IsTeleporter = ();
Expand Down
77 changes: 76 additions & 1 deletion xcm/src/v0/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ pub use junction::{BodyId, BodyPart, Junction, NetworkId};
pub use multi_asset::{AssetInstance, MultiAsset};
pub use multi_location::MultiLocation;
pub use order::Order;
pub use traits::{Error, ExecuteXcm, Outcome, Result, SendXcm};
pub use traits::{Error, ExecuteXcm, HrmpChannelManagementHooks, Outcome, Result, SendXcm};

/// A prelude for importing all types typically used when interacting with XCM messages.
pub mod prelude {
Expand Down Expand Up @@ -262,6 +262,64 @@ pub enum Xcm<Call> {
recipient: u32,
},

/// A message to propose opening a channel on the relay-chain between the
/// sender para to the recipient para.
///
/// - `recipient`: The recipient in the to-be opened channel.
/// - `max_message_size`: The maximum size of a message proposed by the sender.
/// - `max_capacity`: The maximum number of messages that can be queued in the channel.
///
/// Safety: The message should originate directly from the sender para.
///
/// Kind: *Instruction*.
///
/// Errors:
HrmpInitOpenChannel {
origin_type: OriginKind,
require_weight_at_most: u64,
#[codec(compact)]
recipient: u32,
#[codec(compact)]
max_message_size: u32,
#[codec(compact)]
max_capacity: u32,
},

/// A message to accept opening a channel on the relay-chain.
///
/// - `sender`: The sender in the to-be opened channel.
///
/// Safety: The message should originate directly from the recipient para.
///
/// Kind: *Instruction*.
///
/// Errors:
HrmpAcceptOpenChannel {
origin_type: OriginKind,
require_weight_at_most: u64,
#[codec(compact)]
sender: u32,
},

/// A message to close a channel on the relay-chain.
///
/// - `sender`: The sender in the to-be closed channel.
/// - `recipient`: The recipient in the to-be closed channel.
///
/// Safety: The message should originate directly from the sender or
/// recipient para (either member of the channel).
///
/// Kind: *Instruction*.
///
/// Errors:
HrmpCloseChannel {
origin_type: OriginKind,
require_weight_at_most: u64,
#[codec(compact)]
sender: u32,
#[codec(compact)]
recipient: u32,
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recalling an open channel request is upcoming in #3543

I think it's worth to reconsider these messages in the light of that PR.

/// A message to indicate that the embedded XCM is actually arriving on behalf of some consensus
/// location within the origin.
///
Expand Down Expand Up @@ -314,6 +372,23 @@ impl<Call> Xcm<Call> {
HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient },
HrmpChannelClosing { initiator, sender, recipient } =>
HrmpChannelClosing { initiator, sender, recipient },
HrmpInitOpenChannel {
origin_type,
require_weight_at_most,
recipient,
max_message_size,
max_capacity,
} => HrmpInitOpenChannel {
origin_type,
require_weight_at_most,
recipient,
max_message_size,
max_capacity,
},
HrmpAcceptOpenChannel { origin_type, require_weight_at_most, sender } =>
HrmpAcceptOpenChannel { origin_type, require_weight_at_most, sender },
HrmpCloseChannel { origin_type, require_weight_at_most, sender, recipient } =>
HrmpCloseChannel { origin_type, require_weight_at_most, sender, recipient },
Transact { origin_type, require_weight_at_most, call } =>
Transact { origin_type, require_weight_at_most, call: call.into() },
RelayedFrom { who, message } =>
Expand Down
35 changes: 35 additions & 0 deletions xcm/src/v0/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

use core::result;
use parity_scale_codec::{Decode, Encode};
use sp_runtime::traits::Dispatchable;
use frame_support::weights::GetDispatchInfo;

use super::{MultiLocation, Xcm};

Expand Down Expand Up @@ -259,3 +261,36 @@ impl SendXcm for Tuple {
Err(Error::CannotReachDestination(destination, message))
}
}

/// These hooks expose HRMP channel management functionality to enable parachains
/// to send messages that propose opening channels, accept opening channels, and
/// close open channels.
/// Parachains should configure the default `()` implementation which returns `Error::Undefined`.
/// Relay chains will use the implementation in the `hrmp` pallet.
pub trait HrmpChannelManagementHooks {
type HrmpCall: Dispatchable + GetDispatchInfo;
fn hrmp_init_open_channel(
recipient: u32,
max_message_size: u32,
max_capacity: u32,
) -> result::Result<Self::HrmpCall, Error>;
fn hrmp_accept_open_channel(sender: u32) -> result::Result<Self::HrmpCall, Error>;
fn hrmp_close_channel(sender: u32, recipient: u32) -> result::Result<Self::HrmpCall, Error>;
}

impl HrmpChannelManagementHooks for () {
type HrmpCall = ();
fn hrmp_init_open_channel(
_recipient: u32,
_max_message_size: u32,
_max_capacity: u32,
) -> result::Result<(), Error> {
Err(().into())
}
fn hrmp_accept_open_channel(_sender: u32) -> result::Result<(), Error> {
Err(().into())
}
fn hrmp_close_channel(_sender: u32, _recipient: u32) -> result::Result<(), Error> {
Err(().into())
}
}
1 change: 1 addition & 0 deletions xcm/xcm-builder/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ impl Config for TestConfig {
type Call = TestCall;
type XcmSender = TestSendXcm;
type AssetTransactor = TestAssetTransactor;
type HrmpChannelManager = ();
type OriginConverter = TestOriginConverter;
type IsReserve = TestIsReserve;
type IsTeleporter = TestIsTeleporter;
Expand Down
5 changes: 4 additions & 1 deletion xcm/xcm-executor/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use frame_support::{
dispatch::{Dispatchable, Parameter},
weights::{GetDispatchInfo, PostDispatchInfo},
};
use xcm::v0::SendXcm;
use xcm::v0::{HrmpChannelManagementHooks, SendXcm};

/// The trait to parameterize the `XcmExecutor`.
pub trait Config {
Expand All @@ -35,6 +35,9 @@ pub trait Config {
/// How to withdraw and deposit an asset.
type AssetTransactor: TransactAsset;

/// Hooks to expose HRMP actions to XCM.
type HrmpChannelManager: HrmpChannelManagementHooks;

/// How to get a call origin from a `OriginKind` value.
type OriginConverter: ConvertOrigin<<Self::Call as Dispatchable>::Origin>;

Expand Down
107 changes: 105 additions & 2 deletions xcm/xcm-executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ use frame_support::{
};
use sp_std::{marker::PhantomData, prelude::*};
use xcm::v0::{
Error as XcmError, ExecuteXcm, MultiAsset, MultiLocation, Order, Outcome, Response, SendXcm,
Xcm,
Error as XcmError, ExecuteXcm, HrmpChannelManagementHooks, MultiAsset, MultiLocation, Order,
Outcome, Response, SendXcm, Xcm,
};

pub mod traits;
Expand Down Expand Up @@ -234,6 +234,109 @@ impl<Config: config::Config> XcmExecutor<Config> {
// execution has taken.
None
},
(
origin,
Xcm::HrmpInitOpenChannel {
origin_type,
require_weight_at_most,
recipient,
max_message_size,
max_capacity,
},
) => {
let call = Config::HrmpChannelManager::hrmp_init_open_channel(
recipient,
max_message_size,
max_capacity,
)?;
let dispatch_origin = Config::OriginConverter::convert_origin(origin, origin_type)
.map_err(|_| XcmError::BadOrigin)?;
let weight = call.get_dispatch_info().weight;
ensure!(weight <= require_weight_at_most, XcmError::TooMuchWeightRequired);
let actual_weight = match call.dispatch(dispatch_origin) {
Ok(post_info) => post_info.actual_weight,
Err(error_and_info) => {
// Not much to do with the result as it is. It's up to the parachain to ensure that the
// message makes sense.
error_and_info.post_info.actual_weight
},
}
.unwrap_or(weight);
let surplus = weight.saturating_sub(actual_weight);
// Credit any surplus weight that we bought. This should be safe since it's work we
// didn't realise that we didn't have to do.
// It works because we assume that the `Config::Weigher` will always count the `call`'s
// `get_dispatch_info` weight into its `shallow` estimate.
*weight_credit = weight_credit.saturating_add(surplus);
// Do the same for the total surplus, which is reported to the caller and eventually makes its way
// back up the stack to be subtracted from the deep-weight.
total_surplus = total_surplus.saturating_add(surplus);
// Return the overestimated amount so we can adjust our expectations on how much this entire
// execution has taken.
None
},
(
origin,
Xcm::HrmpAcceptOpenChannel { origin_type, require_weight_at_most, sender },
) => {
let call = Config::HrmpChannelManager::hrmp_accept_open_channel(sender)?;
let dispatch_origin = Config::OriginConverter::convert_origin(origin, origin_type)
.map_err(|_| XcmError::BadOrigin)?;
let weight = call.get_dispatch_info().weight;
ensure!(weight <= require_weight_at_most, XcmError::TooMuchWeightRequired);
let actual_weight = match call.dispatch(dispatch_origin) {
Ok(post_info) => post_info.actual_weight,
Err(error_and_info) => {
// Not much to do with the result as it is. It's up to the parachain to ensure that the
// message makes sense.
error_and_info.post_info.actual_weight
},
}
.unwrap_or(weight);
let surplus = weight.saturating_sub(actual_weight);
// Credit any surplus weight that we bought. This should be safe since it's work we
// didn't realise that we didn't have to do.
// It works because we assume that the `Config::Weigher` will always count the `call`'s
// `get_dispatch_info` weight into its `shallow` estimate.
*weight_credit = weight_credit.saturating_add(surplus);
// Do the same for the total surplus, which is reported to the caller and eventually makes its way
// back up the stack to be subtracted from the deep-weight.
total_surplus = total_surplus.saturating_add(surplus);
// Return the overestimated amount so we can adjust our expectations on how much this entire
// execution has taken.
None
},
(
origin,
Xcm::HrmpCloseChannel { origin_type, require_weight_at_most, sender, recipient },
) => {
let call = Config::HrmpChannelManager::hrmp_close_channel(sender, recipient)?;
let dispatch_origin = Config::OriginConverter::convert_origin(origin, origin_type)
.map_err(|_| XcmError::BadOrigin)?;
let weight = call.get_dispatch_info().weight;
ensure!(weight <= require_weight_at_most, XcmError::TooMuchWeightRequired);
let actual_weight = match call.dispatch(dispatch_origin) {
Ok(post_info) => post_info.actual_weight,
Err(error_and_info) => {
// Not much to do with the result as it is. It's up to the parachain to ensure that the
// message makes sense.
error_and_info.post_info.actual_weight
},
}
.unwrap_or(weight);
let surplus = weight.saturating_sub(actual_weight);
// Credit any surplus weight that we bought. This should be safe since it's work we
// didn't realise that we didn't have to do.
// It works because we assume that the `Config::Weigher` will always count the `call`'s
// `get_dispatch_info` weight into its `shallow` estimate.
*weight_credit = weight_credit.saturating_add(surplus);
// Do the same for the total surplus, which is reported to the caller and eventually makes its way
// back up the stack to be subtracted from the deep-weight.
total_surplus = total_surplus.saturating_add(surplus);
// Return the overestimated amount so we can adjust our expectations on how much this entire
// execution has taken.
None
},
(origin, Xcm::QueryResponse { query_id, response }) => {
Config::ResponseHandler::on_response(origin, query_id, response);
None
Expand Down
1 change: 1 addition & 0 deletions xcm/xcm-simulator/example/src/parachain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ impl Config for XcmConfig {
type Call = Call;
type XcmSender = XcmRouter;
type AssetTransactor = LocalAssetTransactor;
type HrmpChannelManager = ();
type OriginConverter = XcmOriginToCallOrigin;
type IsReserve = NativeAsset;
type IsTeleporter = ();
Expand Down
Loading