Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Rename enum variant. Docs. Return result. Failure e2e
  • Loading branch information
pmikolajczyk41 committed Feb 9, 2023
commit 4ef1ce9633df36456009ec4862e3868605a35cec
2 changes: 1 addition & 1 deletion crates/env/src/engine/on_chain/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ define_error_codes! {
/// recording was disabled.
LoggingDisabled = 9,
/// The call dispatched by `call_runtime` was executed but returned an error.
CallRuntimeReturned = 10,
CallRuntimeFailed = 10,
/// ECDSA public key recovery failed. Most probably wrong recovery id or signature.
EcdsaRecoveryFailed = 11,
}
Expand Down
2 changes: 1 addition & 1 deletion crates/env/src/engine/on_chain/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +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::CallRuntimeReturned => Self::CallRuntimeReturned,
ext::Error::CallRuntimeFailed => Self::CallRuntimeFailed,
ext::Error::EcdsaRecoveryFailed => Self::EcdsaRecoveryFailed,
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/env/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ pub enum Error {
/// recording was disabled.
LoggingDisabled,
/// The call dispatched by `call_runtime` was executed but returned an error.
CallRuntimeReturned,
CallRuntimeFailed,
/// ECDSA pubkey recovery failed. Most probably wrong recovery id or signature.
EcdsaRecoveryFailed,
}
Expand Down
2 changes: 1 addition & 1 deletion examples/call-runtime/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ To integrate this example into Substrate you need to adjust pallet contracts con

## Comparison to `ChainExtension`

Just as a chain extension `call_runtime` API allows contracts for direct calling to the runtime.
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.
Expand Down
69 changes: 65 additions & 4 deletions examples/call-runtime/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@
use ink::primitives::AccountId;
use sp_runtime::MultiAddress;

/// A part of the runtime dispatchable API.
///
/// For now, `ink!` doesn't provide any support for exposing the real `RuntimeCall` enum, which
/// fully describes the composed API of all the pallets present in runtime. Hence, in order to use
/// `call-runtime` functionality, we have to provide at least a partial object, which correctly
/// encodes the target extrinsic.
///
/// You can investigate the full `RuntimeCall` definition by either expanding `construct_runtime!`
/// macro application or by using secondary tools for reading chain metadata, like `subxt`.
#[derive(scale::Encode)]
enum RuntimeCall {
// This index can be found by investigating runtime configuration. You can check the pallet
Expand Down Expand Up @@ -33,24 +42,41 @@ mod runtime_call {
RuntimeCall,
};

/// A trivial contract with a single message, that uses `call-runtime` API for performing
/// native token transfer.
#[ink(storage)]
#[derive(Default)]
pub struct RuntimeCaller;

impl RuntimeCaller {
/// The constructor is `payable`, so that during instantiation it can be given some tokens
/// that will be further transferred with `transfer_through_runtime` message.
#[ink(constructor, payable)]
pub fn new() -> Self {
Default::default()
}

/// Tries to transfer `value` from the contract's balance to `receiver`.
///
/// Fails if:
/// - called in the off-chain environment
/// - the chain doesn't allow `call-runtime` API (`UnsafeUnstableInterface` is turned off)
/// - the chain forbids contracts to call `Balances::transfer` (`CallFilter` is too
/// restrictive)
/// - after the transfer, `receiver` doesn't have at least existential deposit
/// - the contract doesn't have enough balance
#[ink(message)]
pub fn transfer_through_runtime(&mut self, receiver: AccountId, value: Balance) {
pub fn transfer_through_runtime(
&mut self,
receiver: AccountId,
value: Balance,
) -> Result<(), ()> {
self.env()
.call_runtime(&RuntimeCall::Balances(BalancesCall::Transfer {
dest: receiver.into(),
value,
}))
.expect("Should succeed");
.map_err(|_| ())
}
}

Expand All @@ -69,7 +95,7 @@ mod runtime_call {
)]
fn cannot_call_runtime_off_chain() {
let mut contract = RuntimeCaller::new();
contract.transfer_through_runtime(
let _call_res = contract.transfer_through_runtime(
default_accounts::<DefaultEnvironment>().bob,
10,
);
Expand All @@ -91,7 +117,11 @@ mod runtime_call {

type E2EResult<T> = Result<T, Box<dyn std::error::Error>>;

/// The contract will be given 1k tokens during instantiation.
const CONTRACT_BALANCE: Balance = 1_000_000_000_000_000;
/// The receiver will get enough funds to have the required existential deposit.
///
/// If your chain has this threshold higher, increase the transfer value.
const TRANSFER_VALUE: Balance = 1_000_000_000;

#[ink_e2e::test]
Expand Down Expand Up @@ -130,11 +160,13 @@ mod runtime_call {
let transfer_message = build_message::<RuntimeCallerRef>(contract_acc_id)
.call(|caller| caller.transfer_through_runtime(receiver, TRANSFER_VALUE));

let _call_res = client
let call_res = client
.call(&ink_e2e::alice(), transfer_message, 0, None)
.await
.expect("call failed");

assert!(call_res.dry_run.exec_result.result.is_ok());

// then
let contract_balance_after = client
.balance(contract_acc_id)
Expand All @@ -156,5 +188,34 @@ mod runtime_call {

Ok(())
}

/// In the standard configuration, the node doesn't allow for `call-runtime` usage.
#[ink_e2e::test]
async fn call_runtime_fails_when_forbidden(
mut client: Client<C, E>,
) -> E2EResult<()> {
// given
let constructor = RuntimeCallerRef::new();
let contract_acc_id = client
.instantiate("call-runtime", &ink_e2e::alice(), constructor, 0, None)
.await
.expect("instantiate failed")
.account_id;

let receiver: AccountId = default_accounts::<DefaultEnvironment>().bob;

let transfer_message = build_message::<RuntimeCallerRef>(contract_acc_id)
.call(|caller| caller.transfer_through_runtime(receiver, TRANSFER_VALUE));

// when
let call_res = client
.call(&ink_e2e::alice(), transfer_message, 0, None)
.await;

// then
assert!(call_res.is_err());

Ok(())
}
}
}