Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

xcm: fix for DenyThenTry Barrier #7169

Open
wants to merge 50 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
faa431a
Fix for DenyThenTry
yrong Jan 15, 2025
d0748cf
Apply suggestions from code review
bkontur Jan 15, 2025
bf669bb
Rename to DenyExportMessageFrom with comments
yrong Jan 15, 2025
716ccdc
Move DenyExportMessageFrom to bridge-hub-common
yrong Jan 15, 2025
17c9b14
Merge branch 'fix-for-deny-then-try' of https://github.com/yrong/polk…
yrong Jan 15, 2025
e10587b
Update comments
yrong Jan 15, 2025
d83dadb
Add the prdoc
yrong Jan 15, 2025
0b4c955
Merge branch 'master' into fix-for-deny-then-try
yrong Jan 15, 2025
ac810f7
Refactor DenyExecution to be more explicit
yrong Jan 15, 2025
8f0af5b
Update prdoc/pr_7169.prdoc
yrong Jan 15, 2025
67e7991
Merge branch 'master' into fix-for-deny-then-try
yrong Jan 15, 2025
ee8de3e
Merge branch 'master' into fix-for-deny-then-try
yrong Jan 16, 2025
2b496e5
Update polkadot/xcm/xcm-executor/src/traits/should_execute.rs
bkontur Jan 16, 2025
81ec7f1
Update polkadot/xcm/xcm-executor/src/traits/should_execute.rs
bkontur Jan 16, 2025
17c4972
Improve tests
yrong Jan 16, 2025
58d7990
Test for DenyReserveTransferToRelayChain
yrong Jan 16, 2025
2258ab1
Merge branch 'fix-for-deny-then-try' of https://github.com/yrong/polk…
yrong Jan 16, 2025
dbfe244
Merge branch 'master' into fix-for-deny-then-try
yrong Jan 17, 2025
462c049
Apply suggestions from code review
bkontur Jan 17, 2025
6e578bf
Update polkadot/xcm/xcm-builder/src/tests/barriers.rs
bkontur Jan 17, 2025
e4acb39
Update from bkontur running command 'fmt'
Jan 17, 2025
8b94963
Move dummy impls to tests
yrong Jan 17, 2025
b2f7338
More tests
yrong Jan 17, 2025
a8a7ea3
Merge branch 'fix-for-deny-then-try' of https://github.com/yrong/polk…
yrong Jan 17, 2025
a78449e
Fix comments
yrong Jan 17, 2025
ddba5dc
Apply suggestions from code review
bkontur Jan 17, 2025
66814c9
Update polkadot/xcm/xcm-executor/src/traits/should_execute.rs
bkontur Jan 21, 2025
02912a6
Update cumulus/parachains/runtimes/bridge-hubs/common/tests/tests.rs
bkontur Jan 21, 2025
5d3a5e7
Merge branch 'master' into fix-for-deny-then-try
bkontur Jan 21, 2025
85b06c2
Add comments
yrong Jan 21, 2025
dfbafc5
Merge branch 'master' into fix-for-deny-then-try
yrong Jan 21, 2025
a842c4d
Fix clippy
yrong Jan 22, 2025
c7cd51d
Merge branch 'fix-for-deny-then-try' of https://github.com/yrong/polk…
yrong Jan 22, 2025
551afc1
Update polkadot/xcm/xcm-executor/src/traits/should_execute.rs
yrong Jan 22, 2025
cd33044
Update polkadot/xcm/xcm-executor/src/traits/should_execute.rs
yrong Jan 22, 2025
639177b
Update polkadot/xcm/xcm-executor/src/traits/should_execute.rs
yrong Jan 22, 2025
7564e23
Update cumulus/parachains/runtimes/bridge-hubs/common/src/barriers.rs
yrong Jan 22, 2025
d9c2f0e
Update cumulus/parachains/runtimes/bridge-hubs/common/src/barriers.rs
yrong Jan 22, 2025
a04aae2
Merge branch 'fix-for-deny-then-try' of https://github.com/yrong/polk…
yrong Jan 22, 2025
c038e86
Merge branch 'master' into fix-for-deny-then-try
yrong Jan 22, 2025
234a5e7
Merge branch 'master' into fix-for-deny-then-try
franciscoaguirre Jan 24, 2025
b39f07e
Update polkadot/xcm/xcm-builder/src/tests/barriers.rs
yrong Jan 25, 2025
110d42e
Update polkadot/xcm/xcm-builder/src/tests/barriers.rs
yrong Jan 25, 2025
8699575
Update cumulus/parachains/runtimes/bridge-hubs/common/src/barriers.rs
yrong Jan 25, 2025
3cd6bf5
Merge branch 'master' into fix-for-deny-then-try
yrong Jan 25, 2025
6b65c81
Change return to Result<(), ProcessMessageError>
yrong Jan 25, 2025
03ff441
Fix tests
yrong Jan 25, 2025
8d61bfb
Merge branch 'master' into fix-for-deny-then-try
yrong Jan 26, 2025
c2719f9
Update polkadot/xcm/xcm-executor/src/traits/should_execute.rs
bkontur Jan 27, 2025
83835fc
Merge branch 'master' into fix-for-deny-then-try
bkontur Jan 27, 2025
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
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.

6 changes: 6 additions & 0 deletions cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ sp-core = { workspace = true }
sp-runtime = { workspace = true }
sp-std = { workspace = true }
xcm = { workspace = true }
xcm-builder = { workspace = true }
xcm-executor = { workspace = true }

[features]
default = ["std"]
Expand All @@ -32,6 +34,8 @@ std = [
"sp-core/std",
"sp-runtime/std",
"sp-std/std",
"xcm-builder/std",
"xcm-executor/std",
"xcm/std",
]

Expand All @@ -41,5 +45,7 @@ runtime-benchmarks = [
"pallet-message-queue/runtime-benchmarks",
"snowbridge-core/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
"xcm-builder/runtime-benchmarks",
"xcm-executor/runtime-benchmarks",
"xcm/runtime-benchmarks",
]
59 changes: 59 additions & 0 deletions cumulus/parachains/runtimes/bridge-hubs/common/src/barriers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use core::{marker::PhantomData, ops::ControlFlow};
use cumulus_primitives_core::Weight;
use frame_support::traits::{Contains, ProcessMessageError};
use xcm::prelude::{ExportMessage, Instruction, Location, NetworkId};

use xcm_builder::{CreateMatcher, MatchXcm};
use xcm_executor::traits::{DenyExecution, Properties};

/// Deny execution if the message contains instruction `ExportMessage` with
/// a. origin is contained in `FromOrigin` (i.e.`FromOrigin::Contains(origin)`)
/// b. network is contained in `ToGlobalConsensus`, (i.e. `ToGlobalConsensus::contains(network)`)
pub struct DenyExportMessageFrom<FromOrigin, ToGlobalConsensus>(
PhantomData<(FromOrigin, ToGlobalConsensus)>,
);

impl<FromOrigin, ToGlobalConsensus> DenyExecution
for DenyExportMessageFrom<FromOrigin, ToGlobalConsensus>
where
FromOrigin: Contains<Location>,
ToGlobalConsensus: Contains<NetworkId>,
{
fn deny_execution<RuntimeCall>(
origin: &Location,
message: &mut [Instruction<RuntimeCall>],
_max_weight: Weight,
_properties: &mut Properties,
) -> Option<ProcessMessageError> {
match message.matcher().match_next_inst_while(
yrong marked this conversation as resolved.
Show resolved Hide resolved
|_| true,
|inst| match inst {
ExportMessage { network, .. } =>
if ToGlobalConsensus::contains(network) && FromOrigin::contains(origin) {
return Err(ProcessMessageError::Unsupported)
} else {
Ok(ControlFlow::Continue(()))
},
yrong marked this conversation as resolved.
Show resolved Hide resolved
_ => Ok(ControlFlow::Continue(())),
},
) {
Ok(_) => None,
Err(error) => Some(error),
}
}
}
2 changes: 2 additions & 0 deletions cumulus/parachains/runtimes/bridge-hubs/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
// limitations under the License.
#![cfg_attr(not(feature = "std"), no_std)]

pub mod barriers;
pub mod digest_item;
pub mod message_queue;
pub mod xcm_version;

pub use barriers::DenyExportMessageFrom;
pub use digest_item::CustomDigestItem;
pub use message_queue::{AggregateMessageOrigin, BridgeHubMessageRouter};
140 changes: 140 additions & 0 deletions cumulus/parachains/runtimes/bridge-hubs/common/tests/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Cumulus.

// Cumulus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Cumulus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.

#![cfg(test)]
use bridge_hub_common::DenyExportMessageFrom;
use frame_support::{
assert_err, assert_ok, parameter_types,
traits::{Equals, Everything, EverythingBut, ProcessMessageError},
};
use xcm::prelude::{
AliasOrigin, All, AssetFilter, DepositReserveAsset, Ethereum, ExportMessage, Here, Instruction,
Location, NetworkId, NetworkId::Polkadot, Parachain, Weight, Wild,
};
use xcm_builder::{DenyReserveTransferToRelayChain, DenyThenTry, TakeWeightCredit};
use xcm_executor::traits::{Properties, ShouldExecute};

parameter_types! {
pub AssetHubLocation: Location = Location::new(1, Parachain(1000));
pub ParachainLocation: Location = Location::new(1, Parachain(2000));
pub EthereumNetwork: NetworkId = Ethereum { chain_id: 1 };
}

#[test]
fn deny_export_message_from_source_other_than_asset_hub_should_work() {
pub type Barrier = DenyThenTry<
bkontur marked this conversation as resolved.
Show resolved Hide resolved
(
DenyReserveTransferToRelayChain,
DenyExportMessageFrom<EverythingBut<Equals<AssetHubLocation>>, Equals<EthereumNetwork>>,
),
TakeWeightCredit,
>;

let mut xcm: Vec<Instruction<()>> = vec![
AliasOrigin(Here.into()),
ExportMessage {
network: EthereumNetwork::get(),
destination: Here,
xcm: Default::default(),
},
];

let result = Barrier::should_execute(
&ParachainLocation::get(),
&mut xcm,
Weight::zero(),
&mut Properties { weight_credit: Weight::zero(), message_id: None },
);

assert_err!(result, ProcessMessageError::Unsupported);
}

#[test]
fn allow_export_message_from_asset_hub_should_work() {
pub type Barrier = DenyThenTry<
(
DenyReserveTransferToRelayChain,
DenyExportMessageFrom<EverythingBut<Equals<AssetHubLocation>>, Equals<EthereumNetwork>>,
),
TakeWeightCredit,
>;

let mut xcm: Vec<Instruction<()>> = vec![
AliasOrigin(Here.into()),
ExportMessage {
network: EthereumNetwork::get(),
destination: Here,
xcm: Default::default(),
},
];

let result = Barrier::should_execute(
&AssetHubLocation::get(),
&mut xcm,
Weight::zero(),
&mut Properties { weight_credit: Weight::zero(), message_id: None },
);

assert_ok!(result);
}

#[test]
fn allow_export_message_from_source_other_than_asset_hub_if_destination_other_than_ethereum() {
pub type Barrier = DenyThenTry<
(
DenyReserveTransferToRelayChain,
DenyExportMessageFrom<EverythingBut<Equals<AssetHubLocation>>, Equals<EthereumNetwork>>,
),
TakeWeightCredit,
>;

let mut xcm: Vec<Instruction<()>> = vec![
AliasOrigin(Here.into()),
ExportMessage { network: Polkadot, destination: Here, xcm: Default::default() },
];

let result = Barrier::should_execute(
&ParachainLocation::get(),
&mut xcm,
Weight::zero(),
&mut Properties { weight_credit: Weight::zero(), message_id: None },
);

assert_ok!(result);
}

#[test]
fn deny_reserver_transfer_to_relaychain_does_not_break() {
bkontur marked this conversation as resolved.
Show resolved Hide resolved
pub type Barrier = DenyThenTry<
(DenyReserveTransferToRelayChain, DenyExportMessageFrom<Everything, Everything>),
TakeWeightCredit,
>;

let mut xcm: Vec<Instruction<()>> = vec![DepositReserveAsset {
assets: AssetFilter::try_from(Wild(All)).unwrap(),
dest: Location { parents: 1, interior: Here },
xcm: Default::default(),
}];

let result = Barrier::should_execute(
&Here.into(),
&mut xcm,
Weight::zero(),
&mut Properties { weight_credit: Weight::zero(), message_id: None },
);

assert_err!(result, ProcessMessageError::Unsupported);
}
28 changes: 15 additions & 13 deletions polkadot/xcm/xcm-builder/src/barriers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use frame_support::{
};
use polkadot_parachain_primitives::primitives::IsSystem;
use xcm::prelude::*;
use xcm_executor::traits::{CheckSuspension, OnResponse, Properties, ShouldExecute};
use xcm_executor::traits::{CheckSuspension, DenyExecution, OnResponse, Properties, ShouldExecute};

/// Execution barrier that just takes `max_weight` from `properties.weight_credit`.
///
Expand Down Expand Up @@ -444,12 +444,12 @@ impl ShouldExecute for AllowHrmpNotificationsFromRelayChain {
/// If it passes the Deny, and matches one of the Allow cases then it is let through.
pub struct DenyThenTry<Deny, Allow>(PhantomData<Deny>, PhantomData<Allow>)
where
Deny: ShouldExecute,
Deny: DenyExecution,
Allow: ShouldExecute;

impl<Deny, Allow> ShouldExecute for DenyThenTry<Deny, Allow>
where
Deny: ShouldExecute,
Deny: DenyExecution,
Allow: ShouldExecute,
{
fn should_execute<RuntimeCall>(
Expand All @@ -458,21 +458,23 @@ where
max_weight: Weight,
properties: &mut Properties,
) -> Result<(), ProcessMessageError> {
Deny::should_execute(origin, message, max_weight, properties)?;
Allow::should_execute(origin, message, max_weight, properties)
match Deny::deny_execution(origin, message, max_weight, properties) {
Some(err) => Err(err),
None => Allow::should_execute(origin, message, max_weight, properties),
}
}
}

// See issue <https://github.com/paritytech/polkadot/issues/5233>
pub struct DenyReserveTransferToRelayChain;
impl ShouldExecute for DenyReserveTransferToRelayChain {
fn should_execute<RuntimeCall>(
impl DenyExecution for DenyReserveTransferToRelayChain {
fn deny_execution<RuntimeCall>(
origin: &Location,
message: &mut [Instruction<RuntimeCall>],
_max_weight: Weight,
_properties: &mut Properties,
) -> Result<(), ProcessMessageError> {
message.matcher().match_next_inst_while(
) -> Option<ProcessMessageError> {
match message.matcher().match_next_inst_while(
|_| true,
|inst| match inst {
InitiateReserveWithdraw {
Expand All @@ -498,9 +500,9 @@ impl ShouldExecute for DenyReserveTransferToRelayChain {

_ => Ok(ControlFlow::Continue(())),
},
)?;

// Permit everything else
Ok(())
) {
Ok(_) => None,
Err(err) => Some(err),
}
}
}
2 changes: 1 addition & 1 deletion polkadot/xcm/xcm-executor/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub use on_response::{OnResponse, QueryHandler, QueryResponseStatus, VersionChan
mod process_transaction;
pub use process_transaction::ProcessTransaction;
mod should_execute;
pub use should_execute::{CheckSuspension, Properties, ShouldExecute};
pub use should_execute::{CheckSuspension, DenyExecution, Properties, ShouldExecute};
mod transact_asset;
pub use transact_asset::TransactAsset;
mod hrmp;
Expand Down
63 changes: 63 additions & 0 deletions polkadot/xcm/xcm-executor/src/traits/should_execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,66 @@ impl CheckSuspension for Tuple {
false
}
}

/// Trait to determine whether the execution engine should not execute a given XCM.
///
/// Can be amalgamated into a tuple to have multiple trials. If any of the tuple elements returns
bkontur marked this conversation as resolved.
Show resolved Hide resolved
/// `Err(())`, the execution stops. Else, `Ok(_)` is returned if all elements accept the message.
pub trait DenyExecution {
/// Returns `Ok(())` means there is no reason not to execute the message
/// while Err(e) indicates there is a reason not to execute.
bkontur marked this conversation as resolved.
Show resolved Hide resolved
///
/// - `origin`: The origin (sender) of the message.
/// - `instructions`: The message itself.
/// - `max_weight`: The (possibly over-) estimation of the weight of execution of the message.
/// - `properties`: Various pre-established properties of the message which may be mutated by
/// this API.
fn deny_execution<RuntimeCall>(
origin: &Location,
instructions: &mut [Instruction<RuntimeCall>],
max_weight: Weight,
properties: &mut Properties,
) -> Option<ProcessMessageError>;
Copy link
Contributor

Choose a reason for hiding this comment

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

nitish: using Result instead of Option would be idiomatic here.

Suggested change
) -> Option<ProcessMessageError>;
) -> Result<(), ProcessMessageError>;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The original version is something like that. @bkontur left some concerns in
#7169 (comment) which make sense to me, so we made the change accordingly.

Copy link
Contributor

Choose a reason for hiding this comment

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

I understand it better with the Option because seeing Some(_) makes me guess it will be denied but seeing Ok(_) makes me doubt whether or not it's okay to deny or okay to pass.

To clear up all possible misunderstanding we could use a custom enum:

enum DenyResult {
  Deny,
  DontDeny,
}

Might be overkill though.

Copy link
Contributor Author

@yrong yrong Jan 25, 2025

Choose a reason for hiding this comment

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

Miss the comment in another thread #7169 (comment)

@franciscoaguirre seems others prefer more to Result<(), ProcessMessageError>, but thanks for the comment here anyway.

}

#[impl_trait_for_tuples::impl_for_tuples(30)]
yrong marked this conversation as resolved.
Show resolved Hide resolved
impl DenyExecution for Tuple {
fn deny_execution<RuntimeCall>(
origin: &Location,
instructions: &mut [Instruction<RuntimeCall>],
max_weight: Weight,
properties: &mut Properties,
) -> Option<ProcessMessageError> {
for_tuples!( #(
let barrier = core::any::type_name::<Tuple>();
match Tuple::deny_execution(origin, instructions, max_weight, properties) {
Some(error) => {
tracing::trace!(
bkontur marked this conversation as resolved.
Show resolved Hide resolved
target: "xcm::should_execute",
bkontur marked this conversation as resolved.
Show resolved Hide resolved
yrong marked this conversation as resolved.
Show resolved Hide resolved
?origin,
?instructions,
?max_weight,
?properties,
?error,
%barrier,
"did not pass barrier",
);
return Some(error);
},
None => {
tracing::trace!(
target: "xcm::should_execute",
bkontur marked this conversation as resolved.
Show resolved Hide resolved
yrong marked this conversation as resolved.
Show resolved Hide resolved
?origin,
?instructions,
?max_weight,
?properties,
%barrier,
"pass barrier",
);
},
}
)* );

None
}
}
Loading
Loading