Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
659256b
Initial commit
tiagobndr May 27, 2025
d21b766
Add the XCM Precompile to the Mock Network
tiagobndr May 28, 2025
3126166
Update from github-actions[bot] running command 'fmt'
github-actions[bot] May 28, 2025
8f7fdd4
Merge branch 'master' into tb/integ_xcm_precompile_pallet_xcm
tiagobndr May 28, 2025
ddacec4
fix: PR comments
tiagobndr May 28, 2025
b341837
Merge branch 'master' into tb/integ_xcm_precompile_pallet_xcm
sphamjoli May 28, 2025
9306406
update: test for xcm precompile
sphamjoli May 29, 2025
b963c4f
Merge branch 'master' into tb/integ_xcm_precompile_pallet_xcm
sphamjoli May 29, 2025
240b8ea
update: charge gas for precompile
sphamjoli May 29, 2025
43c77ce
Merge branch 'tb/integ_xcm_precompile_pallet_xcm' of https://github.c…
sphamjoli May 29, 2025
a57e581
Update from github-actions[bot] running command 'fmt'
github-actions[bot] May 29, 2025
26b3f6e
Merge branch 'master' into tb/integ_xcm_precompile_pallet_xcm
tiagobndr May 29, 2025
2bd9c17
fix: PR comments
tiagobndr May 29, 2025
39f124b
Update from github-actions[bot] running command 'fmt'
github-actions[bot] May 29, 2025
e2c632b
Merge branch 'master' into tb/integ_xcm_precompile_pallet_xcm
tiagobndr May 30, 2025
a040a1b
doc: add prdoc
tiagobndr May 30, 2025
10a0a83
Merge branch 'master' into tb/integ_xcm_precompile_pallet_xcm
sphamjoli May 30, 2025
7b7acdc
Merge branch 'master' into tb/integ_xcm_precompile_pallet_xcm
tiagobndr May 30, 2025
3b1ad85
Merge branch 'master' into tb/integ_xcm_precompile_pallet_xcm
tiagobndr May 30, 2025
fd8f350
Merge branch 'tb/integ_xcm_precompile_pallet_xcm' of https://github.c…
sphamjoli May 30, 2025
6442869
Merge branch 'tb/integ_xcm_precompile_pallet_xcm' of https://github.c…
sphamjoli May 30, 2025
ea60b5e
Merge branch 'master' into tb/integ_xcm_precompile_pallet_xcm
sphamjoli May 30, 2025
10e27f9
fix: PR comments
sphamjoli May 30, 2025
2a10514
fix: CI
sphamjoli May 30, 2025
51c4683
fix: CI
sphamjoli May 30, 2025
79d8a5f
Update from github-actions[bot] running command 'fmt'
github-actions[bot] May 30, 2025
56bd6fc
fix: revert changes on charging weight for precompile calls
tiagobndr Jun 2, 2025
6969f17
fix: PR comments
tiagobndr Jun 2, 2025
2b732f4
Merge branch 'master' into tb/integ_xcm_precompile_pallet_xcm
tiagobndr Jun 2, 2025
f1ab023
fix: use depth-limited decoding for XCM messages
tiagobndr Jun 2, 2025
cb26365
fix: add Weight::MAX to the Weigher::weight() call
tiagobndr Jun 2, 2025
b7738d3
Update from github-actions[bot] running command 'fmt'
github-actions[bot] Jun 2, 2025
bf0cfae
Merge branch 'master' into tb/integ_xcm_precompile_pallet_xcm
athei Jun 2, 2025
eea0712
feat(xcm-precompile): refund excess weight
franciscoaguirre Jun 2, 2025
d46a1e8
fix(pallet-revive): use to_usize instead of try_into
franciscoaguirre Jun 2, 2025
6c9d83c
fix: fmt
franciscoaguirre Jun 2, 2025
8c57620
Merge branch 'master' into tb/integ_xcm_precompile_pallet_xcm
franciscoaguirre Jun 2, 2025
fa2dd49
Merge branch 'master' into tb/integ_xcm_precompile_pallet_xcm
sphamjoli Jun 2, 2025
859193c
fix: PR comments
tiagobndr Jun 3, 2025
e1694a9
fix: PR comment regarding removing Clone
tiagobndr Jun 3, 2025
7a6c735
Update from github-actions[bot] running command 'fmt'
github-actions[bot] Jun 3, 2025
6ec2d74
Merge branch 'master' into tb/integ_xcm_precompile_pallet_xcm
tiagobndr Jun 3, 2025
bf67b1e
Update substrate/frame/revive/src/precompiles/builtin/modexp.rs
franciscoaguirre Jun 3, 2025
f5ae802
fix: add benchmarks for weigh_message
tiagobndr Jun 3, 2025
56872ec
run benchmarks for westend and add todos for all runtimes
tiagobndr Jun 4, 2025
09bdb41
Update from github-actions[bot] running command 'fmt'
github-actions[bot] Jun 4, 2025
742c423
Merge branch 'master' into tb/integ_xcm_precompile_pallet_xcm
tiagobndr Jun 4, 2025
723d3ea
fix: move XCM precompile tests from mod.rs to precompiles.rs
tiagobndr Jun 4, 2025
06627c7
fix: add weigh_message benchmark to all runtimes
tiagobndr Jun 4, 2025
ab76d38
Update from github-actions[bot] running command 'fmt'
github-actions[bot] Jun 4, 2025
5368ddf
fix: clippy
franciscoaguirre Jun 4, 2025
7bcb6cf
fix(xcm-precompile): add execute weight info
franciscoaguirre Jun 4, 2025
3024678
Update from github-actions[bot] running command 'bench --runtime asse…
github-actions[bot] Jun 4, 2025
f674007
fix: handle error in weigh_message benchmark
franciscoaguirre Jun 4, 2025
87f59d3
Merge branch 'master' into tb/integ_xcm_precompile_pallet_xcm
franciscoaguirre Jun 4, 2025
d7dca77
fix: update weights to those from reference hardware
franciscoaguirre Jun 4, 2025
f299795
revert: remove unnecessary changes
franciscoaguirre Jun 4, 2025
0885f63
chore: wrap weight in RuntimeCosts::Precompile inside the function
franciscoaguirre Jun 4, 2025
c708434
fix: add weigh_message benchmark to staking-async
tiagobndr Jun 4, 2025
a29e51b
chore: define LOG_TARGET constant for logging
tiagobndr Jun 4, 2025
5665007
fix: update prdoc
tiagobndr Jun 4, 2025
5333e1f
chore: narrow IXcm import to IXcmCalls
tiagobndr Jun 4, 2025
c87d86e
refactor: introduce revert macro to standardize error logging
tiagobndr Jun 4, 2025
97f58bf
refactor: set ALICE as default mapped account in the genesis config
tiagobndr Jun 4, 2025
c141c83
Update from github-actions[bot] running command 'fmt'
github-actions[bot] Jun 4, 2025
9a1ec3a
Merge branch 'master' into tb/integ_xcm_precompile_pallet_xcm
tiagobndr Jun 4, 2025
fd8fccb
chore: use a function instead of a macro to revert
tiagobndr Jun 5, 2025
8a435b8
Update from github-actions[bot] running command 'fmt'
github-actions[bot] Jun 5, 2025
047d8b5
fix: CI
tiagobndr Jun 5, 2025
43c3a7d
Merge branch 'master' into tb/integ_xcm_precompile_pallet_xcm
tiagobndr Jun 5, 2025
ea843df
Merge branch 'master' into tb/integ_xcm_precompile_pallet_xcm
franciscoaguirre Jun 5, 2025
ac19567
fix: export ALICE from mock network instead
tiagobndr Jun 5, 2025
3b9ac22
Merge branch 'master' into tb/integ_xcm_precompile_pallet_xcm
sphamjoli Jun 6, 2025
a0cbd43
Merge branch 'master' into tb/integ_xcm_precompile_pallet_xcm
sphamjoli Jun 7, 2025
faceac5
fix(xcm-precompile): small weight fix
franciscoaguirre Jun 10, 2025
115ac42
fix: fmt
franciscoaguirre Jun 10, 2025
84f40f7
Merge branch 'master' into tb/integ_xcm_precompile_pallet_xcm
tiagobndr Jun 11, 2025
d5a5f66
Merge branch 'master' into tb/integ_xcm_precompile_pallet_xcm
athei Jun 11, 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.

5 changes: 5 additions & 0 deletions polkadot/xcm/pallet-xcm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ tracing = { workspace = true }

frame-support = { workspace = true }
frame-system = { workspace = true }
pallet-revive = { workspace = true }
sp-core = { workspace = true }
sp-io = { workspace = true }
sp-runtime = { workspace = true }

pallet-timestamp = { workspace = true }
xcm = { workspace = true }
xcm-builder = { workspace = true }
xcm-executor = { workspace = true }
Expand All @@ -49,6 +51,7 @@ std = [
"frame-support/std",
"frame-system/std",
"pallet-balances/std",
"pallet-revive/std",
"scale-info/std",
"serde",
"sp-core/std",
Expand All @@ -66,6 +69,7 @@ runtime-benchmarks = [
"frame-system/runtime-benchmarks",
"pallet-assets/runtime-benchmarks",
"pallet-balances/runtime-benchmarks",
"pallet-revive/runtime-benchmarks",
"polkadot-parachain-primitives/runtime-benchmarks",
"polkadot-runtime-parachains/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
Expand All @@ -80,6 +84,7 @@ try-runtime = [
"frame-system/try-runtime",
"pallet-assets/try-runtime",
"pallet-balances/try-runtime",
"pallet-revive/try-runtime",
"polkadot-runtime-parachains/try-runtime",
"sp-runtime/try-runtime",
]
1 change: 1 addition & 0 deletions polkadot/xcm/pallet-xcm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
pub mod benchmarking;
#[cfg(test)]
mod mock;
pub mod precompiles;
#[cfg(test)]
mod tests;

Expand Down
24 changes: 23 additions & 1 deletion polkadot/xcm/pallet-xcm/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ use xcm_executor::{
};
use xcm_simulator::helpers::derive_topic_id;

use crate::{self as pallet_xcm, TestWeightInfo};
use crate::{self as pallet_xcm, precompiles::XcmPrecompile, TestWeightInfo};
use pallet_timestamp;

pub type AccountId = AccountId32;
pub type Balance = u128;
Expand Down Expand Up @@ -139,6 +140,17 @@ pub mod pallet_test_notifier {
}
}

parameter_types! {
pub const MinimumPeriod: u64 = 1;
}

impl pallet_timestamp::Config for Test {
type Moment = u64;
type OnTimestampSet = ();
type MinimumPeriod = MinimumPeriod;
type WeightInfo = ();
}

construct_runtime!(
pub enum Test
{
Expand All @@ -148,6 +160,8 @@ construct_runtime!(
ParasOrigin: origin,
XcmPallet: pallet_xcm,
TestNotifier: pallet_test_notifier,
Revive: pallet_revive,
Timestamp: pallet_timestamp,
}
);

Expand Down Expand Up @@ -320,6 +334,14 @@ impl pallet_assets::Config for Test {
type BenchmarkHelper = XcmBenchmarkHelper;
}

#[derive_impl(pallet_revive::config_preludes::TestDefaultConfig)]
impl pallet_revive::Config for Test {
type AddressMapper = pallet_revive::AccountId32Mapper<Self>;
type Currency = Balances;
type Precompiles = (XcmPrecompile<Self>,);
type Time = Timestamp;
}

// This child parachain is a system parachain trusted to teleport native token.
pub const SOME_SYSTEM_PARA: u32 = 1001;

Expand Down
135 changes: 135 additions & 0 deletions polkadot/xcm/pallet-xcm/src/precompiles.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// This file is part of Substrate.

// 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.
Comment thread
tiagobndr marked this conversation as resolved.
Outdated

use crate::{Call, Config, VersionedLocation, VersionedXcm, Weight, WeightInfo};
use alloc::vec::Vec;
use alloy::sol_types::SolValue;
use codec::{DecodeAll, Encode};
use core::{marker::PhantomData, num::NonZero};
use pallet_revive::{precompiles::*, Origin};
use tracing::log::error;
use xcm_executor::traits::WeightBounds;

alloy::sol!("src/precompiles/IXcm.sol");
use IXcm::*;
Comment thread
franciscoaguirre marked this conversation as resolved.
Outdated

pub struct XcmPrecompile<T>(PhantomData<T>);

impl<Runtime> Precompile for XcmPrecompile<Runtime>
Comment thread
tiagobndr marked this conversation as resolved.
where
Runtime: crate::Config + pallet_revive::Config,
Call<Runtime>: Into<<Runtime as pallet_revive::Config>::RuntimeCall>,
{
type T = Runtime;
const MATCHER: AddressMatcher = AddressMatcher::Fixed(NonZero::new(10).unwrap());
const HAS_CONTRACT_INFO: bool = false;
Comment thread
acatangiu marked this conversation as resolved.
type Interface = IXcm::IXcmCalls;

fn call(
_address: &[u8; 20],
input: &Self::Interface,
env: &mut impl Ext<T = Self::T>,
) -> Result<Vec<u8>, Error> {
let origin = env.caller();
let frame_origin = match origin {
Origin::Root => frame_system::RawOrigin::Root.into(),
Origin::Signed(account_id) =>
frame_system::RawOrigin::Signed(account_id.clone()).into(),
};

match input {
IXcmCalls::xcmSend(IXcm::xcmSendCall { destination, message }) => {
let _weight = <Runtime as Config>::WeightInfo::send();
// TODO: Charge gas for the weight

let final_destination = VersionedLocation::decode_all(&mut &destination[..])
.map_err(|e| {
error!("XCM send failed: Invalid destination format. Error: {e:?}");
Comment thread
raymondkfcheung marked this conversation as resolved.
Outdated
Error::Revert("Invalid destination format".into())
})?;

let final_message =
VersionedXcm::<()>::decode_all(&mut &message[..]).map_err(|e| {
error!("XCM send failed: Invalid message format. Error: {e:?}");
Error::Revert("Invalid message format".into())
Comment thread
raymondkfcheung marked this conversation as resolved.
Outdated
})?;

crate::Pallet::<Runtime>::send(
frame_origin,
final_destination.into(),
final_message.into(),
)
.map(|message_id| message_id.encode())
.map_err(|e| {
error!(
"XCM send failed: destination or message format may be incompatible. \
Error: {e:?}"
);
Error::Revert(
"XCM send failed: destination or message format may be incompatible".into(),
)
})
},
IXcmCalls::xcmExecute(IXcm::xcmExecuteCall { message, weight }) => {
let final_message = VersionedXcm::decode_all(&mut &message[..]).map_err(|e| {
error!("XCM execute failed: Invalid message format. Error: {e:?}");
Error::Revert("Invalid message format".into())
Comment thread
raymondkfcheung marked this conversation as resolved.
Outdated
})?;

let weight = Weight::from_parts(weight.refTime, weight.proofSize);
// env.gas_meter_mut().charge(RuntimeCosts::CallXcmExecute(weight.clone()))?; //
// TODO: Charge gas

crate::Pallet::<Runtime>::execute(frame_origin, final_message.into(), weight)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We are missing a weight refund here.

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.

Please check if the solution is good

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.

don't we want to

env.charge(<Runtime as Config>::WeightInfo::execute());

as well?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

No need to handle it twice. Use this function: https://paritytech.github.io/polkadot-sdk/master/frame_support/dispatch/fn.extract_actual_weight.html

Then you don't need to clone the value either.

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.

@athei can you please review my impl?

.map(|results| results.encode())
.map_err(|e| {
error!(
"XCM execute failed: message may be invalid or execution \
constraints not satisfied. Error: {e:?}"
);
Error::Revert(
"XCM execute failed: message may be invalid or execution \
constraints not satisfied"
.into(),
)
})
},
IXcmCalls::weighMessage(IXcm::weighMessageCall { message }) => {
let converted_message =
VersionedXcm::decode_all(&mut &message[..]).map_err(|error| {
error!("XCM weightMessage: Invalid message format. Error: {error:?}");
Error::Revert("XCM weightMessage: Invalid message format".into())
})?;

let mut final_message = converted_message.try_into().map_err(|e| {
error!("XCM weightMessage: Conversion to Xcm failed with Error: {e:?}");
Error::Revert("XCM weightMessage: Conversion to Xcm failed".into())
})?;

let weight = <<Runtime>::Weigher>::weight(&mut final_message).map_err(|e| {
error!("XCM weightMessage: Failed to calculate weight. Error: {e:?}");
Error::Revert("XCM weightMessage: Failed to calculate weight".into())
})?;

let final_weight =
IXcm::Weight { proofSize: weight.proof_size(), refTime: weight.ref_time() };

Ok(final_weight.abi_encode())
},
}
}
}
30 changes: 30 additions & 0 deletions polkadot/xcm/pallet-xcm/src/precompiles/IXcm.sol
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.

@franciscoaguirre we don't want to put that in the ethereum-standards crate ?

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.

It's not an ethereum standard

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.

I thought the crate would hold ever sol files

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.

I would only hold ethereum standards, else we should change the name of the crate

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Depends on whether the XCM.sol file needs to be shared with other pallets or not. Right now it doesn't . So it should be fine to leave it there for now.

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: MIT
Comment thread
tiagobndr marked this conversation as resolved.
pragma solidity ^0.8.20;

/// @title Defines all functions that can be used to interact with XCM
/// @author Tiago Bandeira
Comment thread
tiagobndr marked this conversation as resolved.
Outdated
/// @dev Parameters MUST use SCALE codec serialisation
interface IXcm {
/// Weight v2
struct Weight {
/// The computational time used to execute some logic based on reference hardware
uint64 refTime;
/// The size of the proof needed to execute some logic
uint64 proofSize;
}
Comment thread
tiagobndr marked this conversation as resolved.

/// @notice Execute a Versioned XCM message locally with the caller's origin
/// @param message The Versioned XCM message to send
/// @param weight The maximum amount of weight to be used to execute the message
function xcmExecute(bytes calldata message, Weight calldata weight) external;
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 don't return anything from either xcmExecute or xcmSend, should we at least let the caller know if it was successful? Or we just revert?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What about emitting an event @franciscoaguirre

Copy link
Copy Markdown
Contributor Author

@tiagobndr tiagobndr May 28, 2025

Choose a reason for hiding this comment

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

What about emitting an event @franciscoaguirre

We get that out of the box from calling pallet_xcm::send() or pallet_xcm::execute() - e.g. here

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.

We don't return anything from either xcmExecute or xcmSend, should we at least let the caller know if it was successful? Or we just revert?

From the call to the precompile, we get back whatever gets returned from pallet_xcm::send() or pallet_xcm::execute(). It's just that we don't explicitly set it in the interface because we don't know its type in advance

Copy link
Copy Markdown
Member

@xermicus xermicus Jun 6, 2025

Choose a reason for hiding this comment

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

I don't like this interface. In practice, as @franciscoaguirre pointed out, how would you even know if it succeeded or not?

I suggest to version the interface in one way or the other, such that it will remain stable (then return values are possible - even if they are just untyped bytes[] the caller at least get's a chance to decode them, can be added later).

Copy link
Copy Markdown
Member

@xermicus xermicus Jun 6, 2025

Choose a reason for hiding this comment

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

FWIW if the precompile reverts on errors, callers can at least check the call success variable in Solidity. But versioning it explicitly still seems like a good idea to me. Unless to whatever this is calling into is absolutely stable forever? I can't really imagine that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

And those things should be documented in the interface as well.

Copy link
Copy Markdown
Member

@xermicus xermicus Jun 6, 2025

Choose a reason for hiding this comment

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

And pleases also consider this: Given the precompile reverts on error, any change in the conditions when reverts happen is a breaking change. Unless I am missing things I don't yet see how this will work out unless we get a mapping of exactly one (versioned) interface to one precompile contract address.


/// @notice Send an Versioned XCM message to a destination chain
/// @param destination The destination location, encoded according to the XCM format
/// @param message The Versioned XCM message to send
function xcmSend(bytes calldata destination, bytes calldata message) external;

/// @notice Given a message estimate the weight cost
/// @param message The XCM message to send
/// @returns weight estimated for sending the message
function weighMessage(bytes calldata message) external view returns (Weight weight);
}
Loading
Loading