Ensure outbound XCMs are decodable with limits + add EnsureDecodableXcm router (for testing purposes) (#4186)

This PR:
- adds `EnsureDecodableXcm` (testing) router that attempts to *encode*
and *decode* passed XCM `message` to ensure that the receiving side will
be able to decode, at least with the same XCM version.
- fixes `pallet_xcm` / `pallet_xcm_benchmarks` assets data generation

Relates to investigation of
https://substrate.stackexchange.com/questions/11288 and missing fix
https://github.com/paritytech/polkadot-sdk/pull/2129 which did not get
into the fellows 1.1.X release.

## Questions/TODOs

- [x] fix XCM benchmarks, which produces undecodable data - new router
catched at least two cases
  - `BoundedVec exceeds its limit`
  - `Fungible asset of zero amount is not allowed`  
- [x] do we need to add `sort` to the `prepend_with` as we did for
reanchor [here](https://github.com/paritytech/polkadot-sdk/pull/2129)?
@serban300 (**created separate/follow-up PR**:
https://github.com/paritytech/polkadot-sdk/pull/4235)
- [x] We added decoding check to `XcmpQueue` -> `validate_xcm_nesting`,
why not to added to the `ParentAsUmp` or `ChildParachainRouter`?
@franciscoaguirre (**created separate/follow-up PR**:
https://github.com/paritytech/polkadot-sdk/pull/4236)
- [ ] `SendController::send_blob` replace `VersionedXcm::<()>::decode(`
with `VersionedXcm::<()>::decode_with_depth_limit(MAX_XCM_DECODE_DEPTH,
data)` ?

---------

Co-authored-by: Adrian Catangiu <adrian@parity.io>
This commit is contained in:
Branislav Kontur
2024-04-23 13:40:05 +02:00
committed by GitHub
parent 5f2e66f5d0
commit 118cd6f922
12 changed files with 70 additions and 50 deletions
Generated
-8
View File
@@ -14348,7 +14348,6 @@ dependencies = [
name = "polkadot-test-runtime"
version = "1.0.0"
dependencies = [
"bitvec",
"frame-election-provider-support",
"frame-executive",
"frame-support",
@@ -14373,16 +14372,12 @@ dependencies = [
"pallet-vesting",
"pallet-xcm",
"parity-scale-codec",
"polkadot-parachain-primitives",
"polkadot-primitives",
"polkadot-runtime-common",
"polkadot-runtime-parachains",
"rustc-hex",
"scale-info",
"serde",
"serde_derive",
"serde_json",
"smallvec",
"sp-api",
"sp-authority-discovery",
"sp-block-builder",
@@ -21273,11 +21268,8 @@ version = "1.0.0"
dependencies = [
"frame-support",
"polkadot-primitives",
"polkadot-runtime-common",
"smallvec",
"sp-core",
"sp-runtime",
"sp-weights",
]
[[package]]
-10
View File
@@ -11,14 +11,10 @@ license.workspace = true
workspace = true
[dependencies]
bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] }
parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] }
log = { workspace = true }
rustc-hex = { version = "2.1.0", default-features = false }
scale-info = { version = "2.11.1", default-features = false, features = ["derive"] }
serde = { workspace = true }
serde_derive = { optional = true, workspace = true }
smallvec = "1.8.0"
authority-discovery-primitives = { package = "sp-authority-discovery", path = "../../../substrate/primitives/authority-discovery", default-features = false }
babe-primitives = { package = "sp-consensus-babe", path = "../../../substrate/primitives/consensus/babe", default-features = false }
@@ -63,7 +59,6 @@ pallet-vesting = { path = "../../../substrate/frame/vesting", default-features =
runtime-common = { package = "polkadot-runtime-common", path = "../common", default-features = false }
primitives = { package = "polkadot-primitives", path = "../../primitives", default-features = false }
pallet-xcm = { path = "../../xcm/pallet-xcm", default-features = false }
polkadot-parachain-primitives = { path = "../../parachain", default-features = false }
polkadot-runtime-parachains = { path = "../parachains", default-features = false }
xcm-builder = { package = "staging-xcm-builder", path = "../../xcm/xcm-builder", default-features = false }
xcm-executor = { package = "staging-xcm-executor", path = "../../xcm/xcm-executor", default-features = false }
@@ -92,7 +87,6 @@ std = [
"authority-discovery-primitives/std",
"babe-primitives/std",
"beefy-primitives/std",
"bitvec/std",
"block-builder-api/std",
"frame-election-provider-support/std",
"frame-executive/std",
@@ -118,14 +112,11 @@ std = [
"pallet-vesting/std",
"pallet-xcm/std",
"parity-scale-codec/std",
"polkadot-parachain-primitives/std",
"polkadot-runtime-parachains/std",
"primitives/std",
"runtime-common/std",
"rustc-hex/std",
"scale-info/std",
"serde/std",
"serde_derive",
"sp-api/std",
"sp-core/std",
"sp-genesis-builder/std",
@@ -157,7 +148,6 @@ runtime-benchmarks = [
"pallet-timestamp/runtime-benchmarks",
"pallet-vesting/runtime-benchmarks",
"pallet-xcm/runtime-benchmarks",
"polkadot-parachain-primitives/runtime-benchmarks",
"polkadot-runtime-parachains/runtime-benchmarks",
"primitives/runtime-benchmarks",
"runtime-common/runtime-benchmarks",
@@ -14,18 +14,12 @@ smallvec = "1.8.0"
frame-support = { path = "../../../../substrate/frame/support", default-features = false }
primitives = { package = "polkadot-primitives", path = "../../../primitives", default-features = false }
runtime-common = { package = "polkadot-runtime-common", path = "../../common", default-features = false }
sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false }
sp-weights = { path = "../../../../substrate/primitives/weights", default-features = false }
sp-core = { path = "../../../../substrate/primitives/core", default-features = false }
[features]
default = ["std"]
std = [
"frame-support/std",
"primitives/std",
"runtime-common/std",
"sp-core/std",
"sp-runtime/std",
"sp-weights/std",
]
@@ -23,7 +23,9 @@ use frame_support::{
traits::{Everything, Nothing},
};
use xcm::latest::prelude::*;
use xcm_builder::{AllowUnpaidExecutionFrom, FrameTransactionalProcessor, MintLocation};
use xcm_builder::{
AllowUnpaidExecutionFrom, EnsureDecodableXcm, FrameTransactionalProcessor, MintLocation,
};
type Block = frame_system::mocking::MockBlock<Test>;
@@ -91,7 +93,7 @@ parameter_types! {
pub struct XcmConfig;
impl xcm_executor::Config for XcmConfig {
type RuntimeCall = RuntimeCall;
type XcmSender = DevNull;
type XcmSender = EnsureDecodableXcm<DevNull>;
type AssetTransactor = AssetTransactor;
type OriginConverter = ();
type IsReserve = TrustedReserves;
@@ -28,7 +28,8 @@ use xcm_builder::{
AssetsInHolding, TestAssetExchanger, TestAssetLocker, TestAssetTrap,
TestSubscriptionService, TestUniversalAliases,
},
AliasForeignAccountId32, AllowUnpaidExecutionFrom, FrameTransactionalProcessor,
AliasForeignAccountId32, AllowUnpaidExecutionFrom, EnsureDecodableXcm,
FrameTransactionalProcessor,
};
use xcm_executor::traits::ConvertOrigin;
@@ -81,7 +82,7 @@ type Aliasers = AliasForeignAccountId32<OnlyParachains>;
pub struct XcmConfig;
impl xcm_executor::Config for XcmConfig {
type RuntimeCall = RuntimeCall;
type XcmSender = DevNull;
type XcmSender = EnsureDecodableXcm<DevNull>;
type AssetTransactor = NoAssetTransactor;
type OriginConverter = AlwaysSignedByDefault<RuntimeOrigin>;
type IsReserve = AllAssetLocationsPass;
+7 -5
View File
@@ -33,10 +33,11 @@ use xcm::prelude::*;
use xcm_builder::{
AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom,
AllowTopLevelPaidExecutionFrom, Case, ChildParachainAsNative, ChildParachainConvertsVia,
ChildSystemParachainAsSuperuser, DescribeAllTerminal, FixedRateOfFungible, FixedWeightBounds,
FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, HashedDescription, IsConcrete,
MatchedConvertedConcreteId, NoChecking, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, TakeWeightCredit, XcmFeeManagerFromComponents, XcmFeeToAccount,
ChildSystemParachainAsSuperuser, DescribeAllTerminal, EnsureDecodableXcm, FixedRateOfFungible,
FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter,
HashedDescription, IsConcrete, MatchedConvertedConcreteId, NoChecking,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
XcmFeeManagerFromComponents, XcmFeeToAccount,
};
use xcm_executor::{
traits::{Identity, JustTry},
@@ -488,7 +489,8 @@ pub type Barrier = (
AllowSubscriptionsFrom<Everything>,
);
pub type XcmRouter = (TestPaidForPara3000SendXcm, TestSendXcmErrX8, TestSendXcm);
pub type XcmRouter =
EnsureDecodableXcm<(TestPaidForPara3000SendXcm, TestSendXcmErrX8, TestSendXcm)>;
pub struct XcmConfig;
impl xcm_executor::Config for XcmConfig {
+1 -1
View File
@@ -119,7 +119,7 @@ mod process_xcm_message;
pub use process_xcm_message::ProcessXcmMessage;
mod routing;
pub use routing::{EnsureDelivery, WithTopicSource, WithUniqueTopic};
pub use routing::{EnsureDecodableXcm, EnsureDelivery, WithTopicSource, WithUniqueTopic};
mod transactional;
pub use transactional::FrameTransactionalProcessor;
+34
View File
@@ -139,3 +139,37 @@ impl EnsureDelivery for Tuple {
(None, None)
}
}
/// A wrapper router that attempts to *encode* and *decode* passed XCM `message` to ensure that the
/// receiving side will be able to decode, at least with the same XCM version.
///
/// This is designed to be at the top-level of any routers which do the real delivery. While other
/// routers can manipulate the `message`, we cannot access the final XCM due to the generic
/// `Inner::Ticket`. Therefore, this router aims to validate at least the passed `message`.
///
/// NOTE: For use in mock runtimes which don't have the DMP/UMP/HRMP XCM validations.
pub struct EnsureDecodableXcm<Inner>(sp_std::marker::PhantomData<Inner>);
impl<Inner: SendXcm> SendXcm for EnsureDecodableXcm<Inner> {
type Ticket = Inner::Ticket;
fn validate(
destination: &mut Option<Location>,
message: &mut Option<Xcm<()>>,
) -> SendResult<Self::Ticket> {
if let Some(msg) = message {
let versioned_xcm = VersionedXcm::<()>::from(msg.clone());
if versioned_xcm.validate_xcm_nesting().is_err() {
log::error!(
target: "xcm::validate_xcm_nesting",
"EnsureDecodableXcm validate_xcm_nesting error for \nversioned_xcm: {versioned_xcm:?}\nbased on xcm: {msg:?}"
);
return Err(SendError::Transport("EnsureDecodableXcm validate_xcm_nesting error"))
}
}
Inner::validate(destination, message)
}
fn deliver(ticket: Self::Ticket) -> Result<XcmHash, SendError> {
Inner::deliver(ticket)
}
}
+5 -2
View File
@@ -19,6 +19,7 @@
use crate::{
barriers::{AllowSubscriptionsFrom, RespectSuspension, TrailingSetTopicAsId},
test_utils::*,
EnsureDecodableXcm,
};
pub use crate::{
AliasForeignAccountId32, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
@@ -165,8 +166,8 @@ pub fn set_exporter_override(
pub fn clear_exporter_override() {
EXPORTER_OVERRIDE.with(|x| x.replace(None));
}
pub struct TestMessageSender;
impl SendXcm for TestMessageSender {
pub struct TestMessageSenderImpl;
impl SendXcm for TestMessageSenderImpl {
type Ticket = (Location, Xcm<()>, XcmHash);
fn validate(
dest: &mut Option<Location>,
@@ -183,6 +184,8 @@ impl SendXcm for TestMessageSender {
Ok(hash)
}
}
pub type TestMessageSender = EnsureDecodableXcm<TestMessageSenderImpl>;
pub struct TestMessageExporter;
impl ExportXcm for TestMessageExporter {
type Ticket = (NetworkId, u32, InteriorLocation, InteriorLocation, Xcm<()>, XcmHash);
+7 -5
View File
@@ -35,9 +35,9 @@ use staging_xcm_builder as xcm_builder;
use xcm_builder::{
AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom,
ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser,
FixedRateOfFungible, FixedWeightBounds, FungibleAdapter, IsChildSystemParachain, IsConcrete,
MintLocation, RespectSuspension, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, TakeWeightCredit,
EnsureDecodableXcm, FixedRateOfFungible, FixedWeightBounds, FungibleAdapter,
IsChildSystemParachain, IsConcrete, MintLocation, RespectSuspension, SignedAccountId32AsNative,
SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
};
pub type AccountId = AccountId32;
@@ -68,6 +68,8 @@ impl SendXcm for TestSendXcm {
}
}
pub type TestXcmRouter = EnsureDecodableXcm<TestSendXcm>;
// copied from kusama constants
pub const UNITS: Balance = 1_000_000_000_000;
pub const CENTS: Balance = UNITS / 30_000;
@@ -180,7 +182,7 @@ pub type TrustedTeleporters = (xcm_builder::Case<KusamaForAssetHub>,);
pub struct XcmConfig;
impl xcm_executor::Config for XcmConfig {
type RuntimeCall = RuntimeCall;
type XcmSender = TestSendXcm;
type XcmSender = TestXcmRouter;
type AssetTransactor = LocalAssetTransactor;
type OriginConverter = LocalOriginConverter;
type IsReserve = ();
@@ -215,7 +217,7 @@ impl pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type UniversalLocation = UniversalLocation;
type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
type XcmRouter = TestSendXcm;
type XcmRouter = TestXcmRouter;
// Anyone can execute XCM messages locally...
type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
type XcmExecuteFilter = Nothing;
@@ -40,10 +40,10 @@ use polkadot_parachain_primitives::primitives::{
use xcm::{latest::prelude::*, VersionedXcm};
use xcm_builder::{
Account32Hash, AccountId32Aliases, AllowUnpaidExecutionFrom, ConvertedConcreteId,
EnsureXcmOrigin, FixedRateOfFungible, FixedWeightBounds, FrameTransactionalProcessor,
FungibleAdapter, IsConcrete, NativeAsset, NoChecking, NonFungiblesAdapter, ParentIsPreset,
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation,
EnsureDecodableXcm, EnsureXcmOrigin, FixedRateOfFungible, FixedWeightBounds,
FrameTransactionalProcessor, FungibleAdapter, IsConcrete, NativeAsset, NoChecking,
NonFungiblesAdapter, ParentIsPreset, SiblingParachainConvertsVia, SignedAccountId32AsNative,
SignedToAccountId32, SovereignSignedViaLocation,
};
use xcm_executor::{
traits::{ConvertLocation, JustTry},
@@ -212,7 +212,7 @@ pub type LocalAssetTransactor = (
>,
);
pub type XcmRouter = super::ParachainXcmRouter<MsgQueue>;
pub type XcmRouter = EnsureDecodableXcm<super::ParachainXcmRouter<MsgQueue>>;
pub type Barrier = AllowUnpaidExecutionFrom<Everything>;
parameter_types! {
@@ -36,9 +36,9 @@ use xcm::latest::prelude::*;
use xcm_builder::{
Account32Hash, AccountId32Aliases, AllowUnpaidExecutionFrom, AsPrefixedGeneralIndex,
ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser,
ConvertedConcreteId, FixedRateOfFungible, FixedWeightBounds, FrameTransactionalProcessor,
FungibleAdapter, IsConcrete, NoChecking, NonFungiblesAdapter, SignedAccountId32AsNative,
SignedToAccountId32, SovereignSignedViaLocation,
ConvertedConcreteId, EnsureDecodableXcm, FixedRateOfFungible, FixedWeightBounds,
FrameTransactionalProcessor, FungibleAdapter, IsConcrete, NoChecking, NonFungiblesAdapter,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation,
};
use xcm_executor::{traits::JustTry, Config, XcmExecutor};
@@ -168,7 +168,7 @@ parameter_types! {
pub const MaxAssetsIntoHolding: u32 = 64;
}
pub type XcmRouter = super::RelayChainXcmRouter;
pub type XcmRouter = EnsureDecodableXcm<super::RelayChainXcmRouter>;
pub type Barrier = AllowUnpaidExecutionFrom<Everything>;
pub struct XcmConfig;