Skip to content

Commit

Permalink
Add xcm integration (#1912)
Browse files Browse the repository at this point in the history
Expose xcm_execute and xcm_send host functions to ink!
  • Loading branch information
pgherveou authored Apr 26, 2024
1 parent 370a495 commit eeae6c9
Show file tree
Hide file tree
Showing 19 changed files with 478 additions and 13 deletions.
1 change: 1 addition & 0 deletions .config/cargo_spellcheck.dic
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,4 @@ DRink
^
externalities
sandbox_client
xcm
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@ jobs:
# - custom_allocator
# Pulls in sp-std which needlessly requires atomic pointers (TODO: Fix sp-std and enable this example)
# - call-runtime
scripts/for_all_contracts_exec.sh --path integration-tests --ignore public/custom-allocator --ignore public/call-runtime \
scripts/for_all_contracts_exec.sh --path integration-tests --ignore public/custom-allocator --ignore public/call-runtime --ignore public/contract-xcm \
-- cargo build --manifest-path {} --no-default-features --target $RISCV_TARGET -Zbuild-std="core,alloc"
examples-docs:
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added
- [Linter] Add links to detailed lint description ‒ [#2170](https://github.com/use-ink/ink/pull/2170)
- Add `xcm_execute` and `xcm_send` support - [#1912](https://github.com/paritytech/ink/pull/1912)
- Environment agnostic contract invocation API ‒ [#219](https://github.com/use-ink/ink/pull/2219)

### Changed
Expand Down
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.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ sp-core = { version = "32.0.0", default-features = false }
sp-keyring = { version = "35.0.0", default-features = false }
sp-runtime = { version = "35.0.0", default-features = false }
sp-weights = { version = "31.0.0", default-features = false }
xcm = { package = "staging-xcm", version = "11.0.0", default-features = false }

# Local dependencies
ink = { version = "=5.0.0", path = "crates/ink", default-features = false }
Expand Down
2 changes: 1 addition & 1 deletion crates/e2e/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ std = [
"ink_e2e_macro/std",
"ink_sandbox/std",
"frame-support/std",
"pallet-contracts-mock-network?/std"
"pallet-contracts-mock-network?/std",
]

sandbox = [
Expand Down
5 changes: 4 additions & 1 deletion crates/e2e/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ pub use node_proc::{
TestNodeProcessBuilder,
};
#[cfg(feature = "sandbox")]
pub use sandbox_client::Client as SandboxClient;
pub use sandbox_client::{
preset,
Client as SandboxClient,
};
pub use sp_core::H256;
pub use sp_keyring::AccountKeyring;
pub use subxt::{
Expand Down
13 changes: 11 additions & 2 deletions crates/e2e/src/sandbox_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,18 +483,27 @@ pub mod preset {
/// }
/// ```
#[derive(Default)]
pub struct MockNetworkSandbox;
pub struct MockNetworkSandbox {
dry_run: bool,
}

impl Sandbox for MockNetworkSandbox {
type Runtime = parachain::Runtime;

fn execute_with<T>(&mut self, execute: impl FnOnce() -> T) -> T {
ParaA::execute_with(execute)
if self.dry_run {
ParaA::execute_with(execute)
} else {
ParaA::execute_without_dispatch(execute)
}
}

fn dry_run<T>(&mut self, action: impl FnOnce(&mut Self) -> T) -> T {
EXT_PARAA.with(|v| {
let backend_backup = v.borrow_mut().as_backend();
self.dry_run = true;
let result = action(self);
self.dry_run = false;

let mut v = v.borrow_mut();
v.commit_all().expect("Failed to commit changes");
Expand Down
14 changes: 8 additions & 6 deletions crates/env/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ cfg-if = { workspace = true }
paste = { workspace = true }
static_assertions = { workspace = true }
const_env = { workspace = true }
xcm = { workspace = true }

[target.'cfg(target_arch = "wasm32")'.dependencies]
rlibc = "1"
Expand Down Expand Up @@ -63,22 +64,23 @@ default = [ "std" ]
std = [
"blake2",
"ink_allocator/std",
"ink_engine/std",
"ink_prelude/std",
"ink_primitives/std",
"ink_storage_traits/std",
"num-traits/std",
"ink_engine/std",
"scale/std",
"scale-decode",
"scale-encode",
"scale-info/std",
"scale/std",
"schnorrkel",
"secp256k1",
# Enables hashing crates for off-chain environment.
"schnorrkel",
"num-traits/std",
# Enables hashing crates for off-chain environment.
"sha2",
"sha3",
"scale-decode?/std",
"scale-encode?/std"
"scale-encode?/std",
"xcm/std"
]

# Enable contract debug messages via `debug_print!` and `debug_println!`.
Expand Down
51 changes: 51 additions & 0 deletions crates/env/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -903,3 +903,54 @@ where
instance.unlock_delegate_dependency::<E>(code_hash)
})
}

/// Execute an XCM message locally, using the contract's address as the origin.
///
/// For more details consult the
/// [host function documentation](https://paritytech.github.io/substrate/master/pallet_contracts/api_doc/trait.Current.html#tymethod.xcm_execute).
///
/// # Errors
///
/// - If the message cannot be properly decoded on the `pallet-contracts` side.
/// - If the XCM execution fails because of the runtime's XCM configuration.
///
/// # Panics
///
/// Panics in the off-chain environment.
pub fn xcm_execute<E, Call>(msg: &xcm::VersionedXcm<Call>) -> Result<()>
where
E: Environment,
Call: scale::Encode,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
TypedEnvBackend::xcm_execute::<E, _>(instance, msg)
})
}

/// Send an XCM message, using the contract's address as the origin.
///
/// The `msg` argument has to be SCALE encoded, it needs to be decodable to a valid
/// instance of the `RuntimeCall` enum.
///
/// For more details consult
/// [host function documentation](https://paritytech.github.io/substrate/master/pallet_contracts/api_doc/trait.Current.html#tymethod.xcm_send).
///
/// # Errors
///
/// - If the message cannot be properly decoded on the `pallet-contracts` side.
///
/// # Panics
///
/// Panics in the off-chain environment.
pub fn xcm_send<E, Call>(
dest: &xcm::VersionedLocation,
msg: &xcm::VersionedXcm<Call>,
) -> Result<xcm::v4::XcmHash>
where
E: Environment,
Call: scale::Encode,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
TypedEnvBackend::xcm_send::<E, _>(instance, dest, msg)
})
}
24 changes: 24 additions & 0 deletions crates/env/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -455,4 +455,28 @@ pub trait TypedEnvBackend: EnvBackend {
fn unlock_delegate_dependency<E>(&mut self, code_hash: &E::Hash)
where
E: Environment;

/// Execute an XCM message locally, using the contract's address as the origin.
///
/// # Note
///
/// For more details visit: [`xcm`][`crate::xcm_execute`].
fn xcm_execute<E, Call>(&mut self, msg: &xcm::VersionedXcm<Call>) -> Result<()>
where
E: Environment,
Call: scale::Encode;

/// Send an XCM message, using the contract's address as the origin.
///
/// # Note
///
/// For more details visit: [`xcm`][`crate::xcm_send`].
fn xcm_send<E, Call>(
&mut self,
dest: &xcm::VersionedLocation,
msg: &xcm::VersionedXcm<Call>,
) -> Result<xcm::v4::XcmHash>
where
E: Environment,
Call: scale::Encode;
}
18 changes: 18 additions & 0 deletions crates/env/src/engine/off_chain/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,24 @@ impl TypedEnvBackend for EnvInstance {
unimplemented!("off-chain environment does not support delegate dependencies")
}

fn xcm_execute<E, Call>(&mut self, _msg: &xcm::VersionedXcm<Call>) -> Result<()>
where
E: Environment,
{
unimplemented!("off-chain environment does not support `xcm_execute`")
}

fn xcm_send<E, Call>(
&mut self,
_dest: &xcm::VersionedLocation,
_msg: &xcm::VersionedXcm<Call>,
) -> Result<xcm::v4::XcmHash>
where
E: Environment,
{
unimplemented!("off-chain environment does not support `xcm_send`")
}

fn unlock_delegate_dependency<E>(&mut self, _code_hash: &E::Hash)
where
E: Environment,
Expand Down
37 changes: 37 additions & 0 deletions crates/env/src/engine/on_chain/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ use pallet_contracts_uapi::{
ReturnErrorCode,
ReturnFlags,
};
use xcm::VersionedXcm;

impl CryptoHash for Blake2x128 {
fn hash(input: &[u8], output: &mut <Self as HashOutput>::Type) {
Expand Down Expand Up @@ -726,4 +727,40 @@ impl TypedEnvBackend for EnvInstance {
let enc_code_hash = scope.take_encoded(code_hash);
ext::unlock_delegate_dependency(enc_code_hash)
}

fn xcm_execute<E, Call>(&mut self, msg: &VersionedXcm<Call>) -> Result<()>
where
E: Environment,
Call: scale::Encode,
{
let mut scope = self.scoped_buffer();

// Double encoding the message as the host fn expects an encoded message.
let enc_msg = scope.take_encoded(&scale::Encode::encode(msg));
#[allow(deprecated)]
ext::xcm_execute(enc_msg).map_err(Into::into)
}

fn xcm_send<E, Call>(
&mut self,
dest: &xcm::VersionedLocation,
msg: &VersionedXcm<Call>,
) -> Result<xcm::v4::XcmHash>
where
E: Environment,
Call: scale::Encode,
{
let mut scope = self.scoped_buffer();
let output = scope.take(32);
scope.append_encoded(dest);
let enc_dest = scope.take_appended();

// Double encoding the message as the host fn expects an encoded message.
scope.append_encoded(&scale::Encode::encode(msg));
let enc_msg = scope.take_appended();
#[allow(deprecated)]
ext::xcm_send(enc_dest, enc_msg, output.try_into().unwrap())?;
let hash: xcm::v4::XcmHash = scale::Decode::decode(&mut &output[..])?;
Ok(hash)
}
}
3 changes: 2 additions & 1 deletion crates/ink/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ pallet-contracts-uapi = { workspace = true }
scale = { workspace = true }
scale-info = { workspace = true, default-features = false, features = ["derive"], optional = true }
derive_more = { workspace = true, features = ["from"] }
xcm = { workspace = true}

[dev-dependencies]
ink_ir = { workspace = true, default-features = true }
ink_metadata = { workspace = true }

trybuild = { workspace = true, features = ["diff"] }


Expand All @@ -45,6 +45,7 @@ std = [
"ink_storage/std",
"scale-info/std",
"scale/std",
"xcm/std"
]
# Enable contract debug messages via `debug_print!` and `debug_println!`.
ink-debug = [ "ink_env/ink-debug" ]
Expand Down
15 changes: 15 additions & 0 deletions crates/ink/src/env_access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1341,4 +1341,19 @@ where
pub fn unlock_delegate_dependency(self, code_hash: &E::Hash) {
ink_env::unlock_delegate_dependency::<E>(code_hash)
}

pub fn xcm_execute<Call: scale::Encode>(
self,
msg: &xcm::VersionedXcm<Call>,
) -> Result<()> {
ink_env::xcm_execute::<E, _>(msg)
}

pub fn xcm_send<Call: scale::Encode>(
self,
dest: &xcm::VersionedLocation,
msg: &xcm::VersionedXcm<Call>,
) -> Result<xcm::v4::XcmHash> {
ink_env::xcm_send::<E, _>(dest, msg)
}
}
1 change: 1 addition & 0 deletions crates/ink/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ pub use ink_primitives as primitives;
pub use scale;
#[cfg(feature = "std")]
pub use scale_info;
pub use xcm;

pub mod storage {
pub mod traits {
Expand Down
2 changes: 1 addition & 1 deletion crates/primitives/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ use {
From,
)]
#[cfg_attr(feature = "std", derive(TypeInfo, DecodeAsType, EncodeAsType))]
pub struct AccountId([u8; 32]);
pub struct AccountId(pub [u8; 32]);

impl AsRef<[u8; 32]> for AccountId {
#[inline]
Expand Down
27 changes: 27 additions & 0 deletions integration-tests/public/contract-xcm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[package]
name = "contract-xcm"
version = "4.0.0"
authors = ["Parity Technologies <[email protected]>"]
edition = "2021"
publish = false

[dependencies]
ink = { path = "../../../crates/ink", default-features = false }
frame-support = { version = "32.0.0", default-features = false }
pallet-balances = { version = "33.0.0", default-features = false }

[dev-dependencies]
ink_e2e = { path = "../../../crates/e2e", features = ["sandbox"] }

[lib]
path = "lib.rs"

[features]
default = ["std"]
std = [
"ink/std",
"pallet-balances/std",
"frame-support/std",
]
ink-as-dependency = []
e2e-tests = []
Loading

0 comments on commit eeae6c9

Please sign in to comment.