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

[xcm] Extend haul_blob with Channel + include NetworkId to channel id (origin/(network, destination)) #7244

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
4 changes: 2 additions & 2 deletions xcm/xcm-builder/src/tests/bridging/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::{universal_exports::*, WithTopicSource};
use frame_support::{parameter_types, traits::Get};
use std::{cell::RefCell, marker::PhantomData};
use xcm_executor::{
traits::{export_xcm, validate_export},
traits::{export_xcm, validate_export, Channel},
XcmExecutor,
};
use SendError::*;
Expand Down Expand Up @@ -112,7 +112,7 @@ impl<D: DispatchBlob> TestBridge<D> {
}
}
impl<D: DispatchBlob> HaulBlob for TestBridge<D> {
fn haul_blob(blob: Vec<u8>) -> Result<(), HaulBlobError> {
fn haul_blob(blob: Vec<u8>, _channel: Channel) -> Result<(), HaulBlobError> {
BRIDGE_TRAFFIC.with(|t| t.borrow_mut().push(blob));
Ok(())
}
Expand Down
2 changes: 1 addition & 1 deletion xcm/xcm-builder/src/tests/origins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ fn export_message_should_work() {
let uni_src = (ByGenesis([0; 32]), Parachain(42), Parachain(1)).into();
assert_eq!(
exported_xcm(),
vec![(Polkadot, 403611790, uni_src, Here, expected_message, expected_hash)]
vec![(Polkadot, 470110423, uni_src, Here, expected_message, expected_hash)]
);
}

Expand Down
16 changes: 8 additions & 8 deletions xcm/xcm-builder/src/universal_exports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use frame_support::{ensure, traits::Get};
use parity_scale_codec::{Decode, Encode};
use sp_std::{convert::TryInto, marker::PhantomData, prelude::*};
use xcm::prelude::*;
use xcm_executor::traits::{validate_export, ExportXcm};
use xcm_executor::traits::{validate_export, Channel, ExportXcm};
use SendError::*;

/// Returns the network ID and consensus location within that network of the remote
Expand Down Expand Up @@ -295,7 +295,7 @@ pub trait DispatchBlob {

pub trait HaulBlob {
/// Sends a blob over some point-to-point link. This will generally be implemented by a bridge.
fn haul_blob(blob: Vec<u8>) -> Result<(), HaulBlobError>;
fn haul_blob(blob: Vec<u8>, channel: Channel) -> Result<(), HaulBlobError>;
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -365,15 +365,15 @@ pub struct HaulBlobExporter<Bridge, BridgedNetwork, Price>(
impl<Bridge: HaulBlob, BridgedNetwork: Get<NetworkId>, Price: Get<MultiAssets>> ExportXcm
for HaulBlobExporter<Bridge, BridgedNetwork, Price>
{
type Ticket = (Vec<u8>, XcmHash);
type Ticket = (Vec<u8>, XcmHash, Channel);

fn validate(
network: NetworkId,
_channel: u32,
channel: Channel,
universal_source: &mut Option<InteriorMultiLocation>,
destination: &mut Option<InteriorMultiLocation>,
message: &mut Option<Xcm<()>>,
) -> Result<((Vec<u8>, XcmHash), MultiAssets), SendError> {
) -> Result<(Self::Ticket, MultiAssets), SendError> {
let bridged_network = BridgedNetwork::get();
ensure!(&network == &bridged_network, SendError::NotApplicable);
// We don't/can't use the `channel` for this adapter.
Expand Down Expand Up @@ -402,11 +402,11 @@ impl<Bridge: HaulBlob, BridgedNetwork: Get<NetworkId>, Price: Get<MultiAssets>>
let message = VersionedXcm::from(message);
let id = maybe_id.unwrap_or_else(|| message.using_encoded(sp_io::hashing::blake2_256));
let blob = BridgeMessage { universal_dest, message }.encode();
Ok(((blob, id), Price::get()))
Ok(((blob, id, channel), Price::get()))
}

fn deliver((blob, id): (Vec<u8>, XcmHash)) -> Result<XcmHash, SendError> {
Bridge::haul_blob(blob)?;
fn deliver((blob, id, channel): Self::Ticket) -> Result<XcmHash, SendError> {
Bridge::haul_blob(blob, channel)?;
Ok(id)
}
}
Expand Down
15 changes: 5 additions & 10 deletions xcm/xcm-executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,17 @@ use frame_support::{
ensure,
traits::{Contains, ContainsPair, Get, PalletsInfoAccess},
};
use parity_scale_codec::{Decode, Encode};
use parity_scale_codec::Encode;
use sp_core::defer;
use sp_io::hashing::blake2_128;
use sp_std::{marker::PhantomData, prelude::*};
use sp_weights::Weight;
use xcm::latest::prelude::*;

pub mod traits;
use traits::{
validate_export, AssetExchange, AssetLock, CallDispatcher, ClaimAssets, ConvertOrigin,
DropAssets, Enact, ExportXcm, FeeManager, FeeReason, OnResponse, Properties, ShouldExecute,
TransactAsset, VersionChangeNotifier, WeightBounds, WeightTrader,
channel_from_params, validate_export, AssetExchange, AssetLock, CallDispatcher, ClaimAssets,
ConvertOrigin, DropAssets, Enact, ExportXcm, FeeManager, FeeReason, OnResponse, Properties,
ShouldExecute, TransactAsset, VersionChangeNotifier, WeightBounds, WeightTrader,
};

mod assets;
Expand Down Expand Up @@ -834,11 +833,7 @@ impl<Config: config::Config> XcmExecutor<Config> {
let universal_source = Config::UniversalLocation::get()
.within_global(origin)
.map_err(|()| XcmError::Unanchored)?;
let hash = (self.origin_ref(), &destination).using_encoded(blake2_128);
let channel = u32::decode(&mut hash.as_ref()).unwrap_or(0);
// Hash identifies the lane on the exporter which we use. We use the pairwise
// combination of the origin and destination to ensure origin/destination pairs will
// generally have their own lanes.
let channel = channel_from_params(self.origin_ref(), &network, &destination);
let (ticket, fee) = validate_export::<Config::MessageExporter>(
network,
channel,
Expand Down
62 changes: 58 additions & 4 deletions xcm/xcm-executor/src/traits/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,24 @@

use xcm::latest::prelude::*;

/// An identifier for a channel.
pub type Channel = u32;

/// Generates channel identifier for `origin/(network, destination)` combination to ensure using separated lanes.
Copy link
Contributor

Choose a reason for hiding this comment

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

Destination network or source network?

pub fn channel_from_params(
origin_ref: Option<&MultiLocation>,
network: &NetworkId,
destination: &InteriorMultiLocation,
) -> Channel {
use parity_scale_codec::{Decode, Encode};
// Hash identifies the lane on the exporter which we use. We use the pairwise
// combination of the origin and (network, destination) to ensure origin/(network, destination) pairs will
// generally have their own lanes.
let hash = (origin_ref, (network, destination)).using_encoded(sp_io::hashing::blake2_256);
let channel = u32::decode(&mut hash.as_ref()).unwrap_or(0);
channel
}

/// Utility for delivering a message to a system under a different (non-local) consensus with a
/// spoofed origin. This essentially defines the behaviour of the `ExportMessage` XCM instruction.
///
Expand Down Expand Up @@ -50,7 +68,7 @@ pub trait ExportXcm {
/// early without trying alternative means of delivery.
fn validate(
network: NetworkId,
channel: u32,
channel: Channel,
universal_source: &mut Option<InteriorMultiLocation>,
destination: &mut Option<InteriorMultiLocation>,
message: &mut Option<Xcm<()>>,
Expand All @@ -70,7 +88,7 @@ impl ExportXcm for Tuple {

fn validate(
network: NetworkId,
channel: u32,
channel: Channel,
universal_source: &mut Option<InteriorMultiLocation>,
destination: &mut Option<InteriorMultiLocation>,
message: &mut Option<Xcm<()>>,
Expand Down Expand Up @@ -111,7 +129,7 @@ impl ExportXcm for Tuple {
/// both in `Some` before passing them as as mutable references into `T::send_xcm`.
pub fn validate_export<T: ExportXcm>(
network: NetworkId,
channel: u32,
channel: Channel,
universal_source: InteriorMultiLocation,
dest: InteriorMultiLocation,
msg: Xcm<()>,
Expand All @@ -129,7 +147,7 @@ pub fn validate_export<T: ExportXcm>(
/// before actually doing the delivery.
pub fn export_xcm<T: ExportXcm>(
network: NetworkId,
channel: u32,
channel: Channel,
universal_source: InteriorMultiLocation,
dest: InteriorMultiLocation,
msg: Xcm<()>,
Expand All @@ -144,3 +162,39 @@ pub fn export_xcm<T: ExportXcm>(
let hash = T::deliver(ticket)?;
Ok((hash, price))
}

#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashSet;

#[test]
fn channel_from_params_works() {
let params: Vec<(Option<MultiLocation>, &NetworkId, &InteriorMultiLocation)> = vec![
// different interior
(None, &ByGenesis([0; 32]), &X1(Parachain(1234))),
(None, &ByGenesis([0; 32]), &X1(Parachain(1235))),
// different networkId
(None, &ByGenesis([0; 32]), &X1(Parachain(1236))),
(None, &ByGenesis([1; 32]), &X1(Parachain(1236))),
// different origin
(None, &ByGenesis([0; 32]), &X1(Parachain(1237))),
(Some(MultiLocation::here()), &ByGenesis([0; 32]), &X1(Parachain(1237))),
(Some(MultiLocation::parent()), &ByGenesis([0; 32]), &X1(Parachain(1237))),
];

// check unique
let channels: HashSet<Channel> =
HashSet::from_iter(params.iter().map(|(origin, network, interior)| {
channel_from_params(origin.as_ref(), network, interior)
}));
assert_eq!(params.len(), channels.len());

// check not random
assert_eq!(
channel_from_params(None, &ByGenesis([0; 32]), &X1(Parachain(1234))),
channel_from_params(None, &ByGenesis([0; 32]), &X1(Parachain(1234)))
);
assert_eq!(channel_from_params(Some(&Parachain(1).into()), &Polkadot, &Here), 470110423);
}
}
2 changes: 1 addition & 1 deletion xcm/xcm-executor/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub use asset_lock::{AssetLock, Enact, LockError};
mod asset_exchange;
pub use asset_exchange::AssetExchange;
mod export;
pub use export::{export_xcm, validate_export, ExportXcm};
pub use export::{channel_from_params, export_xcm, validate_export, Channel, ExportXcm};
mod fee_manager;
pub use fee_manager::{FeeManager, FeeReason};
mod filter_asset_location;
Expand Down