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

XCM v3: Bridge infrastructure #4681

Merged
merged 65 commits into from
Feb 14, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
665bd6c
XCM bridge infrastructure
gavofyork Oct 30, 2021
535980e
Missing bit of cherry-pick
gavofyork Jan 10, 2022
d4376f1
Revamped XCM proc macros; new NetworkIds
gavofyork Oct 31, 2021
f093c55
Fixes
gavofyork Oct 31, 2021
bb939e8
Formatting
gavofyork Oct 31, 2021
ec2b72d
ExportMessage instruction and config type
gavofyork Oct 31, 2021
6878ed3
Add MessageExporter definitions
gavofyork Oct 31, 2021
270b662
Formatting
gavofyork Oct 31, 2021
bba850d
Missing files
gavofyork Oct 31, 2021
73e4758
Fixes
gavofyork Oct 31, 2021
4bef607
Initial bridging config API
gavofyork Oct 31, 2021
c0edea0
Allow for two-stage XCM execution
gavofyork Nov 2, 2021
128363e
Update xcm/src/v3/mod.rs
gavofyork Nov 2, 2021
4eb42d6
XCM crate building again
gavofyork Jan 10, 2022
08c41fa
Initial bridging primitive
gavofyork Jan 17, 2022
562b08b
Docs
gavofyork Jan 17, 2022
83adc05
Merge branch 'gav-xcm-v3' into gav-xcm-v3-bridging
gavofyork Jan 17, 2022
5ac926a
Docs
gavofyork Jan 18, 2022
b2dc3f1
More work
gavofyork Jan 20, 2022
4d8c9a8
More work
gavofyork Jan 20, 2022
a837427
Merge branch 'master' into gav-xcm-v3
gavofyork Jan 22, 2022
cacaf4c
Merge branch 'gav-xcm-v3' into gav-xcm-v3-bridging
gavofyork Jan 22, 2022
4a8fc7f
Merge branch 'gav-xcm-v3' into gav-xcm-v3-bridging
gavofyork Jan 22, 2022
449fe35
Merge branch 'gav-xcm-v3-bridging' of github.com:paritytech/polkadot …
gavofyork Jan 22, 2022
1723ae9
Make build
gavofyork Jan 22, 2022
30fbd39
WithComputedOrigin and SovereignPaidRemoteExporter
gavofyork Jan 23, 2022
f75c343
Remove TODOs
gavofyork Jan 28, 2022
fc9fa04
Merge remote-tracking branch 'origin/gav-xcm-v3' into gav-xcm-v3-brid…
gavofyork Jan 28, 2022
197ec2e
Merge branch 'gav-xcm-v3' into gav-xcm-v3-bridging
gavofyork Jan 31, 2022
8af0a3a
Slim bridge API and tests.
gavofyork Jan 31, 2022
caf33cb
Fixes
gavofyork Jan 31, 2022
347b32e
More work
gavofyork Feb 2, 2022
8ef2b84
First bridge test passing
gavofyork Feb 2, 2022
b459cfc
Formatting
gavofyork Feb 2, 2022
b2d3fdf
Another test
gavofyork Feb 2, 2022
ca031c2
Next round of bridging tests
gavofyork Feb 2, 2022
870b109
Repot tests
gavofyork Feb 2, 2022
c68bbc8
Cleanups
gavofyork Feb 2, 2022
1724115
Paid bridging
gavofyork Feb 2, 2022
cc9c35f
Formatting
gavofyork Feb 2, 2022
ac24184
Tests
gavofyork Feb 4, 2022
b90d041
Spelling
gavofyork Feb 4, 2022
7310377
Formatting
gavofyork Feb 4, 2022
d5b6f27
Fees and refactoring
gavofyork Feb 4, 2022
6537401
Fixes
gavofyork Feb 4, 2022
f2f844e
Formatting
gavofyork Feb 4, 2022
cfed333
Refactor SendXcm to become two-phase
gavofyork Feb 5, 2022
450f529
Fix tests
gavofyork Feb 5, 2022
7525c01
Refactoring of SendXcm and ExportXcm complete
gavofyork Feb 7, 2022
e715ef2
Formatting
gavofyork Feb 7, 2022
59768bd
Rename CannotReachDestination -> NotApplicable
gavofyork Feb 7, 2022
18f1100
Remove XCM v0
gavofyork Feb 7, 2022
087ac70
Minor grumbles
gavofyork Feb 7, 2022
9c9c38f
Formatting
gavofyork Feb 8, 2022
ca0d360
Formatting
gavofyork Feb 8, 2022
c4bc44a
Merge branch 'gav-xcm-v3-bridging' of github.com:paritytech/polkadot …
gavofyork Feb 8, 2022
3570fb4
Fixes
gavofyork Feb 8, 2022
45a697c
Fixes
gavofyork Feb 8, 2022
e28c84c
Cleanup XCM config
gavofyork Feb 9, 2022
5247473
Fee handling
gavofyork Feb 9, 2022
d68d61d
Merge remote-tracking branch 'origin/gav-xcm-v3' into gav-xcm-v3-brid…
gavofyork Feb 14, 2022
6ef1f0e
Fixes
gavofyork Feb 14, 2022
faa7463
Formatting
gavofyork Feb 14, 2022
ad5c941
Fixes
gavofyork Feb 14, 2022
5ed0737
Bump
gavofyork Feb 14, 2022
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
Prev Previous commit
Next Next commit
More work
  • Loading branch information
gavofyork committed Jan 20, 2022
commit b2dc3f13df69a00247af6f6bb59d429b0db02ba4
1 change: 1 addition & 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 xcm/xcm-builder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ description = "Tools & types for building with XCM and its executor."
version = "0.9.13"

[dependencies]
impl-trait-for-tuples = "0.2.1"
parity-scale-codec = { version = "2.3.1", default-features = false, features = ["derive"] }
scale-info = { version = "1.0", default-features = false, features = ["derive"] }
xcm = { path = "..", default-features = false }
Expand Down
159 changes: 151 additions & 8 deletions xcm/xcm-builder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,17 +121,33 @@ mod universal_exports {
assert_eq!(x, Err((Parent, Polkadot, Parachain(1000)).into()));
}

/// Implementation of `SendXcm` which uses the given `ExportXcm` impl in order to forward the
/// message over a bridge.
///
/// The actual message forwarded over the bridge is prepended with `UniversalOrigin` and
/// `DescendOrigin` in order to ensure that the message is executed with this Origin.
///
/// No effort is made to charge for any bridge fees, so this can only be used when it is known
/// that the message sending cannot be abused in any way.
pub struct LocalUnpaidExporter<Exporter, Ancestry>(PhantomData<(Exporter, Ancestry)>);
impl<Exporter: ExportXcm, Ancestry: Get<InteriorMultiLocation>> SendXcm for LocalUnpaidExporter<Exporter, Ancestry> {
fn send_xcm(dest: impl Into<MultiLocation>, message: Xcm<()>) -> SendResult {
let (network, destination, _, _) = match ensure_is_remote(Ancestry::get(), dest) {
fn send_xcm(dest: impl Into<MultiLocation>, xcm: Xcm<()>) -> SendResult {
let devolved = match ensure_is_remote(Ancestry::get(), dest) {
Ok(x) => x,
Err(dest) => return Err(SendError::CannotReachDestination(dest, message)),
Err(dest) => return Err(SendError::CannotReachDestination(dest, xcm)),
};
let (network, destination, local_network, local_location) = devolved;
let mut message: Xcm<()> = vec![
UniversalOrigin(GlobalConsensus(local_network)),
DescendOrigin(local_location),
].into();
message.inner_mut().extend(xcm.into_iter());
Exporter::export_xcm(network, 0, destination, message)
}
}

/// Alternative implentation of `LocalUnpaidExporter` which uses the `ExportMessage`
/// instruction executing locally.
pub struct LocalUnpaidExecutingExporter<
Executer,
Ancestry,
Expand All @@ -144,6 +160,135 @@ mod universal_exports {
WeightLimit: Get<u64>,
Call,
> SendXcm for LocalUnpaidExecutingExporter<Executer, Ancestry, WeightLimit, Call> {
fn send_xcm(dest: impl Into<MultiLocation>, xcm: Xcm<()>) -> SendResult {
let dest = dest.into();

// TODO: proper matching so we can be sure that it's the only viable send_xcm before we
// attempt and thus can acceptably consume dest & xcm.
let err = Err(SendError::CannotReachDestination(dest.clone(), xcm.clone()));

let devolved = match ensure_is_remote(Ancestry::get(), dest) {
Ok(x) => x,
Err(_) => return err,
};
let (remote_network, remote_location, local_network, local_location) = devolved;

let mut inner_xcm: Xcm<()> = vec![
UniversalOrigin(GlobalConsensus(local_network)),
DescendOrigin(local_location),
].into();
inner_xcm.inner_mut().extend(xcm.into_iter());

let message = Xcm(vec![ ExportMessage {
network: remote_network,
destination: remote_location,
xcm: inner_xcm,
} ]);
let pre = match Executer::prepare(message) {
Ok(x) => x,
Err(_) => return err,
};
// We just swallow the weight - it should be constant.
let weight_credit = pre.weight_of();
match Executer::execute(Here, pre, weight_credit) {
Outcome::Complete(_) => Ok(()),
_ => return err,
}
}
}

// TODO: `LocalPaidExecutingExporter` able to accept from non-`Here`, but local, origins.

pub trait ExporterFor {
fn exporter_for(network: &NetworkId, remote_location: &InteriorMultiLocation) -> Option<MultiLocation>;
}

#[impl_trait_for_tuples::impl_for_tuples(30)]
impl ExporterFor for Tuple {
fn exporter_for(network: &NetworkId, remote_location: &InteriorMultiLocation) -> Option<MultiLocation> {
for_tuples!( #(
if let Some(r) = Tuple::exporter_for(network, remote_location) {
return Some(r);
}
)* );
None
}
}

pub struct NetworkExportTable<T>(sp_std::marker::PhantomData<T>);
impl<T: Get<&'static [(NetworkId, MultiLocation)]>> ExporterFor for NetworkExportTable<T> {
fn exporter_for(network: &NetworkId, _: &InteriorMultiLocation) -> Option<MultiLocation> {
T::get().iter().find(|(ref j, _)| j == network).map(|(_, l)| l.clone())
}
}

/// Implementation of `SendXcm` which wraps the message inside an `ExportMessage` instruction
/// and sends it to a destination known to be able to handle it.
///
/// No effort is made to make payment to the bridge for its services, so the bridge location
/// must have been configured with a barrier rule allowing unpaid execution for this message
/// coming from our origin.
///
/// The actual message send to the bridge for forwarding is prepended with `UniversalOrigin`
/// and `DescendOrigin` in order to ensure that the message is executed with our Origin.
pub struct UnpaidRemoteExporter<
Bridges,
Router,
Ancestry,
>(PhantomData<(Bridges, Router, Ancestry)>);
impl<
Bridges: ExporterFor,
Router: SendXcm,
Ancestry: Get<InteriorMultiLocation>,
> SendXcm for UnpaidRemoteExporter<Bridges, Router, Ancestry> {
fn send_xcm(dest: impl Into<MultiLocation>, xcm: Xcm<()>) -> SendResult {
let dest = dest.into();

// TODO: proper matching so we can be sure that it's the only viable send_xcm before we
// attempt and thus can acceptably consume dest & xcm.
let err = SendError::CannotReachDestination(dest.clone(), xcm.clone());

let devolved = ensure_is_remote(Ancestry::get(), dest).map_err(|_| err.clone())?;
let (remote_network, remote_location, local_network, local_location) = devolved;

let bridge = Bridges::exporter_for(&remote_network, &remote_location).ok_or(err)?;

let mut inner_xcm: Xcm<()> = vec![
UniversalOrigin(GlobalConsensus(local_network)),
DescendOrigin(local_location),
].into();
inner_xcm.inner_mut().extend(xcm.into_iter());
let message = Xcm(vec![
ExportMessage {
network: remote_network,
destination: remote_location,
xcm: inner_xcm,
},
]);
Router::send_xcm(bridge, message)
}
}
/*
/// Implementation of `SendXcm` which wraps the message inside an `ExportMessage` instruction
/// and sends it to a destination known to be able to handle it.
///
/// No effort is made to make payment to the bridge for its services, so the bridge location
/// must have been configured with a barrier rule allowing this message unpaid execution.
///
/// The actual message send to the bridge for forwarding is prepended with `UniversalOrigin`
/// and `DescendOrigin` in order to ensure that the message is executed with this Origin.
pub struct PaidRemoteExporter<
Executer,
Ancestry,
WeightLimit,
Call,
>(PhantomData<(Executer, Ancestry, WeightLimit, Call)>);
impl<
Executer: ExecuteXcm<Call>,
Ancestry: Get<InteriorMultiLocation>,
WeightLimit: Get<u64>,
Call,
> SendXcm for LocalPaidExecutingExporter<Executer, Ancestry, WeightLimit, Call> {
fn send_xcm(dest: impl Into<MultiLocation>, xcm: Xcm<()>) -> SendResult {
let dest = dest.into();

Expand All @@ -164,10 +309,10 @@ mod universal_exports {
inner_xcm.inner_mut().extend(xcm.into_iter());

let message = Xcm(vec![
/* WithdrawAsset((Here, )),
WithdrawAsset((Here, ).into()),
BuyExecution { fees: Wild(AllCounted(1)), weight_limit: Unlimited },
DepositAsset { assets: Wild(AllCounted(1)), beneficiary: Here.into() },
*/ ExportMessage { network: remote_network, destination: remote_location, xcm: inner_xcm },
ExportMessage { network: remote_network, destination: remote_location, xcm: inner_xcm },
]);
let pre = match Executer::prepare(message) {
Ok(x) => x,
Expand All @@ -181,7 +326,5 @@ mod universal_exports {
}
}
}

// TODO: LocalPaidExecutingExporter able to accept from non-Here origins.
// TODO: RemotePaidExecutingExporter which uses `SendXcm`.
*/
}