-
Notifications
You must be signed in to change notification settings - Fork 480
Support call_runtime
#1641
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
Changes from 16 commits
d6f55bc
d3a1291
7ad9137
6a47080
1a6cb26
6e21f63
4918b82
b9503cc
5f5e2ae
ed4a155
9210619
d80b3bb
2e3d71c
99982d4
9943cbe
f825412
2991153
2e7bcb4
880b84c
4e69291
0f8f142
cc13064
93c535b
4ef1ce9
a15dbce
e81fb98
9f59e7a
2285c87
13225e2
d4665f9
84dc23e
ee7cfcb
ca6238d
89147f1
f3073de
e981d47
db85259
883739d
dff8d92
c3fe8f2
614dae7
315900a
1dfd5f5
560b954
23f71a5
4671f0d
59a0cb0
3dcd483
27e0f0b
bf34580
f15c1b6
507e526
fe98dfe
b1f9845
fcf4d85
8284ddb
c81398f
855f4e0
fe76dda
3b4beb3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -49,4 +49,5 @@ std = [ | |
| ink-debug = [ | ||
| "ink_env/ink-debug", | ||
| ] | ||
| call-runtime = ["ink_env/call-runtime"] | ||
| show-codegen-docs = [] | ||
| 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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| [package] | ||
| name = "call-runtime" | ||
| version = "4.0.0-rc" | ||
| 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 } | ||
| sp-io = { version = "12.0.0", default-features = false, features = ["disable_panic_handler", "disable_oom", "disable_allocator"] } | ||
|
||
| sp-runtime = { version = "12.0.0", default-features = false } | ||
HCastano marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
agryaznov marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| [dev-dependencies] | ||
| ink_e2e = { path = "../../crates/e2e" } | ||
|
|
||
| [lib] | ||
| name = "call_runtime" | ||
| path = "lib.rs" | ||
| crate-type = ["cdylib"] | ||
|
|
||
| [features] | ||
| default = ["std"] | ||
| std = [ | ||
| "ink/std", | ||
| "scale/std", | ||
| "scale-info/std", | ||
| "sp-runtime/std", | ||
| "sp-io/std", | ||
| ] | ||
| ink-as-dependency = [] | ||
| e2e-tests = [] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| # `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: | ||
| `pallet_contracts::Config`: | ||
| ```rust | ||
| impl pallet_contracts::Config for Runtime { | ||
| … | ||
HCastano marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // `Everything` or anything that will allow for Balances::transfer extrinsic | ||
pmikolajczyk41 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| type CallFilter = frame_support::traits::Everything; | ||
| type UnsafeUnstableInterface = ConstBool<true>; | ||
| … | ||
| } | ||
| ``` | ||
HCastano marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,155 @@ | ||
| #![cfg_attr(not(feature = "std"), no_std)] | ||
HCastano marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| use ink::primitives::AccountId; | ||
| use sp_runtime::MultiAddress; | ||
|
|
||
| #[derive(scale::Encode)] | ||
| enum RuntimeCall { | ||
agryaznov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| #[codec(index = 4)] | ||
HCastano marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Balances(BalancesCall), | ||
| } | ||
|
|
||
| #[derive(scale::Encode)] | ||
| enum BalancesCall { | ||
| #[codec(index = 0)] | ||
HCastano marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Transfer { | ||
| dest: MultiAddress<AccountId, ()>, | ||
| #[codec(compact)] | ||
| value: u128, | ||
| }, | ||
| } | ||
|
|
||
| #[ink::contract] | ||
| mod runtime_call { | ||
| use crate::{ | ||
| BalancesCall, | ||
| RuntimeCall, | ||
| }; | ||
|
|
||
| #[ink(storage)] | ||
| #[derive(Default)] | ||
| pub struct RuntimeCaller; | ||
|
|
||
| impl RuntimeCaller { | ||
| #[ink(constructor, payable)] | ||
| pub fn new() -> Self { | ||
| Self {} | ||
HCastano marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| #[ink(message)] | ||
| pub fn make_transfer_through_runtime( | ||
HCastano marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| &mut self, | ||
| receiver: AccountId, | ||
| value: Balance, | ||
| ) { | ||
| self.env() | ||
| .call_runtime(&RuntimeCall::Balances(BalancesCall::Transfer { | ||
pmikolajczyk41 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| dest: receiver.into(), | ||
| value, | ||
| })) | ||
| .expect("Should succeed"); | ||
HCastano marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
HCastano marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| use ink::env::{ | ||
| test::default_accounts, | ||
| DefaultEnvironment, | ||
| }; | ||
|
|
||
| #[ink::test] | ||
| #[should_panic( | ||
| expected = "off-chain environment does not support `call runtime`" | ||
pmikolajczyk41 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| )] | ||
| fn cannot_call_runtime_off_chain() { | ||
| let mut contract = RuntimeCaller::new(); | ||
| contract.make_transfer_through_runtime( | ||
| default_accounts::<DefaultEnvironment>().bob, | ||
| 10, | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| #[cfg(all(test, feature = "e2e-tests"))] | ||
| mod e2e_tests { | ||
| use super::*; | ||
HCastano marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| use ink::{ | ||
| env::{ | ||
| test::default_accounts, | ||
| DefaultEnvironment, | ||
| }, | ||
| primitives::AccountId, | ||
| }; | ||
| use ink_e2e::build_message; | ||
|
|
||
| type E2EResult<T> = Result<T, Box<dyn std::error::Error>>; | ||
|
|
||
| const CONTRACT_BALANCE: Balance = 1_000_000_000_000_000; | ||
| const TRANSFER_VALUE: Balance = 1_000_000_000; | ||
HCastano marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| #[ink_e2e::test] | ||
| #[ignore = "Requires that the pallet contract is configured with:\ | ||
| - `CallFilter` allowing for a transfer, e.g. `frame_support::traits::Everything`,\ | ||
| - `UnsafeUnstableInterface = ConstBool<true>`"] | ||
HCastano marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| async fn it_works(mut client: Client<C, E>) -> E2EResult<()> { | ||
HCastano marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // given | ||
| let constructor = RuntimeCallerRef::new(); | ||
| let contract_acc_id = client | ||
| .instantiate( | ||
| "call-runtime", | ||
| &ink_e2e::alice(), | ||
| constructor, | ||
| CONTRACT_BALANCE, | ||
| None, | ||
| ) | ||
| .await | ||
| .expect("instantiate failed") | ||
| .account_id; | ||
|
|
||
| let receiver: AccountId = default_accounts::<DefaultEnvironment>().bob; | ||
HCastano marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| let contract_balance_before = client | ||
| .balance(contract_acc_id) | ||
| .await | ||
| .expect("Failed to get account balance"); | ||
| let receiver_balance_before = client | ||
| .balance(receiver) | ||
| .await | ||
| .expect("Failed to get account balance"); | ||
|
|
||
| // when | ||
| let transfer_message = build_message::<RuntimeCallerRef>(contract_acc_id) | ||
| .call(|caller| { | ||
| caller.make_transfer_through_runtime(receiver, TRANSFER_VALUE) | ||
| }); | ||
|
|
||
| let _call_res = client | ||
| .call(&ink_e2e::alice(), transfer_message, 0, None) | ||
| .await | ||
| .expect("call failed"); | ||
|
|
||
| // then | ||
| let contract_balance_after = client | ||
| .balance(contract_acc_id) | ||
| .await | ||
| .expect("Failed to get account balance"); | ||
| let receiver_balance_after = client | ||
| .balance(receiver) | ||
| .await | ||
| .expect("Failed to get account balance"); | ||
|
|
||
| assert_eq!( | ||
| contract_balance_before, | ||
| contract_balance_after + TRANSFER_VALUE | ||
| ); | ||
| assert_eq!( | ||
| receiver_balance_before + TRANSFER_VALUE, | ||
| receiver_balance_after | ||
HCastano marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ); | ||
|
|
||
| Ok(()) | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.