Skip to content

fix(xcm): use Outcome::Incomplete for barrier rejection and improve weight accounting#11302

Open
Kanasjnr wants to merge 8 commits intoparitytech:masterfrom
Kanasjnr:kanas/fix-xcm-barrier-rejection-weight
Open

fix(xcm): use Outcome::Incomplete for barrier rejection and improve weight accounting#11302
Kanasjnr wants to merge 8 commits intoparitytech:masterfrom
Kanasjnr:kanas/fix-xcm-barrier-rejection-weight

Conversation

@Kanasjnr
Copy link
Copy Markdown
Contributor

@Kanasjnr Kanasjnr commented Mar 8, 2026

Description

This PR improves XCM weight accounting by ensuring the executor reports precise used weight when a message is rejected by a barrier. Previously, the executor could overestimate weight (e.g., returning the full message weight) even if execution failed at the barrier stage.
The changes align with the goal of more accurate weight reporting started in PR #7843 and ensure that Outcome::Incomplete is used with the specific weight consumed by the barrier itself.
Closes #7965

Integration

Downstream projects using staging-xcm-builder barriers may need to update their configurations if they wish to provide precise benchmarked weights for barrier checks:

  • New Trait: Barriers are now generic over a WeightInfo trait defined in xcm-builder.
  • Backward Compatibility: A default WeightInfo implementation for () is provided which returns zero weight, so existing XcmConfig definitions will continue to compile without changes.
  • Trait Signature Change: The ShouldExecute trait signature was updated to return Result<Weight, (Weight, ProcessMessageError)> to allow returning consumed weight on error.

Review Notes

Implementation Details

  1. Barrier Refactoring:
    • Introduced WeightInfo in xcm-builder::barriers.
    • Refactored barriers (e.g., TakeWeightCredit, AllowUnpaidExecutionFrom) to be generic over WeightInfo.
    • Updated wrapper barriers (WithComputedOrigin, RespectSuspension, etc.) to correctly aggregate and pass through weights and errors from their inner barriers.
  2. XCM Executor Updates:
    • Modified XcmExecutor::execute to handle Err((weight, error)) from the barrier, returning Outcome::Incomplete { used: weight, error: InstructionError { index: 0, error: XcmError::Barrier } }.
    • Ensured post_process correctly accounts for this used weight.
  3. Bug Fixes:
    • Fixed a pre-existing test failure in DenyReserveTransferToRelayChain by adding an exception for the Relay Chain origin (Location { parents: 1, interior: Here }), which allows the Relay Chain to transfer reserve assets to itself as expected by the tests.
  4. Verification:
    • Added a new scenario test recursive_xcm_execution_fail that uses a custom TestWeightInfo. This test proves the executor now reports the precise 1,000 unit weight assigned to the barrier, whereas it previously overestimated this as the full 3,000,000,000 unit message weight.
    • All 17 barrier unit tests in xcm-builder and 40 unit tests in xcm-executor pass.

Checklist

  • My PR includes a detailed description as outlined in the "Description" and its two subsections above.
  • My PR follows the labeling requirements of this project (at minimum one label for T required)
  • I have made corresponding changes to the documentation.
  • I have added tests that prove my fix is effective or that my feature works.

Bot Commands

You can use the following bot commands in comments to help manage your PR:

Labeling (Self-service for contributors):

  • /cmd label T1-FRAME - Add a single label
  • /cmd label T1-FRAME R0-no-crate-publish-required - Add multiple labels
  • /cmd label T6-XCM D2-substantial I5-enhancement - Add multiple labels at once
  • See label documentation for all available labels

Other useful commands:

  • /cmd fmt - Format code (cargo +nightly fmt and taplo)
  • /cmd prdoc - Generate PR documentation
  • /cmd bench - Run benchmarks
  • /cmd update-ui - Update UI tests
  • /cmd --help - Show help for all available commands

@Kanasjnr Kanasjnr requested a review from a team as a code owner March 8, 2026 12:14
@Kanasjnr
Copy link
Copy Markdown
Contributor Author

Kanasjnr commented Mar 8, 2026

/cmd label T6-XCM D2-substantial I5-enhancement

@Kanasjnr
Copy link
Copy Markdown
Contributor Author

Kanasjnr commented Mar 8, 2026

/cmd prdoc --audience runtime_dev --bump patch

@paritytech-cmd-bot-polkadot-sdk paritytech-cmd-bot-polkadot-sdk bot added D2-substantial Can be fixed by an experienced coder with a working knowledge of the codebase. I5-enhancement An additional feature request. T6-XCM This PR/Issue is related to XCM. labels Mar 8, 2026
@Kanasjnr
Copy link
Copy Markdown
Contributor Author

Kanasjnr commented Mar 9, 2026

@bkontur @franciscoaguirre @raymondkfcheung
Kindly help review

@raymondkfcheung
Copy link
Copy Markdown
Contributor

Do you check the original PR #9808?

@Kanasjnr
Copy link
Copy Markdown
Contributor Author

Kanasjnr commented Mar 12, 2026

Do you check the original PR #9808?

No I didn't it was closed so I didn't bother to check and moreover it was not referenced in the issue description

Copy link
Copy Markdown
Contributor

@franciscoaguirre franciscoaguirre left a comment

Choose a reason for hiding this comment

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

I would definitely test this out on one of the westend runtimes

@@ -26,19 +26,58 @@ use polkadot_parachain_primitives::primitives::IsSystem;
use xcm::prelude::*;
use xcm_executor::traits::{CheckSuspension, DenyExecution, OnResponse, Properties, ShouldExecute};

/// Benchmark weights for this pallet.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not a pallet

@@ -26,19 +26,58 @@ use polkadot_parachain_primitives::primitives::IsSystem;
use xcm::prelude::*;
use xcm_executor::traits::{CheckSuspension, DenyExecution, OnResponse, Properties, ShouldExecute};

/// Benchmark weights for this pallet.
pub trait WeightInfo {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We shouldn't require runtimes to implement this for each one of these barriers when they might not even use all of them or they might use their own custom one.

It might be better to have a trait with just one function weight() -> Weight.

@paritytech-review-bot paritytech-review-bot bot requested a review from a team March 18, 2026 04:18
@Kanasjnr
Copy link
Copy Markdown
Contributor Author

@franciscoaguirre updated!! kindly review

Copy link
Copy Markdown
Contributor

@franciscoaguirre franciscoaguirre left a comment

Choose a reason for hiding this comment

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

Please benchmark these for the westend runtimes to see how it would look like. Right now this change is just floating there


pub use chain::{
AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, Chain, EncodedOrDecodedCall, HashOf,
__private, AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, Chain, EncodedOrDecodedCall, HashOf,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This doesn't look right...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

i was trying to fix fmt ci earlier i reverted it already tho will push the fix soon as soon as i'm done addressing the feedbacks

Comment on lines +249 to +253
#[cfg(feature = "runtime-benchmarks")]
assert_eq!(r, Outcome::Complete { used: weight });

#[cfg(feature = "runtime-benchmarks")]
mock::clear_sent_xcm();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Seems pretty fragile to do conditional compilation on a line-by-line basis here. Is there something you could do to avoid that?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hmm.. true .i will refector this by introducing a helper function assert_teleport_outcome that encapsulates the conditional logic. This will keep the test cases clean and uniform across different configurations.

Comment on lines +605 to +607
if origin == &(Location { parents: 1, interior: Here }) {
return Ok(());
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This change seems unrelated to the rest of the PR. What is it for?

This barrier is not even needed anymore, we now do this check directly on the xcm-executor

@Kanasjnr
Copy link
Copy Markdown
Contributor Author

@franciscoaguirre I've addressed the feedback from the previous review and verified the changes with benchmarks and full test runs
please take a look!

Copy link
Copy Markdown
Contributor

@franciscoaguirre franciscoaguirre left a comment

Choose a reason for hiding this comment

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

The approach in #9808 was to have each runtime benchmark only once for their Barrier tuple in the worst case that the barrier does a lot of work before failing.

The approach taken in this PR is to benchmark each barrier individually. While this is more accurate, it requires every runtime to benchmark each of these barriers. We might be able to provide static weights for some barriers but it's still a lot of complexity for runtime developers.

I would go for something like #9808. What do you think?

@Kanasjnr
Copy link
Copy Markdown
Contributor Author

The approach in #9808 was to have each runtime benchmark only once for their Barrier tuple in the worst case that the barrier does a lot of work before failing.

The approach taken in this PR is to benchmark each barrier individually. While this is more accurate, it requires every runtime to benchmark each of these barriers. We might be able to provide static weights for some barriers but it's still a lot of complexity for runtime developers.

I would go for something like #9808. What do you think?

I've looked at the #9808 approach, but I'm worried it's a bit too blunt for long-term XCM weight accounting. A single "worst-case" fee for the entire barrier tuple feels like it’ll either over charge for simple rejections or under charge if the worst case scenario isn't perfectly caught across all runtimes.

Benchmarking barriers individually is more precise and fits naturally with how the executor actually processes instructions step-by-step. It also keeps everything transparent if a particular barrier is heavy, it shows up in the weights rather than being buried in an aggregate.

Maybe a better compromise would be to provide static or default weights for the really common or trivial barriers? That would keep the integration simple for most developers without losing the accuracy for more complex setups.

What do you think about that trade off? I can pivot if you still prefer the #9808, but I believe the granular approach is more robust for the long run.

@Kanasjnr
Copy link
Copy Markdown
Contributor Author

@franciscoaguirre Still awaiting your feedback

@Kanasjnr
Copy link
Copy Markdown
Contributor Author

@franciscoaguirre i'm still awaiting feedback on this thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

D2-substantial Can be fixed by an experienced coder with a working knowledge of the codebase. I5-enhancement An additional feature request. T6-XCM This PR/Issue is related to XCM.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Review and Update Outcome::Error Usage in XCM Executor

4 participants