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

Commit

Permalink
XCM v3: Bridge infrastructure (#4681)
Browse files Browse the repository at this point in the history
* XCM bridge infrastructure

* Missing bit of cherry-pick

* Revamped XCM proc macros; new NetworkIds

* Fixes

* Formatting

* ExportMessage instruction and config type

* Add MessageExporter definitions

* Formatting

* Missing files

* Fixes

* Initial bridging config API

* Allow for two-stage XCM execution

* Update xcm/src/v3/mod.rs

Co-authored-by: Keith Yeung <[email protected]>

* XCM crate building again

* Initial bridging primitive

* Docs

* Docs

* More work

* More work

* Merge branch 'gav-xcm-v3' into gav-xcm-v3-bridging

* Make build

* WithComputedOrigin and SovereignPaidRemoteExporter

* Remove TODOs

* Slim bridge API and tests.

* Fixes

* More work

* First bridge test passing

* Formatting

* Another test

* Next round of bridging tests

* Repot tests

* Cleanups

* Paid bridging

* Formatting

* Tests

* Spelling

* Formatting

* Fees and refactoring

* Fixes

* Formatting

* Refactor SendXcm to become two-phase

* Fix tests

* Refactoring of SendXcm and ExportXcm complete

* Formatting

* Rename CannotReachDestination -> NotApplicable

* Remove XCM v0

* Minor grumbles

* Formatting

* Formatting

* Fixes

* Fixes

* Cleanup XCM config

* Fee handling

* Fixes

* Formatting

* Fixes

* Bump

Co-authored-by: Keith Yeung <[email protected]>
  • Loading branch information
gavofyork and KiChjang authored Feb 14, 2022
1 parent fdf6352 commit 6185cf3
Show file tree
Hide file tree
Showing 79 changed files with 5,242 additions and 3,475 deletions.
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.

2 changes: 1 addition & 1 deletion bridges/primitives/messages/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
[dependencies]
bitvec = { version = "0.20", default-features = false, features = ["alloc"] }
codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "bit-vec"] }
impl-trait-for-tuples = "0.2"
impl-trait-for-tuples = "0.2.2"
scale-info = { version = "1.0", default-features = false, features = ["bit-vec", "derive"] }
serde = { version = "1.0", optional = true, features = ["derive"] }

Expand Down
59 changes: 38 additions & 21 deletions runtime/common/src/xcm_sender.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,50 @@
//! XCM sender for relay chain.
use parity_scale_codec::Encode;
use runtime_parachains::{configuration, dmp};
use sp_std::marker::PhantomData;
use xcm::latest::prelude::*;
use primitives::v1::Id as ParaId;
use runtime_parachains::{
configuration::{self, HostConfiguration},
dmp,
};
use sp_std::{marker::PhantomData, prelude::*};
use xcm::prelude::*;
use SendError::*;

/// XCM sender for relay chain. It only sends downward message.
pub struct ChildParachainRouter<T, W>(PhantomData<(T, W)>);

impl<T: configuration::Config + dmp::Config, W: xcm::WrapVersion> SendXcm
for ChildParachainRouter<T, W>
{
fn send_xcm(dest: impl Into<MultiLocation>, msg: Xcm<()>) -> SendResult {
let dest = dest.into();
match dest {
MultiLocation { parents: 0, interior: X1(Parachain(id)) } => {
// Downward message passing.
let versioned_xcm =
W::wrap_version(&dest, msg).map_err(|()| SendError::DestinationUnsupported)?;
let config = <configuration::Pallet<T>>::config();
<dmp::Pallet<T>>::queue_downward_message(
&config,
id.into(),
versioned_xcm.encode(),
)
.map_err(Into::<SendError>::into)?;
Ok(())
},
dest => Err(SendError::CannotReachDestination(dest, msg)),
}
type Ticket = (HostConfiguration<T::BlockNumber>, ParaId, Vec<u8>);

fn validate(
dest: &mut Option<MultiLocation>,
msg: &mut Option<Xcm<()>>,
) -> SendResult<(HostConfiguration<T::BlockNumber>, ParaId, Vec<u8>)> {
let d = dest.take().ok_or(MissingArgument)?;
let id = if let MultiLocation { parents: 0, interior: X1(Parachain(id)) } = &d {
*id
} else {
*dest = Some(d);
return Err(NotApplicable)
};

// Downward message passing.
let xcm = msg.take().ok_or(MissingArgument)?;
let config = <configuration::Pallet<T>>::config();
let para = id.into();
let blob = W::wrap_version(&d, xcm).map_err(|()| DestinationUnsupported)?.encode();
<dmp::Pallet<T>>::can_queue_downward_message(&config, &para, &blob)
.map_err(Into::<SendError>::into)?;

Ok(((config, para, blob), MultiAssets::new()))
}

fn deliver(
(config, para, blob): (HostConfiguration<T::BlockNumber>, ParaId, Vec<u8>),
) -> Result<(), SendError> {
<dmp::Pallet<T>>::queue_downward_message(&config, para, blob)
.map_err(|_| SendError::Transport(&"Error placing into DMP queue"))
}
}
46 changes: 27 additions & 19 deletions runtime/kusama/src/xcm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,19 @@ use xcm_builder::{
LocationInverter, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation,
TakeWeightCredit, UsingComponents,
};
use xcm_executor::XcmExecutor;

parameter_types! {
/// The location of the KSM token, from the context of this chain. Since this token is native to this
/// chain, we make it synonymous with it and thus it is the `Here` location, which means "equivalent to
/// the context".
pub const KsmLocation: MultiLocation = Here.into();
pub const TokenLocation: MultiLocation = Here.into_location();
/// The Kusama network ID. This is named.
pub const KusamaNetwork: NetworkId = NetworkId::Kusama;
/// Our XCM location ancestry - i.e. what, if anything, `Parent` means evaluated in our context. Since
/// Kusama is a top-level relay-chain, there is no ancestry.
pub const Ancestry: MultiLocation = Here.into();
pub const ThisNetwork: NetworkId = Kusama;
/// Our XCM location ancestry - i.e. our location within the Consensus Universe.
///
/// Since Kusama is a top-level relay-chain with its own consensus, it's just our network ID.
pub UniversalLocation: InteriorMultiLocation = ThisNetwork::get().into();
/// The check account, which holds any native assets that have been teleported out and not back in (yet).
pub CheckAccount: AccountId = XcmPallet::check_account();
}
Expand All @@ -56,18 +58,18 @@ pub type SovereignAccountOf = (
// We can convert a child parachain using the standard `AccountId` conversion.
ChildParachainConvertsVia<ParaId, AccountId>,
// We can directly alias an `AccountId32` into a local account.
AccountId32Aliases<KusamaNetwork, AccountId>,
AccountId32Aliases<ThisNetwork, AccountId>,
);

/// Our asset transactor. This is what allows us to interest with the runtime facilities from the point of
/// view of XCM-only concepts like `MultiLocation` and `MultiAsset`.
///
/// Ours is only aware of the Balances pallet, which is mapped to `KsmLocation`.
/// Ours is only aware of the Balances pallet, which is mapped to `TokenLocation`.
pub type LocalAssetTransactor = XcmCurrencyAdapter<
// Use this currency:
Balances,
// Use this currency when it is a fungible asset matching the given location or name:
IsConcrete<KsmLocation>,
IsConcrete<TokenLocation>,
// We can convert the MultiLocations with our converter above:
SovereignAccountOf,
// Our chain's account ID type (we can't get away without mentioning it explicitly):
Expand All @@ -76,14 +78,14 @@ pub type LocalAssetTransactor = XcmCurrencyAdapter<
CheckAccount,
>;

/// The means that we convert an the XCM message origin location into a local dispatch origin.
/// The means that we convert the XCM message origin location into a local dispatch origin.
type LocalOriginConverter = (
// A `Signed` origin of the sovereign account that the original location controls.
SovereignSignedViaLocation<SovereignAccountOf, Origin>,
// A child parachain, natively expressed, has the `Parachain` origin.
ChildParachainAsNative<parachains_origin::Origin, Origin>,
// The AccountId32 location type can be expressed natively as a `Signed` origin.
SignedAccountId32AsNative<KusamaNetwork, Origin>,
SignedAccountId32AsNative<ThisNetwork, Origin>,
// A system child parachain, expressed as a Superuser, converts to the `Root` origin.
ChildSystemParachainAsSuperuser<ParaId, Origin>,
);
Expand All @@ -104,13 +106,13 @@ pub type XcmRouter = (
);

parameter_types! {
pub const Kusama: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(KsmLocation::get()) });
pub const KusamaForStatemine: (MultiAssetFilter, MultiLocation) = (Kusama::get(), Parachain(1000).into());
pub const KusamaForEncointer: (MultiAssetFilter, MultiLocation) = (Kusama::get(), Parachain(1001).into());
pub const Ksm: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) });
pub const KsmForStatemine: (MultiAssetFilter, MultiLocation) = (Ksm::get(), Parachain(1000).into_location());
pub const KsmForEncointer: (MultiAssetFilter, MultiLocation) = (Ksm::get(), Parachain(1001).into_location());
pub const MaxAssetsIntoHolding: u32 = 64;
}
pub type TrustedTeleporters =
(xcm_builder::Case<KusamaForStatemine>, xcm_builder::Case<KusamaForEncointer>);
(xcm_builder::Case<KsmForStatemine>, xcm_builder::Case<KsmForEncointer>);

match_type! {
pub type OnlyParachains: impl Contains<MultiLocation> = {
Expand Down Expand Up @@ -140,17 +142,22 @@ impl xcm_executor::Config for XcmConfig {
type OriginConverter = LocalOriginConverter;
type IsReserve = ();
type IsTeleporter = TrustedTeleporters;
type LocationInverter = LocationInverter<Ancestry>;
type LocationInverter = LocationInverter<UniversalLocation>;
type Barrier = Barrier;
type Weigher = FixedWeightBounds<BaseXcmWeight, Call, MaxInstructions>;
// The weight trader piggybacks on the existing transaction-fee conversion logic.
type Trader = UsingComponents<WeightToFee, KsmLocation, AccountId, Balances, ToAuthor<Runtime>>;
type Trader =
UsingComponents<WeightToFee, TokenLocation, AccountId, Balances, ToAuthor<Runtime>>;
type ResponseHandler = XcmPallet;
type AssetTrap = XcmPallet;
type AssetClaims = XcmPallet;
type SubscriptionService = XcmPallet;
type PalletInstancesInfo = AllPalletsWithSystem;
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
type FeeManager = ();
// No bridges yet...
type MessageExporter = ();
type UniversalAliases = Nothing;
}

parameter_types! {
Expand All @@ -168,8 +175,9 @@ pub type LocalOriginToLocation = (
CouncilBodyId,
>,
// And a usual Signed origin to be used in XCM as a corresponding AccountId32
SignedToAccountId32<Origin, AccountId, KusamaNetwork>,
SignedToAccountId32<Origin, AccountId, ThisNetwork>,
);

impl pallet_xcm::Config for Runtime {
type Event = Event;
type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<Origin, LocalOriginToLocation>;
Expand All @@ -178,11 +186,11 @@ impl pallet_xcm::Config for Runtime {
type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin<Origin, LocalOriginToLocation>;
// ...but they must match our filter, which rejects all.
type XcmExecuteFilter = Nothing;
type XcmExecutor = xcm_executor::XcmExecutor<XcmConfig>;
type XcmExecutor = XcmExecutor<XcmConfig>;
type XcmTeleportFilter = Everything;
type XcmReserveTransferFilter = Everything;
type Weigher = FixedWeightBounds<BaseXcmWeight, Call, MaxInstructions>;
type LocationInverter = LocationInverter<Ancestry>;
type LocationInverter = LocationInverter<UniversalLocation>;
type Origin = Origin;
type Call = Call;
const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
Expand Down
15 changes: 15 additions & 0 deletions runtime/parachains/src/dmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,21 @@ impl<T: Config> Pallet<T> {
<Self as Store>::DownwardMessageQueueHeads::remove(outgoing_para);
}

/// Determine whether enqueuing a downward message to a specific recipient para would result
/// in an error. If this returns `Ok(())` the caller can be certain that a call to
/// `queue_downward_message` with the same parameters will be successful.
pub fn can_queue_downward_message(
config: &HostConfiguration<T::BlockNumber>,
_para: &ParaId,
msg: &DownwardMessage,
) -> Result<(), QueueDownwardMessageError> {
let serialized_len = msg.len() as u32;
if serialized_len > config.max_downward_message_size {
return Err(QueueDownwardMessageError::ExceedsMaxMessageSize)
}
Ok(())
}

/// Enqueue a downward message to a specific recipient para.
///
/// When encoded, the message should not exceed the `config.max_downward_message_size`.
Expand Down
43 changes: 23 additions & 20 deletions runtime/polkadot/src/xcm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,17 @@ use xcm_builder::{
IsConcrete, LocationInverter, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, TakeWeightCredit, UsingComponents,
};
use xcm_executor::XcmExecutor;

parameter_types! {
/// The location of the DOT token, from the context of this chain. Since this token is native to this
/// chain, we make it synonymous with it and thus it is the `Here` location, which means "equivalent to
/// the context".
pub const DotLocation: MultiLocation = Here.into();
pub const TokenLocation: MultiLocation = Here.into_location();
/// The Polkadot network ID. This is named.
pub const PolkadotNetwork: NetworkId = NetworkId::Polkadot;
/// Our XCM location ancestry - i.e. what, if anything, `Parent` means evaluated in our context. Since
/// Polkadot is a top-level relay-chain, there is no ancestry.
pub const Ancestry: MultiLocation = Here.into();
pub const ThisNetwork: NetworkId = NetworkId::Polkadot;
/// Our location in the universe of consensus systems.
pub const UniversalLocation: InteriorMultiLocation = X1(GlobalConsensus(ThisNetwork::get()));
/// The check account, which holds any native assets that have been teleported out and not back in (yet).
pub CheckAccount: AccountId = XcmPallet::check_account();
}
Expand All @@ -55,18 +55,18 @@ pub type SovereignAccountOf = (
// We can convert a child parachain using the standard `AccountId` conversion.
ChildParachainConvertsVia<ParaId, AccountId>,
// We can directly alias an `AccountId32` into a local account.
AccountId32Aliases<PolkadotNetwork, AccountId>,
AccountId32Aliases<ThisNetwork, AccountId>,
);

/// Our asset transactor. This is what allows us to interest with the runtime facilities from the point of
/// view of XCM-only concepts like `MultiLocation` and `MultiAsset`.
///
/// Ours is only aware of the Balances pallet, which is mapped to `DotLocation`.
/// Ours is only aware of the Balances pallet, which is mapped to `TokenLocation`.
pub type LocalAssetTransactor = XcmCurrencyAdapter<
// Use this currency:
Balances,
// Use this currency when it is a fungible asset matching the given location or name:
IsConcrete<DotLocation>,
IsConcrete<TokenLocation>,
// We can convert the MultiLocations with our converter above:
SovereignAccountOf,
// Our chain's account ID type (we can't get away without mentioning it explicitly):
Expand All @@ -82,7 +82,7 @@ type LocalOriginConverter = (
// A child parachain, natively expressed, has the `Parachain` origin.
ChildParachainAsNative<parachains_origin::Origin, Origin>,
// The AccountId32 location type can be expressed natively as a `Signed` origin.
SignedAccountId32AsNative<PolkadotNetwork, Origin>,
SignedAccountId32AsNative<ThisNetwork, Origin>,
);

parameter_types! {
Expand All @@ -101,12 +101,12 @@ pub type XcmRouter = (
);

parameter_types! {
pub const Polkadot: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(DotLocation::get()) });
pub const PolkadotForStatemint: (MultiAssetFilter, MultiLocation) = (Polkadot::get(), Parachain(1000).into());
pub const Dot: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(TokenLocation::get()) });
pub const DotForStatemint: (MultiAssetFilter, MultiLocation) = (Dot::get(), Parachain(1000).into_location());
pub const MaxAssetsIntoHolding: u32 = 64;
}

pub type TrustedTeleporters = (xcm_builder::Case<PolkadotForStatemint>,);
pub type TrustedTeleporters = (xcm_builder::Case<DotForStatemint>,);

match_type! {
pub type OnlyParachains: impl Contains<MultiLocation> = {
Expand Down Expand Up @@ -134,23 +134,26 @@ impl xcm_executor::Config for XcmConfig {
type OriginConverter = LocalOriginConverter;
type IsReserve = ();
type IsTeleporter = TrustedTeleporters;
type LocationInverter = LocationInverter<Ancestry>;
type LocationInverter = LocationInverter<UniversalLocation>;
type Barrier = Barrier;
type Weigher = FixedWeightBounds<BaseXcmWeight, Call, MaxInstructions>;
// The weight trader piggybacks on the existing transaction-fee conversion logic.
type Trader = UsingComponents<WeightToFee, DotLocation, AccountId, Balances, ToAuthor<Runtime>>;
type Trader =
UsingComponents<WeightToFee, TokenLocation, AccountId, Balances, ToAuthor<Runtime>>;
type ResponseHandler = XcmPallet;
type AssetTrap = XcmPallet;
type AssetClaims = XcmPallet;
type SubscriptionService = XcmPallet;
type PalletInstancesInfo = AllPalletsWithSystem;
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
type FeeManager = ();
// No bridges yet...
type MessageExporter = ();
type UniversalAliases = Nothing;
}

parameter_types! {
pub const CouncilBodyId: BodyId = BodyId::Executive;
// We are conservative with the XCM version we advertize.
pub const AdvertisedXcmVersion: u32 = 2;
}

/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior location
Expand All @@ -164,7 +167,7 @@ pub type LocalOriginToLocation = (
CouncilBodyId,
>,
// And a usual Signed origin to be used in XCM as a corresponding AccountId32
SignedToAccountId32<Origin, AccountId, PolkadotNetwork>,
SignedToAccountId32<Origin, AccountId, ThisNetwork>,
);

impl pallet_xcm::Config for Runtime {
Expand All @@ -175,13 +178,13 @@ impl pallet_xcm::Config for Runtime {
type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin<Origin, LocalOriginToLocation>;
// ...but they must match our filter, which rejects all.
type XcmExecuteFilter = Nothing;
type XcmExecutor = xcm_executor::XcmExecutor<XcmConfig>;
type XcmExecutor = XcmExecutor<XcmConfig>;
type XcmTeleportFilter = Nothing;
type XcmReserveTransferFilter = Nothing;
type Weigher = FixedWeightBounds<BaseXcmWeight, Call, MaxInstructions>;
type LocationInverter = LocationInverter<Ancestry>;
type LocationInverter = LocationInverter<UniversalLocation>;
type Origin = Origin;
type Call = Call;
const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
type AdvertisedXcmVersion = AdvertisedXcmVersion;
type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
}
Loading

0 comments on commit 6185cf3

Please sign in to comment.