XCM revamp (#2836)

* Remove unused relaying XCM

* Aggregate HRMP (XCMP/HMP) messages. Payloads for spambot.

* Revert lock

* Fix

* Broken example

* Introduce fee payment mechanics into XCM.

* Weight limitations on XCM execution

* Mock environment for tests and the first test

* Tests for XCM and a few refactors.

* Remove code that's not ready

* Fix for an XCM and an additional test

* Query response system

* XCMP message dispatch system reimagining

- Moved most of the logic into xcm-handler pallet
- Altered the outgoing XCMP API from push to pull
- Changed underlying outgoing queue data structures to avoid multi-page read/writes
- Introduced queuing for incoming messages
- Introduced signal messages as a flow-control sub-stream
- Introduced flow-control with basic threshold back-pressure
- Introduced overall weight limitation on messages executed
- Additonal alterations to XCM APIs for the new system

* Some build fixes

* Remove the Encode bounds sprayed around

* More faff

* Fix bounds amek use latest scale codec.

* remove println

* fixes

* Fix XcmExecutor Tests

* Fix XCM bounds using derivative crate

* Refactor names of XcmGeneric &c into Xcm

* Repot the xcm-executor into xcm-builder

* Docs

* Docs

* Fixes

* Update xcm/src/lib.rs

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>

* Fixes

* Docs

* Update runtime/parachains/src/ump.rs

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>

* Docs

* Fixes

* Fixes

* Fixes

* Docs

* Fixes

* Fixes

* Introduce transfer_asset specialisation.

* Fixes

* Fixes

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
This commit is contained in:
Gavin Wood
2021-04-07 22:38:29 +02:00
committed by GitHub
parent 8eae0fa443
commit adc238ad86
37 changed files with 2436 additions and 574 deletions
@@ -14,70 +14,68 @@
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
use sp_std::marker::PhantomData;
use sp_std::{marker::PhantomData, borrow::Borrow};
use sp_io::hashing::blake2_256;
use sp_runtime::traits::AccountIdConversion;
use frame_support::traits::Get;
use parity_scale_codec::Encode;
use xcm::v0::{MultiLocation, NetworkId, Junction};
use xcm_executor::traits::LocationConversion;
use xcm_executor::traits::{InvertLocation, Convert};
pub struct Account32Hash<Network, AccountId>(PhantomData<(Network, AccountId)>);
impl<
Network: Get<NetworkId>,
AccountId: From<[u8; 32]> + Into<[u8; 32]>,
> LocationConversion<AccountId> for Account32Hash<Network, AccountId> {
fn from_location(location: &MultiLocation) -> Option<AccountId> {
Some(("multiloc", location).using_encoded(blake2_256).into())
AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone,
> Convert<MultiLocation, AccountId> for Account32Hash<Network, AccountId> {
fn convert_ref(location: impl Borrow<MultiLocation>) -> Result<AccountId, ()> {
Ok(("multiloc", location.borrow()).using_encoded(blake2_256).into())
}
fn try_into_location(who: AccountId) -> Result<MultiLocation, AccountId> {
Err(who)
fn reverse_ref(_: impl Borrow<AccountId>) -> Result<MultiLocation, ()> {
Err(())
}
}
pub struct ParentIsDefault<AccountId>(PhantomData<AccountId>);
impl<
AccountId: Default + Eq,
> LocationConversion<AccountId> for ParentIsDefault<AccountId> {
fn from_location(location: &MultiLocation) -> Option<AccountId> {
if let MultiLocation::X1(Junction::Parent) = location {
Some(AccountId::default())
AccountId: Default + Eq + Clone,
> Convert<MultiLocation, AccountId> for ParentIsDefault<AccountId> {
fn convert_ref(location: impl Borrow<MultiLocation>) -> Result<AccountId, ()> {
if let &MultiLocation::X1(Junction::Parent) = location.borrow() {
Ok(AccountId::default())
} else {
None
Err(())
}
}
fn try_into_location(who: AccountId) -> Result<MultiLocation, AccountId> {
if who == AccountId::default() {
fn reverse_ref(who: impl Borrow<AccountId>) -> Result<MultiLocation, ()> {
if who.borrow() == &AccountId::default() {
Ok(Junction::Parent.into())
} else {
Err(who)
Err(())
}
}
}
pub struct ChildParachainConvertsVia<ParaId, AccountId>(PhantomData<(ParaId, AccountId)>);
impl<
ParaId: From<u32> + Into<u32> + AccountIdConversion<AccountId>,
AccountId,
> LocationConversion<AccountId> for ChildParachainConvertsVia<ParaId, AccountId> {
fn from_location(location: &MultiLocation) -> Option<AccountId> {
if let MultiLocation::X1(Junction::Parachain { id }) = location {
Some(ParaId::from(*id).into_account())
AccountId: Clone,
> Convert<MultiLocation, AccountId> for ChildParachainConvertsVia<ParaId, AccountId> {
fn convert_ref(location: impl Borrow<MultiLocation>) -> Result<AccountId, ()> {
if let &MultiLocation::X1(Junction::Parachain { id }) = location.borrow() {
Ok(ParaId::from(id).into_account())
} else {
None
Err(())
}
}
fn try_into_location(who: AccountId) -> Result<MultiLocation, AccountId> {
if let Some(id) = ParaId::try_from_account(&who) {
fn reverse_ref(who: impl Borrow<AccountId>) -> Result<MultiLocation, ()> {
if let Some(id) = ParaId::try_from_account(who.borrow()) {
Ok(Junction::Parachain { id: id.into() }.into())
} else {
Err(who)
Err(())
}
}
}
@@ -86,65 +84,79 @@ pub struct SiblingParachainConvertsVia<ParaId, AccountId>(PhantomData<(ParaId, A
impl<
ParaId: From<u32> + Into<u32> + AccountIdConversion<AccountId>,
AccountId,
> LocationConversion<AccountId> for SiblingParachainConvertsVia<ParaId, AccountId> {
fn from_location(location: &MultiLocation) -> Option<AccountId> {
if let MultiLocation::X2(Junction::Parent, Junction::Parachain { id }) = location {
Some(ParaId::from(*id).into_account())
AccountId: Clone,
> Convert<MultiLocation, AccountId> for SiblingParachainConvertsVia<ParaId, AccountId> {
fn convert_ref(location: impl Borrow<MultiLocation>) -> Result<AccountId, ()> {
if let &MultiLocation::X2(Junction::Parent, Junction::Parachain { id }) = location.borrow() {
Ok(ParaId::from(id).into_account())
} else {
None
Err(())
}
}
fn try_into_location(who: AccountId) -> Result<MultiLocation, AccountId> {
if let Some(id) = ParaId::try_from_account(&who) {
fn reverse_ref(who: impl Borrow<AccountId>) -> Result<MultiLocation, ()> {
if let Some(id) = ParaId::try_from_account(who.borrow()) {
Ok([Junction::Parent, Junction::Parachain { id: id.into() }].into())
} else {
Err(who)
Err(())
}
}
}
pub struct AccountId32Aliases<Network, AccountId>(PhantomData<(Network, AccountId)>);
impl<
Network: Get<NetworkId>,
AccountId: From<[u8; 32]> + Into<[u8; 32]>,
> LocationConversion<AccountId> for AccountId32Aliases<Network, AccountId> {
fn from_location(location: &MultiLocation) -> Option<AccountId> {
if let MultiLocation::X1(Junction::AccountId32 { id, network }) = location {
if matches!(network, NetworkId::Any) || network == &Network::get() {
return Some((*id).into())
}
}
None
AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone,
> Convert<MultiLocation, AccountId> for AccountId32Aliases<Network, AccountId> {
fn convert(location: MultiLocation) -> Result<AccountId, MultiLocation> {
let id = match location {
MultiLocation::X1(Junction::AccountId32 { id, network: NetworkId::Any }) => id,
MultiLocation::X1(Junction::AccountId32 { id, network }) if &network == &Network::get() => id,
l => return Err(l),
};
Ok(id.into())
}
fn try_into_location(who: AccountId) -> Result<MultiLocation, AccountId> {
fn reverse(who: AccountId) -> Result<MultiLocation, AccountId> {
Ok(Junction::AccountId32 { id: who.into(), network: Network::get() }.into())
}
}
pub struct AccountKey20Aliases<Network, AccountId>(PhantomData<(Network, AccountId)>);
impl<
Network: Get<NetworkId>,
AccountId: From<[u8; 20]> + Into<[u8; 20]>
> LocationConversion<AccountId> for AccountKey20Aliases<Network, AccountId> {
fn from_location(location: &MultiLocation) -> Option<AccountId> {
if let MultiLocation::X1(Junction::AccountKey20 { key, network }) = location {
if matches!(network, NetworkId::Any) || network == &Network::get() {
return Some((*key).into());
}
}
None
AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone,
> Convert<MultiLocation, AccountId> for AccountKey20Aliases<Network, AccountId> {
fn convert(location: MultiLocation) -> Result<AccountId, MultiLocation> {
let key = match location {
MultiLocation::X1(Junction::AccountKey20 { key, network: NetworkId::Any }) => key,
MultiLocation::X1(Junction::AccountKey20 { key, network }) if &network == &Network::get() => key,
l => return Err(l),
};
Ok(key.into())
}
fn try_into_location(who: AccountId) -> Result<MultiLocation, AccountId> {
Ok(Junction::AccountKey20 {
key: who.into(),
network: Network::get(),
}
.into())
fn reverse(who: AccountId) -> Result<MultiLocation, AccountId> {
let j = Junction::AccountKey20 { key: who.into(), network: Network::get() };
Ok(j.into())
}
}
/// Simple location inverter; give it this location's ancestry and it'll figure out the inverted location.
pub struct LocationInverter<Ancestry>(PhantomData<Ancestry>);
impl<Ancestry: Get<MultiLocation>> InvertLocation for LocationInverter<Ancestry> {
fn invert_location(location: &MultiLocation) -> MultiLocation {
let mut ancestry = Ancestry::get();
let mut result = location.clone();
for (i, j) in location.iter_rev()
.map(|j| match j {
Junction::Parent => ancestry.take_first().unwrap_or(Junction::OnlyChild),
_ => Junction::Parent,
})
.enumerate()
{
*result.at_mut(i).expect("location and result begin equal; same size; qed") = j;
}
result
}
}