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

Support call_runtime #1641

Merged
merged 60 commits into from
Feb 27, 2023
Merged
Show file tree
Hide file tree
Changes from 59 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
d6f55bc
Basic contract calling runtime
pmikolajczyk41 Feb 3, 2023
d3a1291
Offchain setting
pmikolajczyk41 Feb 3, 2023
7ad9137
Onchain env: reach seal function
pmikolajczyk41 Feb 3, 2023
6a47080
Feature-gating
pmikolajczyk41 Feb 6, 2023
1a6cb26
Pass call
pmikolajczyk41 Feb 6, 2023
6e21f63
Revert - e2e framework doesn't support custom environment
pmikolajczyk41 Feb 6, 2023
4918b82
Use just encodable argument
pmikolajczyk41 Feb 6, 2023
b9503cc
Pass decodable struct (however call is trapped :( )
pmikolajczyk41 Feb 6, 2023
5f5e2ae
Works with 0 transfer
pmikolajczyk41 Feb 6, 2023
ed4a155
Fix
pmikolajczyk41 Feb 6, 2023
9210619
Docs, remove leftovers
pmikolajczyk41 Feb 6, 2023
d80b3bb
Clippy
pmikolajczyk41 Feb 6, 2023
2e3d71c
docline
pmikolajczyk41 Feb 6, 2023
99982d4
Ignore test
pmikolajczyk41 Feb 6, 2023
9943cbe
typo
pmikolajczyk41 Feb 6, 2023
f825412
CHANGELOG.md, example README.md
pmikolajczyk41 Feb 6, 2023
2991153
Update CHANGELOG.md
ascjones Feb 6, 2023
2e7bcb4
Update crates/env/Cargo.toml
SkymanOne Feb 6, 2023
880b84c
Merge remote-tracking branch 'origin/master' into pmikolajczyk41/call…
pmikolajczyk41 Feb 7, 2023
4e69291
Syntactic improvements
pmikolajczyk41 Feb 8, 2023
0f8f142
Comparison to chain extension
pmikolajczyk41 Feb 8, 2023
cc13064
Indices explanation
pmikolajczyk41 Feb 8, 2023
93c535b
Reason for sp-io in deps
pmikolajczyk41 Feb 8, 2023
4ef1ce9
Rename enum variant. Docs. Return result. Failure e2e
pmikolajczyk41 Feb 9, 2023
a15dbce
Env API docs
pmikolajczyk41 Feb 9, 2023
e81fb98
spellcheck
pmikolajczyk41 Feb 9, 2023
9f59e7a
...
pmikolajczyk41 Feb 9, 2023
2285c87
Clean Cargo.toml
pmikolajczyk41 Feb 9, 2023
13225e2
Note about unstable host
pmikolajczyk41 Feb 9, 2023
d4665f9
Remove offline test
pmikolajczyk41 Feb 9, 2023
84dc23e
Rephrase note
pmikolajczyk41 Feb 9, 2023
ee7cfcb
Review
pmikolajczyk41 Feb 9, 2023
ca6238d
Doc about panic in off-chain env
pmikolajczyk41 Feb 9, 2023
89147f1
Add feature instead of ignoring
pmikolajczyk41 Feb 9, 2023
f3073de
Add feature instead of ignoring
pmikolajczyk41 Feb 9, 2023
e981d47
Error
pmikolajczyk41 Feb 10, 2023
db85259
Apply suggestions from code review
pmikolajczyk41 Feb 10, 2023
883739d
Rename variant error
pmikolajczyk41 Feb 10, 2023
dff8d92
PAnics
pmikolajczyk41 Feb 10, 2023
c3fe8f2
Warnign
pmikolajczyk41 Feb 10, 2023
614dae7
#[allow(clippy::enum_variant_names)]
pmikolajczyk41 Feb 10, 2023
315900a
uitest
pmikolajczyk41 Feb 10, 2023
1dfd5f5
uitest
pmikolajczyk41 Feb 10, 2023
560b954
Merge remote-tracking branch 'origin/master' into pmikolajczyk41/call…
pmikolajczyk41 Feb 13, 2023
23f71a5
Missing testcases
pmikolajczyk41 Feb 13, 2023
4671f0d
Update examples/call-runtime/lib.rs
pmikolajczyk41 Feb 14, 2023
59a0cb0
Update examples/call-runtime/lib.rs
pmikolajczyk41 Feb 14, 2023
3dcd483
Merge remote-tracking branch 'origin/master' into pmikolajczyk41/call…
pmikolajczyk41 Feb 14, 2023
27e0f0b
Merge branch 'master' into pmikolajczyk41/call_runtime
HCastano Feb 16, 2023
bf34580
Bump example version
HCastano Feb 16, 2023
f15c1b6
Fix some nitpicks
HCastano Feb 16, 2023
507e526
Rename error variant
pmikolajczyk41 Feb 17, 2023
fe98dfe
Remove allowance macro
pmikolajczyk41 Feb 17, 2023
b1f9845
Note
pmikolajczyk41 Feb 17, 2023
fcf4d85
Remove note
pmikolajczyk41 Feb 17, 2023
8284ddb
Merge remote-tracking branch 'origin/master' into pmikolajczyk41/call…
pmikolajczyk41 Feb 23, 2023
c81398f
Remove example
pmikolajczyk41 Feb 27, 2023
855f4e0
As integration test
pmikolajczyk41 Feb 27, 2023
fe76dda
Versions
pmikolajczyk41 Feb 27, 2023
3b4beb3
Fix changelog
pmikolajczyk41 Feb 27, 2023
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: 1 addition & 1 deletion 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

### Fixed
- Fixing `ManualKey<0>` to act properly - [#1670](https://github.com/paritytech/ink/pull/1670)
- Add `call-runtime` support - [#1641](https://github.com/paritytech/ink/pull/1641)
agryaznov marked this conversation as resolved.
Show resolved Hide resolved

## Version 4.0.0

Expand Down Expand Up @@ -50,7 +51,6 @@ compatible with the ink! `4.0.0` release.

For full compatibility requirements see the [migration guide](https://use.ink/faq/migrating-from-ink-3-to-4/#compatibility).

### Added
Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh, why was this removed? Looks accidental @pmikolajczyk41 .

Copy link
Member Author

Choose a reason for hiding this comment

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

I must have done this during some semi-automatic merging - that explains the last request for change above :|

- Add `Mapping::contains(key)` and `Mapping::insert_return_size(key, val)` ‒ [#1224](https://github.com/paritytech/ink/pull/1224)
- Add [`payment-channel`](https://github.com/paritytech/ink/tree/master/examples/payment-channel) example ‒ [#1248](https://github.com/paritytech/ink/pull/1248) (thanks [@kanishkatn](https://github.com/kanishkatn)!)
- Add `version` field to ink! metadata ‒ [#1313](https://github.com/paritytech/ink/pull/1313)
Expand Down
3 changes: 3 additions & 0 deletions crates/env/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ std = [
"blake2",
]

# Enable direct call to a pallet dispatchable via `call_runtime()`.
call-runtime = []
SkymanOne marked this conversation as resolved.
Show resolved Hide resolved

# Enable contract debug messages via `debug_print!` and `debug_println!`.
ink-debug = []

Expand Down
32 changes: 32 additions & 0 deletions crates/env/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -700,3 +700,35 @@ where
pub fn set_code_hash(code_hash: &[u8; 32]) -> Result<()> {
<EnvInstance as OnInstance>::on_instance(|instance| instance.set_code_hash(code_hash))
}

/// Tries to trigger a runtime dispatchable, i.e. an extrinsic from a pallet.
///
/// `call` (after SCALE encoding) should be decodable to a valid instance of `RuntimeCall` enum.
///
/// For more details consult
/// [host function documentation](https://paritytech.github.io/substrate/master/pallet_contracts/api_doc/trait.Current.html#tymethod.call_runtime).
///
/// # Errors
///
/// - If the call cannot be properly decoded on the pallet contracts side.
/// - If the runtime doesn't allow for the contract unstable feature.
/// - If the runtime doesn't allow for dispatching this call from a contract.
///
/// # Note
///
/// The `call_runtime` host function is still part of `pallet-contracts`' unstable interface and
/// thus can be changed at anytime.
///
/// # Panics
///
/// Panics in the off-chain environment.
#[cfg(feature = "call-runtime")]
pub fn call_runtime<E, Call>(call: &Call) -> Result<()>
where
E: Environment,
Call: scale::Encode,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
TypedEnvBackend::call_runtime::<E, _>(instance, call)
agryaznov marked this conversation as resolved.
Show resolved Hide resolved
})
}
6 changes: 6 additions & 0 deletions crates/env/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -510,4 +510,10 @@ pub trait TypedEnvBackend: EnvBackend {
fn own_code_hash<E>(&mut self) -> Result<E::Hash>
where
E: Environment;

#[cfg(feature = "call-runtime")]
fn call_runtime<E, Call>(&mut self, call: &Call) -> Result<()>
where
E: Environment,
Call: scale::Encode;
}
8 changes: 8 additions & 0 deletions crates/env/src/engine/off_chain/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -541,4 +541,12 @@ impl TypedEnvBackend for EnvInstance {
{
unimplemented!("off-chain environment does not support `own_code_hash`")
}

#[cfg(feature = "call-runtime")]
fn call_runtime<E, Call>(&mut self, _call: &Call) -> Result<()>
where
E: Environment,
{
unimplemented!("off-chain environment does not support `call_runtime`")
}
}
14 changes: 13 additions & 1 deletion crates/env/src/engine/on_chain/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,11 @@ define_error_codes! {
CodeNotFound = 7,
/// The account that was called is no contract.
NotCallable = 8,
/// The call to `debug_message` had no effect because debug message
/// The call to `debug_message` had no effect because debug message
/// recording was disabled.
LoggingDisabled = 9,
/// The call dispatched by `call_runtime` was executed but returned an error.
CallRuntimeFailed = 10,
pmikolajczyk41 marked this conversation as resolved.
Show resolved Hide resolved
/// ECDSA public key recovery failed. Most probably wrong recovery id or signature.
EcdsaRecoveryFailed = 11,
}
Expand Down Expand Up @@ -325,6 +327,9 @@ mod sys {
out_ptr: Ptr32Mut<[u8]>,
out_len_ptr: Ptr32Mut<u32>,
) -> ReturnCode;

#[cfg(feature = "call-runtime")]
pub fn call_runtime(call_ptr: Ptr32<[u8]>, call_len: u32) -> ReturnCode;
}

#[link(wasm_import_module = "seal1")]
Expand Down Expand Up @@ -639,6 +644,13 @@ pub fn return_value(flags: ReturnFlags, return_value: &[u8]) -> ! {
}
}

#[cfg(feature = "call-runtime")]
pub fn call_runtime(call: &[u8]) -> Result {
let ret_code =
unsafe { sys::call_runtime(Ptr32::from_slice(call), call.len() as u32) };
ret_code.into()
}

macro_rules! impl_wrapper_for {
( $( $name:ident, )* ) => {
$(
Expand Down
12 changes: 12 additions & 0 deletions crates/env/src/engine/on_chain/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ impl From<ext::Error> for Error {
ext::Error::CodeNotFound => Self::CodeNotFound,
ext::Error::NotCallable => Self::NotCallable,
ext::Error::LoggingDisabled => Self::LoggingDisabled,
ext::Error::CallRuntimeFailed => Self::CallRuntimeFailed,
ext::Error::EcdsaRecoveryFailed => Self::EcdsaRecoveryFailed,
}
}
Expand Down Expand Up @@ -575,4 +576,15 @@ impl TypedEnvBackend for EnvInstance {
let hash = scale::Decode::decode(&mut &output[..])?;
Ok(hash)
}

#[cfg(feature = "call-runtime")]
fn call_runtime<E, Call>(&mut self, call: &Call) -> Result<()>
where
E: Environment,
Call: scale::Encode,
{
let mut scope = self.scoped_buffer();
let enc_call = scope.take_encoded(call);
ext::call_runtime(enc_call).map_err(Into::into)
}
}
2 changes: 2 additions & 0 deletions crates/env/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ pub enum Error {
/// The call to `debug_message` had no effect because debug message
/// recording was disabled.
LoggingDisabled,
/// The call dispatched by `call_runtime` was executed but returned an error.
CallRuntimeFailed,
pmikolajczyk41 marked this conversation as resolved.
Show resolved Hide resolved
/// ECDSA pubkey recovery failed. Most probably wrong recovery id or signature.
EcdsaRecoveryFailed,
}
Expand Down
6 changes: 6 additions & 0 deletions crates/ink/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ std = [
ink-debug = [
"ink_env/ink-debug",
]

# Enable direct call to a pallet dispatchable via `call_runtime()`.
call-runtime = [
"ink_env/call-runtime",
]

show-codegen-docs = []

# Disable the ink! provided global memory allocator.
Expand Down
5 changes: 5 additions & 0 deletions crates/ink/src/env_access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -969,4 +969,9 @@ where
pub fn own_code_hash(self) -> Result<E::Hash> {
ink_env::own_code_hash::<E>()
}

#[cfg(feature = "call-runtime")]
pub fn call_runtime<Call: scale::Encode>(self, call: &Call) -> Result<()> {
ink_env::call_runtime::<E, _>(call)
}
}
6 changes: 5 additions & 1 deletion crates/storage/src/lazy/mapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,11 @@ where
/// Removes the `value` at `key`, returning the previous `value` at `key` from storage.
///
/// Returns `None` if no `value` exists at the given `key`.
/// **WARNING**: this method uses the [unstable interface](https://github.com/paritytech/substrate/tree/master/frame/contracts#unstable-interfaces),
///
/// # Warning
///
/// This method uses the
/// [unstable interface](https://github.com/paritytech/substrate/tree/master/frame/contracts#unstable-interfaces),
/// which is unsafe and normally is not available on production chains.
#[inline]
pub fn take<Q>(&self, key: Q) -> Option<V>
Expand Down
9 changes: 9 additions & 0 deletions integration-tests/call-runtime/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Ignore build artifacts from the local tests sub-crate.
/target/

# Ignore backup files creates by cargo fmt.
**/*.rs.bk

# Remove Cargo.lock when creating an executable, leave it for libraries
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
Cargo.lock
43 changes: 43 additions & 0 deletions integration-tests/call-runtime/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
[package]
name = "call-runtime"
version = "4.0.0"
authors = ["Parity Technologies <[email protected]>"]
edition = "2021"
publish = false

[dependencies]
ink = { path = "../../crates/ink", default-features = false, features = ["call-runtime"] }

scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
scale-info = { version = "2.3", default-features = false, features = ["derive"], optional = true }

# Substrate
#
# We need to explicitly turn off some of the `sp-io` features, to avoid conflicts
# (especially for global allocator).
#
# See also: https://substrate.stackexchange.com/questions/4733/error-when-compiling-a-contract-using-the-xcm-chain-extension.
sp-io = { version = "18.0.0", default-features = false, features = ["disable_panic_handler", "disable_oom", "disable_allocator"] }
sp-runtime = { version = "19.0.0", default-features = false }

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

[lib]
path = "lib.rs"

[features]
default = ["std"]
std = [
"ink/std",
"scale/std",
"scale-info/std",
"sp-runtime/std",
"sp-io/std",
]
ink-as-dependency = []
e2e-tests = []

# Assumes that the node used in E2E testing allows using the `call-runtime` API, including triggering
# `Balances::transfer` extrinsic.
permissive-node = []
29 changes: 29 additions & 0 deletions integration-tests/call-runtime/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# `call-runtime` example

## What is this example about?

It demonstrates how to call a runtime dispatchable from an ink! contract.

## Chain-side configuration

To integrate this example into Substrate you need to adjust pallet contracts configuration in your runtime:
```rust
// In your node's runtime configuration file (runtime.rs)
impl pallet_contracts::Config for Runtime {
// `Everything` or anything that will allow for the `Balances::transfer` extrinsic.
type CallFilter = frame_support::traits::Everything;
type UnsafeUnstableInterface = ConstBool<true>;
}
```

## Comparison to `ChainExtension`

Just as a chain extension, `call_runtime` API allows contracts for direct calling to the runtime.
You can trigger any extrinsic that is not forbidden by `pallet_contracts::Config::CallFilter`.
Consider writing a chain extension if you need to perform one of the following tasks:
- Return data.
- Provide functionality **exclusively** to contracts.
- Provide custom weights.
- Avoid the need to keep the `Call` data structure stable.
Loading