From de543ed69c5f0e889546e04d048da572f1f83b93 Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 29 Jan 2024 15:28:38 +0000 Subject: [PATCH 01/47] init call_v2 methods and types --- crates/env/src/api.rs | 15 ++ crates/env/src/backend.rs | 10 ++ crates/env/src/call/call_builder.rs | 168 +++++++++++++++++++++++ crates/env/src/call/mod.rs | 1 + crates/env/src/engine/off_chain/impls.rs | 13 ++ crates/env/src/engine/on_chain/impls.rs | 43 ++++++ crates/ink/src/env_access.rs | 13 ++ 7 files changed, 263 insertions(+) diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index 61682408185..b3ae5f22006 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -22,6 +22,7 @@ use crate::{ call::{ Call, CallParams, + CallV2, ConstructorReturnType, CreateParams, DelegateCall, @@ -286,6 +287,20 @@ where }) } +/// todo: [AJ] docs +pub fn invoke_contract_v2( + params: &CallParams, Args, R>, +) -> Result> +where + E: Environment, + Args: scale::Encode, + R: scale::Decode, +{ + ::on_instance(|instance| { + TypedEnvBackend::invoke_contract_v2::(instance, params) + }) +} + /// Invokes a contract message via delegate call and returns its result. /// /// # Note diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index d5da075d807..7f9a5338904 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -16,6 +16,7 @@ use crate::{ call::{ Call, CallParams, + CallV2, ConstructorReturnType, CreateParams, DelegateCall, @@ -304,6 +305,15 @@ pub trait TypedEnvBackend: EnvBackend { Args: scale::Encode, R: scale::Decode; + fn invoke_contract_v2( + &mut self, + call_data: &CallParams, Args, R>, + ) -> Result> + where + E: Environment, + Args: scale::Encode, + R: scale::Decode; + /// Invokes a contract message via delegate call and returns its result. /// /// # Note diff --git a/crates/env/src/call/call_builder.rs b/crates/env/src/call/call_builder.rs index 55d98219bb4..1b53bb6c045 100644 --- a/crates/env/src/call/call_builder.rs +++ b/crates/env/src/call/call_builder.rs @@ -88,6 +88,35 @@ where } } +impl CallParams, Args, R> +where + E: Environment, +{ + /// Returns the account ID of the called contract instance. + #[inline] + pub fn callee(&self) -> &E::AccountId { + &self.call_type.callee + } + + /// Returns the chosen ref time limit for the called contract execution. + #[inline] + pub fn ref_time_limit(&self) -> Gas { + self.call_type.ref_time_limit + } + + /// Returns the chosen proof time limit for the called contract execution. + #[inline] + pub fn proof_time_limit(&self) -> Gas { + self.call_type.proof_time_limit + } + + /// Returns the transferred value for the called contract. + #[inline] + pub fn transferred_value(&self) -> &E::Balance { + &self.call_type.transferred_value + } +} + impl CallParams, Args, R> where E: Environment, @@ -138,6 +167,45 @@ where } } +impl CallParams, Args, R> +where + E: Environment, + Args: scale::Encode, + R: scale::Decode, +{ + /// Invokes the contract with the given built-up call parameters. + /// + /// Returns the result of the contract execution. + /// + /// # Panics + /// + /// This method panics if it encounters an [`ink::env::Error`][`crate::Error`] or an + /// [`ink::primitives::LangError`][`ink_primitives::LangError`]. If you want to handle + /// those use the [`try_invoke`][`CallParams::try_invoke`] method instead. + pub fn invoke(&self) -> R { + crate::invoke_contract_v2(self) + .unwrap_or_else(|env_error| { + panic!("Cross-contract call failed with {env_error:?}") + }) + .unwrap_or_else(|lang_error| { + panic!("Cross-contract call failed with {lang_error:?}") + }) + } + + /// Invokes the contract with the given built-up call parameters. + /// + /// Returns the result of the contract execution. + /// + /// # Note + /// + /// On failure this returns an outer [`ink::env::Error`][`crate::Error`] or inner + /// [`ink::primitives::LangError`][`ink_primitives::LangError`], both of which can be + /// handled by the caller. + pub fn try_invoke(&self) -> Result, crate::Error> { + crate::invoke_contract_v2(self) + } +} + impl CallParams, Args, R> where E: Environment, @@ -378,6 +446,52 @@ where } } +/// todo: [AJ] docs +#[derive(Clone)] +pub struct CallV2 { + callee: E::AccountId, + ref_time_limit: Gas, + proof_time_limit: Gas, + transferred_value: E::Balance, +} + +impl CallV2 { + /// Returns a clean builder for [`Call`]. + pub fn new(callee: E::AccountId) -> Self { + Self { + callee, + ref_time_limit: Default::default(), + proof_time_limit: Default::default(), + transferred_value: E::Balance::zero(), + } + } +} + +impl CallV2 +where + E: Environment, +{ + /// Sets the `gas_limit` for the current cross-contract call. + pub fn weight_limit(self, ref_time_limit: Gas, proof_time_limit: Gas) -> Self { + CallV2 { + callee: self.callee, + ref_time_limit, + proof_time_limit, + transferred_value: self.transferred_value, + } + } + + /// Sets the `transferred_value` for the current cross-contract call. + pub fn transferred_value(self, transferred_value: E::Balance) -> Self { + CallV2 { + callee: self.callee, + ref_time_limit: self.ref_time_limit, + proof_time_limit: self.proof_time_limit, + transferred_value, + } + } +} + /// The `delegatecall` call type. Performs a call with the given code hash. #[derive(Clone)] pub struct DelegateCall { @@ -514,6 +628,20 @@ where } } + /// todo: [AJ] docs + pub fn call_v2( + self, + callee: E::AccountId, + ) -> CallBuilder>, Args, RetType> { + CallBuilder { + call_type: Set(CallV2::new(callee)), + call_flags: self.call_flags, + exec_input: self.exec_input, + return_type: self.return_type, + _phantom: Default::default(), + } + } + /// Prepares the `CallBuilder` for a cross-contract [`DelegateCall`]. pub fn delegate( self, @@ -566,6 +694,46 @@ where } } +impl CallBuilder>, Args, RetType> +where + E: Environment, +{ + /// Sets the `ref_time_limit` and the `proof_time_limit` for the current + /// cross-contract call. + pub fn weight_limit(self, ref_time_limit: Gas, proof_time_limit: Gas) -> Self { + let call_type = self.call_type.value(); + CallBuilder { + call_type: Set(CallV2 { + callee: call_type.callee, + ref_time_limit, + proof_time_limit, + transferred_value: call_type.transferred_value, + }), + call_flags: self.call_flags, + exec_input: self.exec_input, + return_type: self.return_type, + _phantom: Default::default(), + } + } + + /// Sets the `transferred_value` for the current cross-contract call. + pub fn transferred_value(self, transferred_value: E::Balance) -> Self { + let call_type = self.call_type.value(); + CallBuilder { + call_type: Set(CallV2 { + callee: call_type.callee, + ref_time_limit: call_type.ref_time_limit, + proof_time_limit: call_type.proof_time_limit, + transferred_value, + }), + call_flags: self.call_flags, + exec_input: self.exec_input, + return_type: self.return_type, + _phantom: Default::default(), + } + } +} + impl CallBuilder>, Args, RetType> where E: Environment, diff --git a/crates/env/src/call/mod.rs b/crates/env/src/call/mod.rs index a7979214002..76264aa9e0b 100644 --- a/crates/env/src/call/mod.rs +++ b/crates/env/src/call/mod.rs @@ -43,6 +43,7 @@ pub use self::{ call_builder::{ build_call, Call, + CallV2, CallBuilder, CallParams, DelegateCall, diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index df1a3321028..d5dc7cad504 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -17,6 +17,7 @@ use crate::{ call::{ Call, CallParams, + CallV2, ConstructorReturnType, CreateParams, DelegateCall, @@ -448,6 +449,18 @@ impl TypedEnvBackend for EnvInstance { unimplemented!("off-chain environment does not support contract invocation") } + fn invoke_contract_v2( + &mut self, + _params: &CallParams, Args, R>, + ) -> Result> + where + E: Environment, + Args: scale::Encode, + R: scale::Decode, + { + unimplemented!("off-chain environment does not support contract invocation") + } + fn invoke_contract_delegate( &mut self, params: &CallParams, Args, R>, diff --git a/crates/env/src/engine/on_chain/impls.rs b/crates/env/src/engine/on_chain/impls.rs index b1c39c37794..4b0be501b1a 100644 --- a/crates/env/src/engine/on_chain/impls.rs +++ b/crates/env/src/engine/on_chain/impls.rs @@ -20,6 +20,7 @@ use crate::{ call::{ Call, CallParams, + CallV2, ConstructorReturnType, CreateParams, DelegateCall, @@ -463,6 +464,48 @@ impl TypedEnvBackend for EnvInstance { } } + fn invoke_contract_v2( + &mut self, + params: &CallParams, Args, R>, + ) -> Result> + where + E: Environment, + Args: scale::Encode, + R: scale::Decode, + { + let mut scope = self.scoped_buffer(); + let ref_time_limit = params.ref_time_limit(); + let proof_time_limit = params.proof_time_limit(); + let enc_callee = scope.take_encoded(params.callee()); + let enc_transferred_value = scope.take_encoded(params.transferred_value()); + let call_flags = params.call_flags(); + let enc_input = if !call_flags.contains(CallFlags::FORWARD_INPUT) + && !call_flags.contains(CallFlags::CLONE_INPUT) + { + scope.take_encoded(params.exec_input()) + } else { + &mut [] + }; + let output = &mut scope.take_rest(); + let flags = params.call_flags(); + let call_result = ext::call_v2( + *flags, + enc_callee, + ref_time_limit, + proof_time_limit, + enc_transferred_value, + enc_input, + Some(output), + ); + match call_result { + Ok(()) | Err(ReturnErrorCode::CalleeReverted) => { + let decoded = scale::DecodeAll::decode_all(&mut &output[..])?; + Ok(decoded) + } + Err(actual_error) => Err(actual_error.into()), + } + } + fn invoke_contract_delegate( &mut self, params: &CallParams, Args, R>, diff --git a/crates/ink/src/env_access.rs b/crates/ink/src/env_access.rs index a7a705882d8..de72cd5a448 100644 --- a/crates/ink/src/env_access.rs +++ b/crates/ink/src/env_access.rs @@ -18,6 +18,7 @@ use ink_env::{ call::{ Call, CallParams, + CallV2, ConstructorReturnType, CreateParams, DelegateCall, @@ -578,6 +579,18 @@ where ink_env::invoke_contract::(params) } + /// todo: [AJ] docs + pub fn invoke_contract_v2( + self, + params: &CallParams, Args, R>, + ) -> Result> + where + Args: scale::Encode, + R: scale::Decode, + { + ink_env::invoke_contract_v2::(params) + } + /// Invokes in delegate manner a code message and returns its result. /// /// # Example From 83393523cd604112b93ad7fe2ee18197ff5eb9c2 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 30 Jan 2024 14:59:44 +0000 Subject: [PATCH 02/47] add e2e tests to basic-contract-caller example --- crates/env/src/call/call_builder.rs | 33 ++++++++------- .../basic-contract-caller/e2e_tests.rs | 40 +++++++++++++++++++ .../basic-contract-caller/lib.rs | 3 ++ 3 files changed, 62 insertions(+), 14 deletions(-) create mode 100644 integration-tests/basic-contract-caller/e2e_tests.rs diff --git a/crates/env/src/call/call_builder.rs b/crates/env/src/call/call_builder.rs index 1b53bb6c045..4b0737afbe2 100644 --- a/crates/env/src/call/call_builder.rs +++ b/crates/env/src/call/call_builder.rs @@ -628,20 +628,6 @@ where } } - /// todo: [AJ] docs - pub fn call_v2( - self, - callee: E::AccountId, - ) -> CallBuilder>, Args, RetType> { - CallBuilder { - call_type: Set(CallV2::new(callee)), - call_flags: self.call_flags, - exec_input: self.exec_input, - return_type: self.return_type, - _phantom: Default::default(), - } - } - /// Prepares the `CallBuilder` for a cross-contract [`DelegateCall`]. pub fn delegate( self, @@ -661,6 +647,25 @@ impl CallBuilder>, Args, RetType> where E: Environment, { + /// todo: [AJ] docs + pub fn v2( + self, + ) -> CallBuilder>, Args, RetType> { + let call_type = self.call_type.value(); + CallBuilder { + call_type: Set(CallV2 { + callee: call_type.callee, + ref_time_limit: call_type.gas_limit, + proof_time_limit: Default::default(), + transferred_value: call_type.transferred_value, + } ), + call_flags: self.call_flags, + exec_input: self.exec_input, + return_type: self.return_type, + _phantom: Default::default(), + } + } + /// Sets the `gas_limit` for the current cross-contract call. pub fn gas_limit(self, gas_limit: Gas) -> Self { let call_type = self.call_type.value(); diff --git a/integration-tests/basic-contract-caller/e2e_tests.rs b/integration-tests/basic-contract-caller/e2e_tests.rs new file mode 100644 index 00000000000..f846e662be0 --- /dev/null +++ b/integration-tests/basic-contract-caller/e2e_tests.rs @@ -0,0 +1,40 @@ +use super::basic_contract_caller::*; +use ink_e2e::ContractsBackend; + +type E2EResult = std::result::Result>; + +#[ink_e2e::test] +async fn flip_and_get( + mut client: Client, +) -> E2EResult<()> { + // given + let other_contract_code = client + .upload("other-contract", &ink_e2e::alice()) + .submit() + .await + .expect("other_contract upload failed"); + + let mut constructor = BasicContractCallerRef::new(other_contract_code.code_hash); + let contract = client + .instantiate("basic-contract-caller", &ink_e2e::alice(), &mut constructor) + .submit() + .await + .expect("basic-contract-caller instantiate failed"); + let call_builder = contract.call_builder::(); + let call = call_builder.flip_and_get(); + + // when + let result = client + .call( + &ink_e2e::alice(), + &call, + ) + .submit() + .await + .expect("Calling `flip_and_get` failed") + .return_value(); + + assert!(result); + + Ok(()) +} diff --git a/integration-tests/basic-contract-caller/lib.rs b/integration-tests/basic-contract-caller/lib.rs index f988caabf41..78c999d7c26 100755 --- a/integration-tests/basic-contract-caller/lib.rs +++ b/integration-tests/basic-contract-caller/lib.rs @@ -39,3 +39,6 @@ mod basic_contract_caller { } } } + +#[cfg(all(test, feature = "e2e-tests"))] +mod e2e_tests; From a84fe4f5a23cd60f3ca95bdc7ec34d6fb5703138 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 30 Jan 2024 16:31:35 +0000 Subject: [PATCH 03/47] Add storage_deposit --- crates/env/src/engine/on_chain/impls.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/env/src/engine/on_chain/impls.rs b/crates/env/src/engine/on_chain/impls.rs index 4b0be501b1a..4ada9665846 100644 --- a/crates/env/src/engine/on_chain/impls.rs +++ b/crates/env/src/engine/on_chain/impls.rs @@ -493,6 +493,7 @@ impl TypedEnvBackend for EnvInstance { enc_callee, ref_time_limit, proof_time_limit, + None, // todo: add storage_deposit_limit to CallParams enc_transferred_value, enc_input, Some(output), From b7ad4b0d0cab1bc5472aa61ef0e04ff6ed57986f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 30 Jan 2024 16:32:02 +0000 Subject: [PATCH 04/47] Fix basic-contract-caller e2e tests --- integration-tests/basic-contract-caller/e2e_tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration-tests/basic-contract-caller/e2e_tests.rs b/integration-tests/basic-contract-caller/e2e_tests.rs index f846e662be0..630ebef2cce 100644 --- a/integration-tests/basic-contract-caller/e2e_tests.rs +++ b/integration-tests/basic-contract-caller/e2e_tests.rs @@ -20,7 +20,7 @@ async fn flip_and_get( .submit() .await .expect("basic-contract-caller instantiate failed"); - let call_builder = contract.call_builder::(); + let mut call_builder = contract.call_builder::(); let call = call_builder.flip_and_get(); // when @@ -34,7 +34,7 @@ async fn flip_and_get( .expect("Calling `flip_and_get` failed") .return_value(); - assert!(result); + assert_eq!(result, false); Ok(()) } From 99a9c030afd15d824da56ca97d3fe8b31b446bf4 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 30 Jan 2024 16:40:26 +0000 Subject: [PATCH 05/47] Remove `basic_contract_caller` integration test, moved to #1909 --- .../basic-contract-caller/e2e_tests.rs | 40 ------------------- .../basic-contract-caller/lib.rs | 3 -- 2 files changed, 43 deletions(-) delete mode 100644 integration-tests/basic-contract-caller/e2e_tests.rs diff --git a/integration-tests/basic-contract-caller/e2e_tests.rs b/integration-tests/basic-contract-caller/e2e_tests.rs deleted file mode 100644 index 630ebef2cce..00000000000 --- a/integration-tests/basic-contract-caller/e2e_tests.rs +++ /dev/null @@ -1,40 +0,0 @@ -use super::basic_contract_caller::*; -use ink_e2e::ContractsBackend; - -type E2EResult = std::result::Result>; - -#[ink_e2e::test] -async fn flip_and_get( - mut client: Client, -) -> E2EResult<()> { - // given - let other_contract_code = client - .upload("other-contract", &ink_e2e::alice()) - .submit() - .await - .expect("other_contract upload failed"); - - let mut constructor = BasicContractCallerRef::new(other_contract_code.code_hash); - let contract = client - .instantiate("basic-contract-caller", &ink_e2e::alice(), &mut constructor) - .submit() - .await - .expect("basic-contract-caller instantiate failed"); - let mut call_builder = contract.call_builder::(); - let call = call_builder.flip_and_get(); - - // when - let result = client - .call( - &ink_e2e::alice(), - &call, - ) - .submit() - .await - .expect("Calling `flip_and_get` failed") - .return_value(); - - assert_eq!(result, false); - - Ok(()) -} diff --git a/integration-tests/basic-contract-caller/lib.rs b/integration-tests/basic-contract-caller/lib.rs index 78c999d7c26..f988caabf41 100755 --- a/integration-tests/basic-contract-caller/lib.rs +++ b/integration-tests/basic-contract-caller/lib.rs @@ -39,6 +39,3 @@ mod basic_contract_caller { } } } - -#[cfg(all(test, feature = "e2e-tests"))] -mod e2e_tests; From cc52b415bb42d9a63a35b4784f0555e2c247934f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 31 Jan 2024 10:37:12 +0000 Subject: [PATCH 06/47] WIP adding cross_contract_calls test --- .../cross-contract-calls/.gitignore | 9 ++ .../cross-contract-calls/Cargo.toml | 32 +++++++ .../cross-contract-calls/e2e_tests.rs | 94 +++++++++++++++++++ integration-tests/cross-contract-calls/lib.rs | 46 +++++++++ .../other-contract/.gitignore | 9 ++ .../other-contract/Cargo.toml | 23 +++++ .../other-contract/lib.rs | 33 +++++++ 7 files changed, 246 insertions(+) create mode 100755 integration-tests/cross-contract-calls/.gitignore create mode 100755 integration-tests/cross-contract-calls/Cargo.toml create mode 100644 integration-tests/cross-contract-calls/e2e_tests.rs create mode 100755 integration-tests/cross-contract-calls/lib.rs create mode 100755 integration-tests/cross-contract-calls/other-contract/.gitignore create mode 100755 integration-tests/cross-contract-calls/other-contract/Cargo.toml create mode 100755 integration-tests/cross-contract-calls/other-contract/lib.rs diff --git a/integration-tests/cross-contract-calls/.gitignore b/integration-tests/cross-contract-calls/.gitignore new file mode 100755 index 00000000000..8de8f877e47 --- /dev/null +++ b/integration-tests/cross-contract-calls/.gitignore @@ -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 diff --git a/integration-tests/cross-contract-calls/Cargo.toml b/integration-tests/cross-contract-calls/Cargo.toml new file mode 100755 index 00000000000..ad17489b138 --- /dev/null +++ b/integration-tests/cross-contract-calls/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "cross-contract-calls" +version = "5.0.0-rc" +authors = ["Parity Technologies "] +edition = "2021" +publish = false + +[dependencies] +ink = { path = "../../crates/ink", default-features = false } + +# Note: We **need** to specify the `ink-as-dependency` feature. +# +# If we don't we will end up with linking errors! +other-contract = { path = "other-contract", default-features = false, features = ["ink-as-dependency"] } + +[dev-dependencies] +ink_e2e = { path = "../../crates/e2e" } + +[lib] +path = "lib.rs" + +[features] +default = ["std"] +std = [ + "ink/std", + + # Note: The metadata generation step requires `std`. If we don't specify this the metadata + # generation for our contract will fail! + "other-contract/std", +] +ink-as-dependency = [] +e2e-tests = [] diff --git a/integration-tests/cross-contract-calls/e2e_tests.rs b/integration-tests/cross-contract-calls/e2e_tests.rs new file mode 100644 index 00000000000..bf27597ba3e --- /dev/null +++ b/integration-tests/cross-contract-calls/e2e_tests.rs @@ -0,0 +1,94 @@ +use super::incrementer::*; +use ink_e2e::ContractsBackend; + +type E2EResult = std::result::Result>; + +#[ink_e2e::test] +async fn migration_works(mut client: Client) -> E2EResult<()> { + // Given + let mut constructor = IncrementerRef::new(); + let contract = client + .instantiate("incrementer", &ink_e2e::alice(), &mut constructor) + .submit() + .await + .expect("instantiate failed"); + let mut call = contract.call::(); + + let get = call.get(); + let get_res = client.call(&ink_e2e::alice(), &get).dry_run().await; + assert_eq!(get_res.return_value(), 0); + + let inc = call.inc(); + let _inc_result = client + .call(&ink_e2e::alice(), &inc) + .submit() + .await + .expect("`inc` failed"); + + let get = call.get(); + let get_res = client.call(&ink_e2e::alice(), &get).dry_run().await; + let pre_migration_value = get_res.return_value(); + assert_eq!(pre_migration_value, 1); + + // Upload the code for the contract to be updated to after the migration. + let new_code_hash = client + .upload("updated-incrementer", &ink_e2e::alice()) + .submit() + .await + .expect("uploading `updated-incrementer` failed") + .code_hash; + let new_code_hash = new_code_hash.as_ref().try_into().unwrap(); + + // Upload the code for the migration contract. + let migration_contract = client + .upload("migration", &ink_e2e::alice()) + .submit() + .await + .expect("uploading `migration` failed"); + let migration_code_hash = migration_contract.code_hash.as_ref().try_into().unwrap(); + + // When + + // Set the code hash to the migration contract + let set_code = call.set_code(migration_code_hash); + let _set_code_result = client + .call(&ink_e2e::alice(), &set_code) + .submit() + .await + .expect("`set_code` failed"); + + // Call the migration contract with a new value for `inc_by` and the code hash + // of the updated contract. + const NEW_INC_BY: u8 = 4; + let migrate = contract + .call::() + .migrate(NEW_INC_BY, new_code_hash); + + let _migration_result = client + .call(&ink_e2e::alice(), &migrate) + .submit() + .await + .expect("`migrate` failed"); + + // Then + let inc = contract + .call::() + .inc(); + + let _inc_result = client + .call(&ink_e2e::alice(), &inc) + .submit() + .await + .expect("`inc` failed"); + + let get = call.get(); + let get_res = client.call(&ink_e2e::alice(), &get).dry_run().await; + + // Remember, we updated our incrementer contract to increment by `4`. + assert_eq!( + get_res.return_value(), + pre_migration_value + NEW_INC_BY as u32 + ); + + Ok(()) +} \ No newline at end of file diff --git a/integration-tests/cross-contract-calls/lib.rs b/integration-tests/cross-contract-calls/lib.rs new file mode 100755 index 00000000000..8aa857d682d --- /dev/null +++ b/integration-tests/cross-contract-calls/lib.rs @@ -0,0 +1,46 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + +#[ink::contract] +mod cross_contract_calls { + /// We import the generated `ContractRef` of our other contract. + /// + /// Note that the other contract must have re-exported it (`pub use + /// OtherContractRef`) for us to have access to it. + use other_contract::OtherContractRef; + + #[ink(storage)] + pub struct CrossContractCalls { + /// We specify that our contract will store a reference to the `OtherContract`. + other_contract: AccountId, + } + + impl CrossContractCalls { + /// In order to use the `OtherContract` we first need to **instantiate** it. + /// + /// To do this we will use the uploaded `code_hash` of `OtherContract`. + #[ink(constructor)] + pub fn new(other_contract: AccountId) -> Self { + // todo: need to add instantiate_v2 methods... + let other_contract = OtherContractRef::new(true) + .code_hash(other_contract_code_hash) + .endowment(0) + .salt_bytes([0xDE, 0xAD, 0xBE, 0xEF]) + .instantiate(); + + Self { other_contract } + } + + /// Using the `ContractRef` we can call all the messages of the `OtherContract` as + /// if they were normal Rust methods (because at the end of the day, they + /// are!). + #[ink(message)] + pub fn flip_and_get(&mut self) -> bool { + // todo: add calls to `call_v2` + self.other_contract.flip(); + self.other_contract.get() + } + } +} + +#[cfg(all(test, feature = "e2e-tests"))] +mod e2e_tests; diff --git a/integration-tests/cross-contract-calls/other-contract/.gitignore b/integration-tests/cross-contract-calls/other-contract/.gitignore new file mode 100755 index 00000000000..8de8f877e47 --- /dev/null +++ b/integration-tests/cross-contract-calls/other-contract/.gitignore @@ -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 diff --git a/integration-tests/cross-contract-calls/other-contract/Cargo.toml b/integration-tests/cross-contract-calls/other-contract/Cargo.toml new file mode 100755 index 00000000000..c0b4748e22b --- /dev/null +++ b/integration-tests/cross-contract-calls/other-contract/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "other-contract" +version = "5.0.0-rc" +authors = ["Parity Technologies "] +edition = "2021" +publish = false + +[dependencies] +ink = { path = "../../../crates/ink", default-features = false } + +[dev-dependencies] +ink_e2e = { path = "../../../crates/e2e" } + +[lib] +path = "lib.rs" + +[features] +default = ["std"] +std = [ + "ink/std", +] +ink-as-dependency = [] +e2e-tests = [] diff --git a/integration-tests/cross-contract-calls/other-contract/lib.rs b/integration-tests/cross-contract-calls/other-contract/lib.rs new file mode 100755 index 00000000000..53e51019476 --- /dev/null +++ b/integration-tests/cross-contract-calls/other-contract/lib.rs @@ -0,0 +1,33 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + +/// Re-export the `ContractRef` generated by the ink! codegen. +/// +/// This let's other crates which pull this contract in as a dependency to interact +/// with this contract in a type-safe way. +pub use self::other_contract::OtherContractRef; + +#[ink::contract] +mod other_contract { + + #[ink(storage)] + pub struct OtherContract { + value: bool, + } + + impl OtherContract { + #[ink(constructor)] + pub fn new(init_value: bool) -> Self { + Self { value: init_value } + } + + #[ink(message)] + pub fn flip(&mut self) { + self.value = !self.value; + } + + #[ink(message)] + pub fn get(&self) -> bool { + self.value + } + } +} From a0813f9e18ed36aceeabb242dd5f96a1579c7a9e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 31 Jan 2024 12:07:08 +0000 Subject: [PATCH 07/47] Add `integration-test` for possible migration pattern (#1909) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * WIP * Update versions * WIP * WIP migration * WIP * Make test pass * Move e2e tests mod to own file * Update comment * Update example for new e2e API * Update integration-tests/upgradeable-contracts/set-code-hash-migration/lib.rs Co-authored-by: Michael Müller * Top level gitignore * Fix tests update comments * Update upgradeable contracts README.md * spelling --------- Co-authored-by: Michael Müller --- .../upgradeable-contracts/.gitignore | 2 + .../upgradeable-contracts/README.md | 15 +++ .../set-code-hash-migration/Cargo.toml | 28 ++++++ .../set-code-hash-migration/e2e_tests.rs | 94 +++++++++++++++++++ .../set-code-hash-migration/lib.rs | 69 ++++++++++++++ .../migration/Cargo.toml | 19 ++++ .../set-code-hash-migration/migration/lib.rs | 70 ++++++++++++++ .../updated-incrementer/Cargo.toml | 19 ++++ .../updated-incrementer/lib.rs | 75 +++++++++++++++ 9 files changed, 391 insertions(+) create mode 100644 integration-tests/upgradeable-contracts/.gitignore create mode 100644 integration-tests/upgradeable-contracts/set-code-hash-migration/Cargo.toml create mode 100644 integration-tests/upgradeable-contracts/set-code-hash-migration/e2e_tests.rs create mode 100644 integration-tests/upgradeable-contracts/set-code-hash-migration/lib.rs create mode 100644 integration-tests/upgradeable-contracts/set-code-hash-migration/migration/Cargo.toml create mode 100644 integration-tests/upgradeable-contracts/set-code-hash-migration/migration/lib.rs create mode 100644 integration-tests/upgradeable-contracts/set-code-hash-migration/updated-incrementer/Cargo.toml create mode 100644 integration-tests/upgradeable-contracts/set-code-hash-migration/updated-incrementer/lib.rs diff --git a/integration-tests/upgradeable-contracts/.gitignore b/integration-tests/upgradeable-contracts/.gitignore new file mode 100644 index 00000000000..ff75a1d9fa2 --- /dev/null +++ b/integration-tests/upgradeable-contracts/.gitignore @@ -0,0 +1,2 @@ +**/target/ +Cargo.lock \ No newline at end of file diff --git a/integration-tests/upgradeable-contracts/README.md b/integration-tests/upgradeable-contracts/README.md index 85bd7b5c81f..74a25d764ce 100644 --- a/integration-tests/upgradeable-contracts/README.md +++ b/integration-tests/upgradeable-contracts/README.md @@ -12,6 +12,21 @@ This is exactly what `set_code_hash()` function does. However, developers needs to be mindful of storage compatibility. You can read more about storage compatibility on [use.ink](https://use.ink/basics/upgradeable-contracts#replacing-contract-code-with-set_code_hash) +## [`set-code-hash`](set-code-hash-migration/) + +When upgrading a contract, the new code may have a different storage layout. This example illustrates a method to +migrate the storage from the old layout to the new layout. It does so by using an intermediate `migration` contract +which performs the storage upgrade. The workflow is as follows: + + +1. Upload a `migration` contract with a message `migrate` which performs the storage migration. +2. Set code hash to the `migration` contract. +3. Upload the upgraded version of the original contract. +4. Call `migrate` on the `migration` contract, passing the code hash of the new updated incrementer contract from `3.` +This must happen as a single message, because following the storage migration, the contract will not be able to be +called again, since it will fail to load the migrated storage. + + ## [Delegator](delegator/) Delegator patter is based around a low level cross contract call function `delegate_call`. diff --git a/integration-tests/upgradeable-contracts/set-code-hash-migration/Cargo.toml b/integration-tests/upgradeable-contracts/set-code-hash-migration/Cargo.toml new file mode 100644 index 00000000000..31a6b2cb2b6 --- /dev/null +++ b/integration-tests/upgradeable-contracts/set-code-hash-migration/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "incrementer" +version = "5.0.0-alpha" +authors = ["Parity Technologies "] +edition = "2021" +publish = false + +[dependencies] +ink = { path = "../../../crates/ink", default-features = false } + +migration = { path = "./migration", default-features = false, features = ["ink-as-dependency"] } +updated-incrementer = { path = "./updated-incrementer", default-features = false, features = ["ink-as-dependency"] } + +[dev-dependencies] +ink_e2e = { path = "../../../crates/e2e" } + +[lib] +path = "lib.rs" + +[features] +default = ["std"] +std = [ + "ink/std", + "migration/std", + "updated-incrementer/std", +] +ink-as-dependency = [] +e2e-tests = [] diff --git a/integration-tests/upgradeable-contracts/set-code-hash-migration/e2e_tests.rs b/integration-tests/upgradeable-contracts/set-code-hash-migration/e2e_tests.rs new file mode 100644 index 00000000000..dbbd029a8b0 --- /dev/null +++ b/integration-tests/upgradeable-contracts/set-code-hash-migration/e2e_tests.rs @@ -0,0 +1,94 @@ +use super::incrementer::*; +use ink_e2e::ContractsBackend; + +type E2EResult = std::result::Result>; + +#[ink_e2e::test] +async fn migration_works(mut client: Client) -> E2EResult<()> { + // Given + let mut constructor = IncrementerRef::new(); + let contract = client + .instantiate("incrementer", &ink_e2e::alice(), &mut constructor) + .submit() + .await + .expect("instantiate failed"); + let mut call_builder = contract.call_builder::(); + + let get = call_builder.get(); + let get_res = client.call(&ink_e2e::alice(), &get).dry_run().await?; + assert_eq!(get_res.return_value(), 0); + + let inc = call_builder.inc(); + let _inc_result = client + .call(&ink_e2e::alice(), &inc) + .submit() + .await + .expect("`inc` failed"); + + let get = call_builder.get(); + let get_res = client.call(&ink_e2e::alice(), &get).dry_run().await?; + let pre_migration_value = get_res.return_value(); + assert_eq!(pre_migration_value, 1); + + // Upload the code for the contract to be updated to after the migration. + let new_code_hash = client + .upload("updated-incrementer", &ink_e2e::alice()) + .submit() + .await + .expect("uploading `updated-incrementer` failed") + .code_hash; + let new_code_hash = new_code_hash.as_ref().try_into().unwrap(); + + // Upload the code for the migration contract. + let migration_contract = client + .upload("migration", &ink_e2e::alice()) + .submit() + .await + .expect("uploading `migration` failed"); + let migration_code_hash = migration_contract.code_hash.as_ref().try_into().unwrap(); + + // When + + // Set the code hash to the migration contract + let set_code = call_builder.set_code(migration_code_hash); + let _set_code_result = client + .call(&ink_e2e::alice(), &set_code) + .submit() + .await + .expect("`set_code` failed"); + + // Call the migration contract with a new value for `inc_by` and the code hash + // of the updated contract. + const NEW_INC_BY: u8 = 4; + let migrate = contract + .call_builder::() + .migrate(NEW_INC_BY, new_code_hash); + + let _migration_result = client + .call(&ink_e2e::alice(), &migrate) + .submit() + .await + .expect("`migrate` failed"); + + // Then + let inc = contract + .call_builder::() + .inc(); + + let _inc_result = client + .call(&ink_e2e::alice(), &inc) + .submit() + .await + .expect("`inc` failed"); + + let get = call_builder.get(); + let get_res = client.call(&ink_e2e::alice(), &get).dry_run().await?; + + // Remember, we updated our incrementer contract to increment by `4`. + assert_eq!( + get_res.return_value(), + pre_migration_value + NEW_INC_BY as u32 + ); + + Ok(()) +} diff --git a/integration-tests/upgradeable-contracts/set-code-hash-migration/lib.rs b/integration-tests/upgradeable-contracts/set-code-hash-migration/lib.rs new file mode 100644 index 00000000000..ea67cf199aa --- /dev/null +++ b/integration-tests/upgradeable-contracts/set-code-hash-migration/lib.rs @@ -0,0 +1,69 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + +//! Demonstrates how to use [`set_code_hash`](https://docs.rs/ink_env/latest/ink_env/fn.set_code_hash.html) +//! to swap out the `code_hash` of an on-chain contract. +//! +//! We will swap the code of our `Incrementer` contract with that of the `Incrementer` +//! found in the `updated_incrementer` folder. +//! +//! See the included End-to-End tests an example update workflow. + +#[ink::contract] +pub mod incrementer { + /// Track a counter in storage. + /// + /// # Note + /// + /// Is is important to realize that after the call to `set_code_hash` the contract's + /// storage remains the same. + /// + /// If you change the storage layout in your storage struct you may introduce + /// undefined behavior to your contract! + #[ink(storage)] + #[derive(Default)] + pub struct Incrementer { + count: u32, + } + + impl Incrementer { + /// Creates a new counter smart contract initialized with the given base value. + #[ink(constructor)] + pub fn new() -> Self { + Default::default() + } + + /// Increments the counter value which is stored in the contract's storage. + #[ink(message)] + pub fn inc(&mut self) { + self.count = self.count.checked_add(1).unwrap(); + ink::env::debug_println!( + "The new count is {}, it was modified using the original contract code.", + self.count + ); + } + + /// Returns the counter value which is stored in this contract's storage. + #[ink(message)] + pub fn get(&self) -> u32 { + self.count + } + + /// Modifies the code which is used to execute calls to this contract address + /// (`AccountId`). + /// + /// We use this to upgrade the contract logic. We don't do any authorization here, + /// any caller can execute this method. + /// + /// In a production contract you would do some authorization here! + #[ink(message)] + pub fn set_code(&mut self, code_hash: Hash) { + self.env().set_code_hash(&code_hash).unwrap_or_else(|err| { + panic!("Failed to `set_code_hash` to {code_hash:?} due to {err:?}") + }); + ink::env::debug_println!("Switched code hash to {:?}.", code_hash); + } + } +} + +#[cfg(all(test, feature = "e2e-tests"))] +mod e2e_tests; diff --git a/integration-tests/upgradeable-contracts/set-code-hash-migration/migration/Cargo.toml b/integration-tests/upgradeable-contracts/set-code-hash-migration/migration/Cargo.toml new file mode 100644 index 00000000000..af5cae8ab2a --- /dev/null +++ b/integration-tests/upgradeable-contracts/set-code-hash-migration/migration/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "migration" +version = "5.0.0-alpha" +authors = ["Parity Technologies "] +edition = "2021" +publish = false + +[dependencies] +ink = { path = "../../../../crates/ink", default-features = false } + +[lib] +path = "lib.rs" + +[features] +default = ["std"] +std = [ + "ink/std", +] +ink-as-dependency = [] diff --git a/integration-tests/upgradeable-contracts/set-code-hash-migration/migration/lib.rs b/integration-tests/upgradeable-contracts/set-code-hash-migration/migration/lib.rs new file mode 100644 index 00000000000..93d13cc6f19 --- /dev/null +++ b/integration-tests/upgradeable-contracts/set-code-hash-migration/migration/lib.rs @@ -0,0 +1,70 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] +#![allow(clippy::new_without_default)] + +#[ink::contract] +pub mod incrementer { + + /// Storage struct matches exactly that of the original `incrementer` contract, from + /// which we are migrating. + #[ink(storage)] + pub struct Incrementer { + count: u32, + } + + #[ink::storage_item] + pub struct IncrementerNew { + count: u64, + inc_by: u8, + } + + impl Incrementer { + /// Creates a new counter smart contract initialized with the given base value. + /// + /// # Note + /// + /// When upgrading using the `set_code_hash` workflow we only need to point to a + /// contract's uploaded code hash, **not** an instantiated contract's + /// `AccountId`. + /// + /// Because of this we will never actually call the constructor of this contract. + #[ink(constructor)] + pub fn new() -> Self { + unreachable!( + "Constructors are not called when upgrading using `set_code_hash`." + ) + } + + /// Run the migration to the data layout for the upgraded contract. + /// Once the storage migration has successfully completed, the contract will be + /// upgraded to the supplied code hash. + /// + /// In a production contract you would do some authorization here! + /// + /// # Note + /// + /// This function necessarily accepts a `&self` instead of a `&mut self` because + /// we are modifying storage directly for the migration. + /// + /// The `self` in `&mut self` is the original `Incrementer` storage struct, and + /// would be implicitly written to storage following the function execution, + /// overwriting the migrated storage. + #[ink(message)] + pub fn migrate(&self, inc_by: u8, code_hash: Hash) { + let incrementer_new = IncrementerNew { + count: self.count as u64, + inc_by, + }; + + // overwrite the original storage struct with the migrated storage struct, + // which has a layout compatible with the new contract code. + const STORAGE_KEY: u32 = + ::KEY; + ink::env::set_contract_storage(&STORAGE_KEY, &incrementer_new); + + ink::env::set_code_hash::<::Env>(&code_hash) + .unwrap_or_else(|err| { + panic!("Failed to `set_code_hash` to {code_hash:?} due to {err:?}") + }) + } + } +} diff --git a/integration-tests/upgradeable-contracts/set-code-hash-migration/updated-incrementer/Cargo.toml b/integration-tests/upgradeable-contracts/set-code-hash-migration/updated-incrementer/Cargo.toml new file mode 100644 index 00000000000..49b24990c9d --- /dev/null +++ b/integration-tests/upgradeable-contracts/set-code-hash-migration/updated-incrementer/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "updated-incrementer" +version = "5.0.0-alpha" +authors = ["Parity Technologies "] +edition = "2021" +publish = false + +[dependencies] +ink = { path = "../../../../crates/ink", default-features = false } + +[lib] +path = "lib.rs" + +[features] +default = ["std"] +std = [ + "ink/std", +] +ink-as-dependency = [] diff --git a/integration-tests/upgradeable-contracts/set-code-hash-migration/updated-incrementer/lib.rs b/integration-tests/upgradeable-contracts/set-code-hash-migration/updated-incrementer/lib.rs new file mode 100644 index 00000000000..7ac05c80e3d --- /dev/null +++ b/integration-tests/upgradeable-contracts/set-code-hash-migration/updated-incrementer/lib.rs @@ -0,0 +1,75 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] +#![allow(clippy::new_without_default)] + +#[ink::contract] +pub mod incrementer { + + /// Track a counter in storage. + /// + /// # Note + /// + /// We have changed the storage layout: + /// - `count` is now a `u64` instead of a `u32`. + /// - We have added a new field `inc_by` which controls how many to increment by. + #[ink(storage)] + pub struct Incrementer { + count: u64, + inc_by: u8, + } + + impl Incrementer { + /// Creates a new counter smart contract initialized with the given base value. + /// + /// # Note + /// + /// When upgrading using the `set_code_hash` workflow we only need to point to a + /// contract's uploaded code hash, **not** an instantiated contract's + /// `AccountId`. + /// + /// Because of this we will never actually call the constructor of this contract. + #[ink(constructor)] + pub fn new() -> Self { + unreachable!( + "Constructors are not called when upgrading using `set_code_hash`." + ) + } + + /// Increments the counter value which is stored in the contract's storage. + /// + /// # Note + /// + /// In this upgraded contract the value is incremented by the value in the + /// `inc_by` field. + #[ink(message)] + pub fn inc(&mut self) { + self.count = self.count.checked_add(self.inc_by.into()).unwrap(); + } + + /// Set the value by which the counter will be incremented. + #[ink(message)] + pub fn set_inc_by(&mut self, inc_by: u8) { + self.inc_by = inc_by; + } + + /// Returns the counter value which is stored in this contract's storage. + #[ink(message)] + pub fn get(&self) -> u64 { + self.count + } + + /// Modifies the code which is used to execute calls to this contract address + /// (`AccountId`). + /// + /// We use this to upgrade the contract logic. We don't do any authorization here, + /// any caller can execute this method. + /// + /// In a production contract you would do some authorization here! + #[ink(message)] + pub fn set_code(&mut self, code_hash: Hash) { + self.env().set_code_hash(&code_hash).unwrap_or_else(|err| { + panic!("Failed to `set_code_hash` to {code_hash:?} due to {err:?}") + }); + ink::env::debug_println!("Switched code hash to {:?}.", code_hash); + } + } +} From bab2e0a0fa78c7b1e539b43a578625a41e90e5b8 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 31 Jan 2024 12:42:41 +0000 Subject: [PATCH 08/47] Add `basic-contract-caller` E2E test (#2085) * add e2e tests to basic-contract-caller example * Fix basic-contract-caller e2e tests * Remove `call_builder` change * Remove `basic_contract_caller` integration test, moved to #1909 * Revert "Remove `basic_contract_caller` integration test, moved to #1909" This reverts commit 8f3ab318035735545af513893556658b709c5244. * fmt --- .../basic-contract-caller/e2e_tests.rs | 35 +++++++++++++++++++ .../basic-contract-caller/lib.rs | 3 ++ 2 files changed, 38 insertions(+) create mode 100644 integration-tests/basic-contract-caller/e2e_tests.rs diff --git a/integration-tests/basic-contract-caller/e2e_tests.rs b/integration-tests/basic-contract-caller/e2e_tests.rs new file mode 100644 index 00000000000..e9ce86d4bc1 --- /dev/null +++ b/integration-tests/basic-contract-caller/e2e_tests.rs @@ -0,0 +1,35 @@ +use super::basic_contract_caller::*; +use ink_e2e::ContractsBackend; + +type E2EResult = std::result::Result>; + +#[ink_e2e::test] +async fn flip_and_get(mut client: Client) -> E2EResult<()> { + // given + let other_contract_code = client + .upload("other-contract", &ink_e2e::alice()) + .submit() + .await + .expect("other_contract upload failed"); + + let mut constructor = BasicContractCallerRef::new(other_contract_code.code_hash); + let contract = client + .instantiate("basic-contract-caller", &ink_e2e::alice(), &mut constructor) + .submit() + .await + .expect("basic-contract-caller instantiate failed"); + let mut call_builder = contract.call_builder::(); + let call = call_builder.flip_and_get(); + + // when + let result = client + .call(&ink_e2e::alice(), &call) + .submit() + .await + .expect("Calling `flip_and_get` failed") + .return_value(); + + assert_eq!(result, false); + + Ok(()) +} diff --git a/integration-tests/basic-contract-caller/lib.rs b/integration-tests/basic-contract-caller/lib.rs index f988caabf41..78c999d7c26 100755 --- a/integration-tests/basic-contract-caller/lib.rs +++ b/integration-tests/basic-contract-caller/lib.rs @@ -39,3 +39,6 @@ mod basic_contract_caller { } } } + +#[cfg(all(test, feature = "e2e-tests"))] +mod e2e_tests; From b2a2cf93e6cd75d37907c7d5ead0e24c2069faf1 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 31 Jan 2024 14:45:19 +0000 Subject: [PATCH 09/47] Only need one .gitignore --- integration-tests/cross-contract-calls/.gitignore | 9 +-------- .../cross-contract-calls/other-contract/.gitignore | 9 --------- 2 files changed, 1 insertion(+), 17 deletions(-) delete mode 100755 integration-tests/cross-contract-calls/other-contract/.gitignore diff --git a/integration-tests/cross-contract-calls/.gitignore b/integration-tests/cross-contract-calls/.gitignore index 8de8f877e47..4531c3e8a6b 100755 --- a/integration-tests/cross-contract-calls/.gitignore +++ b/integration-tests/cross-contract-calls/.gitignore @@ -1,9 +1,2 @@ -# 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 +**/target/ Cargo.lock diff --git a/integration-tests/cross-contract-calls/other-contract/.gitignore b/integration-tests/cross-contract-calls/other-contract/.gitignore deleted file mode 100755 index 8de8f877e47..00000000000 --- a/integration-tests/cross-contract-calls/other-contract/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -# 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 From bd83e1861c0db2af428e6b10f9a1a44d318b40d5 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 31 Jan 2024 18:41:11 +0000 Subject: [PATCH 10/47] WIP adding create v2 API --- crates/env/src/call/create_builder.rs | 27 +++++++++++++++---- integration-tests/cross-contract-calls/lib.rs | 2 +- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/crates/env/src/call/create_builder.rs b/crates/env/src/call/create_builder.rs index 2cfb62eb543..95f6b07792f 100644 --- a/crates/env/src/call/create_builder.rs +++ b/crates/env/src/call/create_builder.rs @@ -24,6 +24,7 @@ use crate::{ ExecutionInput, Selector, }, + types::Gas, ContractEnv, Environment, Error, @@ -175,7 +176,12 @@ where /// The code hash of the created contract. code_hash: E::Hash, /// The maximum gas costs allowed for the instantiation. - gas_limit: u64, + /// todo: [AJ] ref_time_limit docs + ref_time_limit: Gas, + /// todo: [AJ] `proof_time_limit` docs + proof_time_limit: Gas, + /// todo: [AJ] `storage_deposit_limit` docs + storage_deposit_limit: Option, /// The endowment for the instantiated contract. endowment: E::Balance, /// The input data for the instantiation. @@ -198,10 +204,21 @@ where &self.code_hash } - /// The gas limit for the contract instantiation. + /// todo: [AJ] ref_time_limit docs #[inline] - pub fn gas_limit(&self) -> u64 { - self.gas_limit + pub fn ref_time_limit(&self) -> u64 { + self.ref_time_limit + } + + /// todo: [AJ] proof_time_limit docs + #[inline] + pub fn proof_time_limit(&self) -> u64 { + self.proof_time_limit + } + + /// todo: [AJ] `storage_deposit_limit` docs + pub fn storage_deposit_limit(&self) -> u64 { + self.proof_time_limit } /// The endowment for the instantiated contract. @@ -698,7 +715,7 @@ where pub fn params(self) -> CreateParams { CreateParams { code_hash: self.code_hash.value(), - gas_limit: self.gas_limit.unwrap_or_else(|| 0), + ref_time_limit: self.gas_limit.unwrap_or_else(|| 0), endowment: self.endowment.value(), exec_input: self.exec_input.value(), salt_bytes: self.salt.value(), diff --git a/integration-tests/cross-contract-calls/lib.rs b/integration-tests/cross-contract-calls/lib.rs index 8aa857d682d..501744aa3dd 100755 --- a/integration-tests/cross-contract-calls/lib.rs +++ b/integration-tests/cross-contract-calls/lib.rs @@ -19,7 +19,7 @@ mod cross_contract_calls { /// /// To do this we will use the uploaded `code_hash` of `OtherContract`. #[ink(constructor)] - pub fn new(other_contract: AccountId) -> Self { + pub fn new(other_contract_code_hash: Hash) -> Self { // todo: need to add instantiate_v2 methods... let other_contract = OtherContractRef::new(true) .code_hash(other_contract_code_hash) From ab251c2b3eff4c2bfc73df981ba61732f85aa410 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 1 Feb 2024 15:11:59 +0000 Subject: [PATCH 11/47] Revert "WIP adding create v2 API" This reverts commit bd83e1861c0db2af428e6b10f9a1a44d318b40d5. --- crates/env/src/call/create_builder.rs | 27 ++++--------------- integration-tests/cross-contract-calls/lib.rs | 2 +- 2 files changed, 6 insertions(+), 23 deletions(-) diff --git a/crates/env/src/call/create_builder.rs b/crates/env/src/call/create_builder.rs index 95f6b07792f..2cfb62eb543 100644 --- a/crates/env/src/call/create_builder.rs +++ b/crates/env/src/call/create_builder.rs @@ -24,7 +24,6 @@ use crate::{ ExecutionInput, Selector, }, - types::Gas, ContractEnv, Environment, Error, @@ -176,12 +175,7 @@ where /// The code hash of the created contract. code_hash: E::Hash, /// The maximum gas costs allowed for the instantiation. - /// todo: [AJ] ref_time_limit docs - ref_time_limit: Gas, - /// todo: [AJ] `proof_time_limit` docs - proof_time_limit: Gas, - /// todo: [AJ] `storage_deposit_limit` docs - storage_deposit_limit: Option, + gas_limit: u64, /// The endowment for the instantiated contract. endowment: E::Balance, /// The input data for the instantiation. @@ -204,21 +198,10 @@ where &self.code_hash } - /// todo: [AJ] ref_time_limit docs + /// The gas limit for the contract instantiation. #[inline] - pub fn ref_time_limit(&self) -> u64 { - self.ref_time_limit - } - - /// todo: [AJ] proof_time_limit docs - #[inline] - pub fn proof_time_limit(&self) -> u64 { - self.proof_time_limit - } - - /// todo: [AJ] `storage_deposit_limit` docs - pub fn storage_deposit_limit(&self) -> u64 { - self.proof_time_limit + pub fn gas_limit(&self) -> u64 { + self.gas_limit } /// The endowment for the instantiated contract. @@ -715,7 +698,7 @@ where pub fn params(self) -> CreateParams { CreateParams { code_hash: self.code_hash.value(), - ref_time_limit: self.gas_limit.unwrap_or_else(|| 0), + gas_limit: self.gas_limit.unwrap_or_else(|| 0), endowment: self.endowment.value(), exec_input: self.exec_input.value(), salt_bytes: self.salt.value(), diff --git a/integration-tests/cross-contract-calls/lib.rs b/integration-tests/cross-contract-calls/lib.rs index 501744aa3dd..8aa857d682d 100755 --- a/integration-tests/cross-contract-calls/lib.rs +++ b/integration-tests/cross-contract-calls/lib.rs @@ -19,7 +19,7 @@ mod cross_contract_calls { /// /// To do this we will use the uploaded `code_hash` of `OtherContract`. #[ink(constructor)] - pub fn new(other_contract_code_hash: Hash) -> Self { + pub fn new(other_contract: AccountId) -> Self { // todo: need to add instantiate_v2 methods... let other_contract = OtherContractRef::new(true) .code_hash(other_contract_code_hash) From 16d14790c3d500577b83222d068b26cc75f56d75 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 1 Feb 2024 18:12:58 +0000 Subject: [PATCH 12/47] WIP e2e tests --- .../cross-contract-calls/e2e_tests.rs | 97 ++++--------------- integration-tests/cross-contract-calls/lib.rs | 41 +++++--- .../other-contract/lib.rs | 6 +- 3 files changed, 48 insertions(+), 96 deletions(-) diff --git a/integration-tests/cross-contract-calls/e2e_tests.rs b/integration-tests/cross-contract-calls/e2e_tests.rs index bf27597ba3e..51313444478 100644 --- a/integration-tests/cross-contract-calls/e2e_tests.rs +++ b/integration-tests/cross-contract-calls/e2e_tests.rs @@ -1,94 +1,35 @@ -use super::incrementer::*; +use super::cross_contract_calls::*; use ink_e2e::ContractsBackend; type E2EResult = std::result::Result>; #[ink_e2e::test] -async fn migration_works(mut client: Client) -> E2EResult<()> { - // Given - let mut constructor = IncrementerRef::new(); - let contract = client - .instantiate("incrementer", &ink_e2e::alice(), &mut constructor) - .submit() - .await - .expect("instantiate failed"); - let mut call = contract.call::(); - - let get = call.get(); - let get_res = client.call(&ink_e2e::alice(), &get).dry_run().await; - assert_eq!(get_res.return_value(), 0); - - let inc = call.inc(); - let _inc_result = client - .call(&ink_e2e::alice(), &inc) - .submit() - .await - .expect("`inc` failed"); - - let get = call.get(); - let get_res = client.call(&ink_e2e::alice(), &get).dry_run().await; - let pre_migration_value = get_res.return_value(); - assert_eq!(pre_migration_value, 1); - - // Upload the code for the contract to be updated to after the migration. - let new_code_hash = client - .upload("updated-incrementer", &ink_e2e::alice()) - .submit() - .await - .expect("uploading `updated-incrementer` failed") - .code_hash; - let new_code_hash = new_code_hash.as_ref().try_into().unwrap(); - - // Upload the code for the migration contract. - let migration_contract = client - .upload("migration", &ink_e2e::alice()) - .submit() - .await - .expect("uploading `migration` failed"); - let migration_code_hash = migration_contract.code_hash.as_ref().try_into().unwrap(); - - // When - - // Set the code hash to the migration contract - let set_code = call.set_code(migration_code_hash); - let _set_code_result = client - .call(&ink_e2e::alice(), &set_code) +async fn flip_and_get(mut client: Client) -> E2EResult<()> { + // given + let other_contract_code = client + .upload("other-contract", &ink_e2e::alice()) .submit() .await - .expect("`set_code` failed"); - - // Call the migration contract with a new value for `inc_by` and the code hash - // of the updated contract. - const NEW_INC_BY: u8 = 4; - let migrate = contract - .call::() - .migrate(NEW_INC_BY, new_code_hash); + .expect("other_contract upload failed"); - let _migration_result = client - .call(&ink_e2e::alice(), &migrate) + let mut constructor = CrossContractCallsRef::new(other_contract_code.code_hash); + let contract = client + .instantiate("cross-contract-calls", &ink_e2e::alice(), &mut constructor) .submit() .await - .expect("`migrate` failed"); + .expect("cross-contract-calls instantiate failed"); + let mut call_builder = contract.call_builder::(); + let call = call_builder.flip_and_get(); - // Then - let inc = contract - .call::() - .inc(); - - let _inc_result = client - .call(&ink_e2e::alice(), &inc) + // when + let result = client + .call(&ink_e2e::alice(), &call) .submit() .await - .expect("`inc` failed"); - - let get = call.get(); - let get_res = client.call(&ink_e2e::alice(), &get).dry_run().await; + .expect("Calling `flip_and_get` failed") + .return_value(); - // Remember, we updated our incrementer contract to increment by `4`. - assert_eq!( - get_res.return_value(), - pre_migration_value + NEW_INC_BY as u32 - ); + assert_eq!(result, false); Ok(()) -} \ No newline at end of file +} diff --git a/integration-tests/cross-contract-calls/lib.rs b/integration-tests/cross-contract-calls/lib.rs index 8aa857d682d..7cb70f2e049 100755 --- a/integration-tests/cross-contract-calls/lib.rs +++ b/integration-tests/cross-contract-calls/lib.rs @@ -2,16 +2,21 @@ #[ink::contract] mod cross_contract_calls { - /// We import the generated `ContractRef` of our other contract. - /// - /// Note that the other contract must have re-exported it (`pub use - /// OtherContractRef`) for us to have access to it. - use other_contract::OtherContractRef; + use ink::{ + codegen::ContractCallBuilder, + env::{ + ContractEnv, + call::FromAccountId + }, + }; + use other_contract::{OtherContract, OtherContractRef}; + + type Env = ::Env; + type OtherContractCallBuilder = ::Type; #[ink(storage)] pub struct CrossContractCalls { - /// We specify that our contract will store a reference to the `OtherContract`. - other_contract: AccountId, + other_contract_call_builder: OtherContractCallBuilder, } impl CrossContractCalls { @@ -19,15 +24,18 @@ mod cross_contract_calls { /// /// To do this we will use the uploaded `code_hash` of `OtherContract`. #[ink(constructor)] - pub fn new(other_contract: AccountId) -> Self { - // todo: need to add instantiate_v2 methods... + pub fn new(other_contract_code_hash: Hash) -> Self { let other_contract = OtherContractRef::new(true) .code_hash(other_contract_code_hash) .endowment(0) .salt_bytes([0xDE, 0xAD, 0xBE, 0xEF]) .instantiate(); - Self { other_contract } + let other_contract_call_builder = >::from_account_id( + *other_contract.as_ref(), + ); + + Self { other_contract_call_builder } } /// Using the `ContractRef` we can call all the messages of the `OtherContract` as @@ -35,9 +43,16 @@ mod cross_contract_calls { /// are!). #[ink(message)] pub fn flip_and_get(&mut self) -> bool { - // todo: add calls to `call_v2` - self.other_contract.flip(); - self.other_contract.get() + self.other_contract_call_builder + .flip() + // .v2() + // .weight_limit(0, 0) + .invoke(); + + self.other_contract_call_builder + .get() + // .v2() + .invoke() } } } diff --git a/integration-tests/cross-contract-calls/other-contract/lib.rs b/integration-tests/cross-contract-calls/other-contract/lib.rs index 53e51019476..61dea79a435 100755 --- a/integration-tests/cross-contract-calls/other-contract/lib.rs +++ b/integration-tests/cross-contract-calls/other-contract/lib.rs @@ -1,10 +1,6 @@ #![cfg_attr(not(feature = "std"), no_std, no_main)] -/// Re-export the `ContractRef` generated by the ink! codegen. -/// -/// This let's other crates which pull this contract in as a dependency to interact -/// with this contract in a type-safe way. -pub use self::other_contract::OtherContractRef; +pub use self::other_contract::{OtherContract, OtherContractRef}; #[ink::contract] mod other_contract { From 85e7e9c4704a389756eced6e69c3ab9ebe836c8c Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 2 Feb 2024 12:19:47 +0000 Subject: [PATCH 13/47] Add CallV2 builder methods --- crates/env/src/call/call_builder.rs | 108 +++++++++++++++++- crates/env/src/call/mod.rs | 2 +- integration-tests/cross-contract-calls/lib.rs | 27 +++-- .../other-contract/lib.rs | 5 +- 4 files changed, 124 insertions(+), 18 deletions(-) diff --git a/crates/env/src/call/call_builder.rs b/crates/env/src/call/call_builder.rs index 4b0737afbe2..f65704d0bd0 100644 --- a/crates/env/src/call/call_builder.rs +++ b/crates/env/src/call/call_builder.rs @@ -648,9 +648,7 @@ where E: Environment, { /// todo: [AJ] docs - pub fn v2( - self, - ) -> CallBuilder>, Args, RetType> { + pub fn v2(self) -> CallBuilder>, Args, RetType> { let call_type = self.call_type.value(); CallBuilder { call_type: Set(CallV2 { @@ -658,7 +656,7 @@ where ref_time_limit: call_type.gas_limit, proof_time_limit: Default::default(), transferred_value: call_type.transferred_value, - } ), + }), call_flags: self.call_flags, exec_input: self.exec_input, return_type: self.return_type, @@ -772,6 +770,23 @@ where } } +impl + CallBuilder>, Set>, Set>> +where + E: Environment, +{ + /// Finalizes the call builder to call a function. + pub fn params(self) -> CallParams, Args, RetType> { + CallParams { + call_type: self.call_type.value(), + call_flags: self.call_flags, + _return_type: Default::default(), + exec_input: self.exec_input.value(), + _phantom: self._phantom, + } + } +} + impl CallBuilder< E, @@ -811,6 +826,28 @@ where } } +impl + CallBuilder< + E, + Set>, + Unset>, + Unset, + > +where + E: Environment, +{ + /// Finalizes the call builder to call a function. + pub fn params(self) -> CallParams, EmptyArgumentList, ()> { + CallParams { + call_type: self.call_type.value(), + call_flags: self.call_flags, + _return_type: Default::default(), + exec_input: Default::default(), + _phantom: self._phantom, + } + } +} + impl CallBuilder< E, @@ -866,6 +903,39 @@ where } } +impl + CallBuilder< + E, + Set>, + Unset>, + Unset>, + > +where + E: Environment, +{ + /// Invokes the cross-chain function call. + /// + /// # Panics + /// + /// This method panics if it encounters an [`ink::env::Error`][`crate::Error`] or an + /// [`ink::primitives::LangError`][`ink_primitives::LangError`]. If you want to handle + /// those use the [`try_invoke`][`CallBuilder::try_invoke`] method instead. + pub fn invoke(self) { + self.params().invoke() + } + + /// Invokes the cross-chain function call. + /// + /// # Note + /// + /// On failure this returns an outer [`ink::env::Error`][`crate::Error`] or inner + /// [`ink::primitives::LangError`][`ink_primitives::LangError`], both of which can be + /// handled by the caller. + pub fn try_invoke(self) -> Result, Error> { + self.params().try_invoke() + } +} + impl CallBuilder< E, @@ -928,6 +998,36 @@ where } } +impl + CallBuilder>, Set>, Set>> +where + E: Environment, + Args: scale::Encode, + R: scale::Decode, +{ + /// Invokes the cross-chain function call and returns the result. + /// + /// # Panics + /// + /// This method panics if it encounters an [`ink::env::Error`][`crate::Error`] or an + /// [`ink::primitives::LangError`][`ink_primitives::LangError`]. If you want to handle + /// those use the [`try_invoke`][`CallBuilder::try_invoke`] method instead. + pub fn invoke(self) -> R { + self.params().invoke() + } + + /// Invokes the cross-chain function call and returns the result. + /// + /// # Note + /// + /// On failure this returns an outer [`ink::env::Error`][`crate::Error`] or inner + /// [`ink::primitives::LangError`][`ink_primitives::LangError`], both of which can be + /// handled by the caller. + pub fn try_invoke(self) -> Result, Error> { + self.params().try_invoke() + } +} + impl CallBuilder>, Set>, Set>> where diff --git a/crates/env/src/call/mod.rs b/crates/env/src/call/mod.rs index 76264aa9e0b..463b96ce5f5 100644 --- a/crates/env/src/call/mod.rs +++ b/crates/env/src/call/mod.rs @@ -43,9 +43,9 @@ pub use self::{ call_builder::{ build_call, Call, - CallV2, CallBuilder, CallParams, + CallV2, DelegateCall, }, create_builder::{ diff --git a/integration-tests/cross-contract-calls/lib.rs b/integration-tests/cross-contract-calls/lib.rs index 7cb70f2e049..e10ca3fb0b6 100755 --- a/integration-tests/cross-contract-calls/lib.rs +++ b/integration-tests/cross-contract-calls/lib.rs @@ -5,11 +5,14 @@ mod cross_contract_calls { use ink::{ codegen::ContractCallBuilder, env::{ + call::FromAccountId, ContractEnv, - call::FromAccountId }, }; - use other_contract::{OtherContract, OtherContractRef}; + use other_contract::{ + OtherContract, + OtherContractRef, + }; type Env = ::Env; type OtherContractCallBuilder = ::Type; @@ -31,11 +34,14 @@ mod cross_contract_calls { .salt_bytes([0xDE, 0xAD, 0xBE, 0xEF]) .instantiate(); - let other_contract_call_builder = >::from_account_id( - *other_contract.as_ref(), - ); + let other_contract_call_builder = + >::from_account_id( + *other_contract.as_ref(), + ); - Self { other_contract_call_builder } + Self { + other_contract_call_builder, + } } /// Using the `ContractRef` we can call all the messages of the `OtherContract` as @@ -45,14 +51,11 @@ mod cross_contract_calls { pub fn flip_and_get(&mut self) -> bool { self.other_contract_call_builder .flip() - // .v2() - // .weight_limit(0, 0) + .v2() + .weight_limit(0, 0) .invoke(); - self.other_contract_call_builder - .get() - // .v2() - .invoke() + self.other_contract_call_builder.get().v2().invoke() } } } diff --git a/integration-tests/cross-contract-calls/other-contract/lib.rs b/integration-tests/cross-contract-calls/other-contract/lib.rs index 61dea79a435..ed280b63812 100755 --- a/integration-tests/cross-contract-calls/other-contract/lib.rs +++ b/integration-tests/cross-contract-calls/other-contract/lib.rs @@ -1,6 +1,9 @@ #![cfg_attr(not(feature = "std"), no_std, no_main)] -pub use self::other_contract::{OtherContract, OtherContractRef}; +pub use self::other_contract::{ + OtherContract, + OtherContractRef, +}; #[ink::contract] mod other_contract { From eb7ca99ed632f6902b6aebe82f896004e6c5757e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 2 Feb 2024 17:29:28 +0000 Subject: [PATCH 14/47] Pass weight limit as params --- crates/env/src/call/call_builder.rs | 21 ++++++++++++-- .../cross-contract-calls/e2e_tests.rs | 16 +++++++++- integration-tests/cross-contract-calls/lib.rs | 29 ++++++++++++++----- 3 files changed, 55 insertions(+), 11 deletions(-) diff --git a/crates/env/src/call/call_builder.rs b/crates/env/src/call/call_builder.rs index f65704d0bd0..bf9e8139801 100644 --- a/crates/env/src/call/call_builder.rs +++ b/crates/env/src/call/call_builder.rs @@ -701,14 +701,31 @@ impl CallBuilder>, Args, RetType> where E: Environment, { + /// Sets the `ref_time_limit` for the current cross-contract call. + pub fn ref_time_limit(self, ref_time_limit: Gas) -> Self { + let call_type = self.call_type.value(); + CallBuilder { + call_type: Set(CallV2 { + callee: call_type.callee, + ref_time_limit, + proof_time_limit: call_type.proof_time_limit, + transferred_value: call_type.transferred_value, + }), + call_flags: self.call_flags, + exec_input: self.exec_input, + return_type: self.return_type, + _phantom: Default::default(), + } + } + /// Sets the `ref_time_limit` and the `proof_time_limit` for the current /// cross-contract call. - pub fn weight_limit(self, ref_time_limit: Gas, proof_time_limit: Gas) -> Self { + pub fn proof_time_limit(self, proof_time_limit: Gas) -> Self { let call_type = self.call_type.value(); CallBuilder { call_type: Set(CallV2 { callee: call_type.callee, - ref_time_limit, + ref_time_limit: call_type.ref_time_limit, proof_time_limit, transferred_value: call_type.transferred_value, }), diff --git a/integration-tests/cross-contract-calls/e2e_tests.rs b/integration-tests/cross-contract-calls/e2e_tests.rs index 51313444478..47f64785a53 100644 --- a/integration-tests/cross-contract-calls/e2e_tests.rs +++ b/integration-tests/cross-contract-calls/e2e_tests.rs @@ -19,9 +19,13 @@ async fn flip_and_get(mut client: Client) -> E2EResult<()> { .await .expect("cross-contract-calls instantiate failed"); let mut call_builder = contract.call_builder::(); - let call = call_builder.flip_and_get(); + + const REF_TIME_LIMIT: u64 = 500_000_000; + const PROOF_TIME_LIMIT: u64 = 100_000; // when + let call = call_builder + .flip_and_get_invoke_v2_with_weight_limit(REF_TIME_LIMIT, PROOF_TIME_LIMIT); let result = client .call(&ink_e2e::alice(), &call) .submit() @@ -31,5 +35,15 @@ async fn flip_and_get(mut client: Client) -> E2EResult<()> { assert_eq!(result, false); + let call = call_builder.flip_and_get_invoke_v2_no_weight_limit(); + let result = client + .call(&ink_e2e::alice(), &call) + .submit() + .await + .expect("Calling `flip_and_get` failed") + .return_value(); + + assert_eq!(result, true); + Ok(()) } diff --git a/integration-tests/cross-contract-calls/lib.rs b/integration-tests/cross-contract-calls/lib.rs index e10ca3fb0b6..2d14528caf8 100755 --- a/integration-tests/cross-contract-calls/lib.rs +++ b/integration-tests/cross-contract-calls/lib.rs @@ -23,9 +23,7 @@ mod cross_contract_calls { } impl CrossContractCalls { - /// In order to use the `OtherContract` we first need to **instantiate** it. - /// - /// To do this we will use the uploaded `code_hash` of `OtherContract`. + /// todo: [AJ] comment #[ink(constructor)] pub fn new(other_contract_code_hash: Hash) -> Self { let other_contract = OtherContractRef::new(true) @@ -44,17 +42,32 @@ mod cross_contract_calls { } } - /// Using the `ContractRef` we can call all the messages of the `OtherContract` as - /// if they were normal Rust methods (because at the end of the day, they - /// are!). + /// todo: [AJ] comment #[ink(message)] - pub fn flip_and_get(&mut self) -> bool { + pub fn flip_and_get_invoke_v2_with_weight_limit( + &mut self, + ref_time_limit: u64, + proof_time_limit: u64, + ) -> bool { self.other_contract_call_builder .flip() .v2() - .weight_limit(0, 0) + .ref_time_limit(ref_time_limit) + .proof_time_limit(proof_time_limit) .invoke(); + self.other_contract_call_builder + .get() + .v2() + .ref_time_limit(ref_time_limit) + .proof_time_limit(proof_time_limit) + .invoke() + } + + #[ink(message)] + pub fn flip_and_get_invoke_v2_no_weight_limit(&mut self) -> bool { + self.other_contract_call_builder.flip().v2().invoke(); + self.other_contract_call_builder.get().v2().invoke() } } From 2c0a6328d7b240b6f6ff9f1ebe2b1e3945dd9e15 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 2 Feb 2024 17:42:20 +0000 Subject: [PATCH 15/47] Allow deprecated --- crates/env/src/engine/on_chain/impls.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/env/src/engine/on_chain/impls.rs b/crates/env/src/engine/on_chain/impls.rs index 4ada9665846..3857a699976 100644 --- a/crates/env/src/engine/on_chain/impls.rs +++ b/crates/env/src/engine/on_chain/impls.rs @@ -488,6 +488,7 @@ impl TypedEnvBackend for EnvInstance { }; let output = &mut scope.take_rest(); let flags = params.call_flags(); + #[allow(deprecated)] let call_result = ext::call_v2( *flags, enc_callee, From 8b6ce3f6c6fe258f4c2a410e79e4f981fbe3626f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 2 Feb 2024 18:24:44 +0000 Subject: [PATCH 16/47] Add storage_deposit_limit --- crates/env/src/call/call_builder.rs | 60 ++++++++++++++++--- crates/env/src/engine/on_chain/impls.rs | 5 +- .../cross-contract-calls/e2e_tests.rs | 8 ++- integration-tests/cross-contract-calls/lib.rs | 5 +- 4 files changed, 66 insertions(+), 12 deletions(-) diff --git a/crates/env/src/call/call_builder.rs b/crates/env/src/call/call_builder.rs index bf9e8139801..7caa997b1fa 100644 --- a/crates/env/src/call/call_builder.rs +++ b/crates/env/src/call/call_builder.rs @@ -100,16 +100,22 @@ where /// Returns the chosen ref time limit for the called contract execution. #[inline] - pub fn ref_time_limit(&self) -> Gas { + pub fn ref_time_limit(&self) -> u64 { self.call_type.ref_time_limit } /// Returns the chosen proof time limit for the called contract execution. #[inline] - pub fn proof_time_limit(&self) -> Gas { + pub fn proof_time_limit(&self) -> u64 { self.call_type.proof_time_limit } + /// Returns the chosen storage deposit limit for the called contract execution. + #[inline] + pub fn storage_deposit_limit(&self) -> Option<&E::Balance> { + self.call_type.storage_deposit_limit.as_ref() + } + /// Returns the transferred value for the called contract. #[inline] pub fn transferred_value(&self) -> &E::Balance { @@ -450,8 +456,9 @@ where #[derive(Clone)] pub struct CallV2 { callee: E::AccountId, - ref_time_limit: Gas, - proof_time_limit: Gas, + ref_time_limit: u64, + proof_time_limit: u64, + storage_deposit_limit: Option, transferred_value: E::Balance, } @@ -462,6 +469,7 @@ impl CallV2 { callee, ref_time_limit: Default::default(), proof_time_limit: Default::default(), + storage_deposit_limit: None, transferred_value: E::Balance::zero(), } } @@ -471,12 +479,24 @@ impl CallV2 where E: Environment, { - /// Sets the `gas_limit` for the current cross-contract call. - pub fn weight_limit(self, ref_time_limit: Gas, proof_time_limit: Gas) -> Self { + /// Sets the `weight_limit` for the current cross-contract call. + pub fn weight_limit(self, ref_time_limit: u64, proof_time_limit: u64) -> Self { CallV2 { callee: self.callee, ref_time_limit, proof_time_limit, + storage_deposit_limit: self.storage_deposit_limit, + transferred_value: self.transferred_value, + } + } + + /// todo: [AJ] storage_deposit_limit docs + pub fn storage_deposit_limit(self, storage_deposit_limit: E::Balance) -> Self { + CallV2 { + callee: self.callee, + ref_time_limit: self.ref_time_limit, + proof_time_limit: self.proof_time_limit, + storage_deposit_limit: Some(storage_deposit_limit), transferred_value: self.transferred_value, } } @@ -487,6 +507,7 @@ where callee: self.callee, ref_time_limit: self.ref_time_limit, proof_time_limit: self.proof_time_limit, + storage_deposit_limit: self.storage_deposit_limit, transferred_value, } } @@ -655,6 +676,7 @@ where callee: call_type.callee, ref_time_limit: call_type.gas_limit, proof_time_limit: Default::default(), + storage_deposit_limit: None, transferred_value: call_type.transferred_value, }), call_flags: self.call_flags, @@ -701,7 +723,8 @@ impl CallBuilder>, Args, RetType> where E: Environment, { - /// Sets the `ref_time_limit` for the current cross-contract call. + /// Sets the `ref_time_limit` part of the weight limit for the current cross-contract + /// call. pub fn ref_time_limit(self, ref_time_limit: Gas) -> Self { let call_type = self.call_type.value(); CallBuilder { @@ -709,6 +732,7 @@ where callee: call_type.callee, ref_time_limit, proof_time_limit: call_type.proof_time_limit, + storage_deposit_limit: call_type.storage_deposit_limit, transferred_value: call_type.transferred_value, }), call_flags: self.call_flags, @@ -718,7 +742,7 @@ where } } - /// Sets the `ref_time_limit` and the `proof_time_limit` for the current + /// Sets the `proof_time_limit` part of the weight limit for the current /// cross-contract call. pub fn proof_time_limit(self, proof_time_limit: Gas) -> Self { let call_type = self.call_type.value(); @@ -727,6 +751,25 @@ where callee: call_type.callee, ref_time_limit: call_type.ref_time_limit, proof_time_limit, + storage_deposit_limit: call_type.storage_deposit_limit, + transferred_value: call_type.transferred_value, + }), + call_flags: self.call_flags, + exec_input: self.exec_input, + return_type: self.return_type, + _phantom: Default::default(), + } + } + + /// Sets the `storage_deposit_limit` for the current cross-contract call. + pub fn storage_deposit_limit(self, storage_deposit_limit: E::Balance) -> Self { + let call_type = self.call_type.value(); + CallBuilder { + call_type: Set(CallV2 { + callee: call_type.callee, + ref_time_limit: call_type.ref_time_limit, + proof_time_limit: call_type.proof_time_limit, + storage_deposit_limit: Some(storage_deposit_limit), transferred_value: call_type.transferred_value, }), call_flags: self.call_flags, @@ -744,6 +787,7 @@ where callee: call_type.callee, ref_time_limit: call_type.ref_time_limit, proof_time_limit: call_type.proof_time_limit, + storage_deposit_limit: call_type.storage_deposit_limit, transferred_value, }), call_flags: self.call_flags, diff --git a/crates/env/src/engine/on_chain/impls.rs b/crates/env/src/engine/on_chain/impls.rs index 3857a699976..935c01b90a2 100644 --- a/crates/env/src/engine/on_chain/impls.rs +++ b/crates/env/src/engine/on_chain/impls.rs @@ -476,6 +476,9 @@ impl TypedEnvBackend for EnvInstance { let mut scope = self.scoped_buffer(); let ref_time_limit = params.ref_time_limit(); let proof_time_limit = params.proof_time_limit(); + let storage_deposit_limit = params + .storage_deposit_limit() + .map(|limit| &*scope.take_encoded(limit)); let enc_callee = scope.take_encoded(params.callee()); let enc_transferred_value = scope.take_encoded(params.transferred_value()); let call_flags = params.call_flags(); @@ -494,7 +497,7 @@ impl TypedEnvBackend for EnvInstance { enc_callee, ref_time_limit, proof_time_limit, - None, // todo: add storage_deposit_limit to CallParams + storage_deposit_limit, enc_transferred_value, enc_input, Some(output), diff --git a/integration-tests/cross-contract-calls/e2e_tests.rs b/integration-tests/cross-contract-calls/e2e_tests.rs index 47f64785a53..9a8eaf7d7e2 100644 --- a/integration-tests/cross-contract-calls/e2e_tests.rs +++ b/integration-tests/cross-contract-calls/e2e_tests.rs @@ -22,10 +22,14 @@ async fn flip_and_get(mut client: Client) -> E2EResult<()> { const REF_TIME_LIMIT: u64 = 500_000_000; const PROOF_TIME_LIMIT: u64 = 100_000; + const STORAGE_DEPOSIT_LIMIT: u128 = 1_000_000_000; // when - let call = call_builder - .flip_and_get_invoke_v2_with_weight_limit(REF_TIME_LIMIT, PROOF_TIME_LIMIT); + let call = call_builder.flip_and_get_invoke_v2_with_limits( + REF_TIME_LIMIT, + PROOF_TIME_LIMIT, + STORAGE_DEPOSIT_LIMIT, + ); let result = client .call(&ink_e2e::alice(), &call) .submit() diff --git a/integration-tests/cross-contract-calls/lib.rs b/integration-tests/cross-contract-calls/lib.rs index 2d14528caf8..04bacf5d7e7 100755 --- a/integration-tests/cross-contract-calls/lib.rs +++ b/integration-tests/cross-contract-calls/lib.rs @@ -44,16 +44,18 @@ mod cross_contract_calls { /// todo: [AJ] comment #[ink(message)] - pub fn flip_and_get_invoke_v2_with_weight_limit( + pub fn flip_and_get_invoke_v2_with_limits( &mut self, ref_time_limit: u64, proof_time_limit: u64, + storage_deposit_limit: Balance, ) -> bool { self.other_contract_call_builder .flip() .v2() .ref_time_limit(ref_time_limit) .proof_time_limit(proof_time_limit) + .storage_deposit_limit(storage_deposit_limit) .invoke(); self.other_contract_call_builder @@ -61,6 +63,7 @@ mod cross_contract_calls { .v2() .ref_time_limit(ref_time_limit) .proof_time_limit(proof_time_limit) + .storage_deposit_limit(storage_deposit_limit) .invoke() } From 982089df4f2eac5f20d6cd5eb4f289faecf52f0a Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 2 Feb 2024 18:37:57 +0000 Subject: [PATCH 17/47] Clippy --- integration-tests/cross-contract-calls/e2e_tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration-tests/cross-contract-calls/e2e_tests.rs b/integration-tests/cross-contract-calls/e2e_tests.rs index 9a8eaf7d7e2..b9f403ee20c 100644 --- a/integration-tests/cross-contract-calls/e2e_tests.rs +++ b/integration-tests/cross-contract-calls/e2e_tests.rs @@ -37,7 +37,7 @@ async fn flip_and_get(mut client: Client) -> E2EResult<()> { .expect("Calling `flip_and_get` failed") .return_value(); - assert_eq!(result, false); + assert!(!result); let call = call_builder.flip_and_get_invoke_v2_no_weight_limit(); let result = client @@ -47,7 +47,7 @@ async fn flip_and_get(mut client: Client) -> E2EResult<()> { .expect("Calling `flip_and_get` failed") .return_value(); - assert_eq!(result, true); + assert!(result); Ok(()) } From 1d8cd75da329ba69a27a25cf0e40d3bc9a907a53 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 2 Feb 2024 18:38:48 +0000 Subject: [PATCH 18/47] Use struct update syntax --- crates/env/src/call/call_builder.rs | 40 ++++++----------------------- 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/crates/env/src/call/call_builder.rs b/crates/env/src/call/call_builder.rs index 7caa997b1fa..d188f4fb50c 100644 --- a/crates/env/src/call/call_builder.rs +++ b/crates/env/src/call/call_builder.rs @@ -729,16 +729,10 @@ where let call_type = self.call_type.value(); CallBuilder { call_type: Set(CallV2 { - callee: call_type.callee, ref_time_limit, - proof_time_limit: call_type.proof_time_limit, - storage_deposit_limit: call_type.storage_deposit_limit, - transferred_value: call_type.transferred_value, + .. call_type }), - call_flags: self.call_flags, - exec_input: self.exec_input, - return_type: self.return_type, - _phantom: Default::default(), + .. self } } @@ -748,16 +742,10 @@ where let call_type = self.call_type.value(); CallBuilder { call_type: Set(CallV2 { - callee: call_type.callee, - ref_time_limit: call_type.ref_time_limit, proof_time_limit, - storage_deposit_limit: call_type.storage_deposit_limit, - transferred_value: call_type.transferred_value, + .. call_type }), - call_flags: self.call_flags, - exec_input: self.exec_input, - return_type: self.return_type, - _phantom: Default::default(), + .. self } } @@ -766,16 +754,10 @@ where let call_type = self.call_type.value(); CallBuilder { call_type: Set(CallV2 { - callee: call_type.callee, - ref_time_limit: call_type.ref_time_limit, - proof_time_limit: call_type.proof_time_limit, storage_deposit_limit: Some(storage_deposit_limit), - transferred_value: call_type.transferred_value, + .. call_type }), - call_flags: self.call_flags, - exec_input: self.exec_input, - return_type: self.return_type, - _phantom: Default::default(), + .. self } } @@ -784,16 +766,10 @@ where let call_type = self.call_type.value(); CallBuilder { call_type: Set(CallV2 { - callee: call_type.callee, - ref_time_limit: call_type.ref_time_limit, - proof_time_limit: call_type.proof_time_limit, - storage_deposit_limit: call_type.storage_deposit_limit, transferred_value, + .. call_type }), - call_flags: self.call_flags, - exec_input: self.exec_input, - return_type: self.return_type, - _phantom: Default::default(), + .. self } } } From 9393e42d8c677b42a5fbec613773088b837a8f48 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 2 Feb 2024 18:43:59 +0000 Subject: [PATCH 19/47] Remove space --- integration-tests/cross-contract-calls/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/integration-tests/cross-contract-calls/lib.rs b/integration-tests/cross-contract-calls/lib.rs index 04bacf5d7e7..5d241641247 100755 --- a/integration-tests/cross-contract-calls/lib.rs +++ b/integration-tests/cross-contract-calls/lib.rs @@ -70,7 +70,6 @@ mod cross_contract_calls { #[ink(message)] pub fn flip_and_get_invoke_v2_no_weight_limit(&mut self) -> bool { self.other_contract_call_builder.flip().v2().invoke(); - self.other_contract_call_builder.get().v2().invoke() } } From ab62c5bbc30a43ba523bedd9c84039aa15b0d370 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 2 Feb 2024 18:50:27 +0000 Subject: [PATCH 20/47] CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fcecec1f93b..1d446ab32c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [Linter] `non_fallible_api` lint - [#2004](https://github.com/paritytech/ink/pull/2004) - [Linter] Publish the linting crates on crates.io - [#2060](https://github.com/paritytech/ink/pull/2060) - [E2E] Added `create_call_builder` for testing existing contracts - [#2075](https://github.com/paritytech/ink/pull/2075) +- `call_v2` cross-contract calls with additional limit parameters - [#2077](https://github.com/paritytech/ink/pull/2077) ### Changed - `Mapping`: Reflect all possible failure cases in comments ‒ [#2079](https://github.com/paritytech/ink/pull/2079) From 818358ecf92cb9b2aae3270eed5dd6499ff59a22 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 2 Feb 2024 19:04:20 +0000 Subject: [PATCH 21/47] fmt --- crates/env/src/call/call_builder.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/env/src/call/call_builder.rs b/crates/env/src/call/call_builder.rs index d188f4fb50c..129e7c88e1a 100644 --- a/crates/env/src/call/call_builder.rs +++ b/crates/env/src/call/call_builder.rs @@ -730,9 +730,9 @@ where CallBuilder { call_type: Set(CallV2 { ref_time_limit, - .. call_type + ..call_type }), - .. self + ..self } } @@ -743,9 +743,9 @@ where CallBuilder { call_type: Set(CallV2 { proof_time_limit, - .. call_type + ..call_type }), - .. self + ..self } } @@ -755,9 +755,9 @@ where CallBuilder { call_type: Set(CallV2 { storage_deposit_limit: Some(storage_deposit_limit), - .. call_type + ..call_type }), - .. self + ..self } } @@ -767,9 +767,9 @@ where CallBuilder { call_type: Set(CallV2 { transferred_value, - .. call_type + ..call_type }), - .. self + ..self } } } From b648bfcfcbd8ec32eb2497cc8d2fbf4b78d066a0 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 5 Feb 2024 12:20:44 +0000 Subject: [PATCH 22/47] Import OtherContract directly instead of reexporting --- integration-tests/cross-contract-calls/lib.rs | 2 +- integration-tests/cross-contract-calls/other-contract/lib.rs | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/integration-tests/cross-contract-calls/lib.rs b/integration-tests/cross-contract-calls/lib.rs index 5d241641247..51131077974 100755 --- a/integration-tests/cross-contract-calls/lib.rs +++ b/integration-tests/cross-contract-calls/lib.rs @@ -9,7 +9,7 @@ mod cross_contract_calls { ContractEnv, }, }; - use other_contract::{ + use other_contract::other_contract::{ OtherContract, OtherContractRef, }; diff --git a/integration-tests/cross-contract-calls/other-contract/lib.rs b/integration-tests/cross-contract-calls/other-contract/lib.rs index ed280b63812..132ecbec264 100755 --- a/integration-tests/cross-contract-calls/other-contract/lib.rs +++ b/integration-tests/cross-contract-calls/other-contract/lib.rs @@ -1,10 +1,5 @@ #![cfg_attr(not(feature = "std"), no_std, no_main)] -pub use self::other_contract::{ - OtherContract, - OtherContractRef, -}; - #[ink::contract] mod other_contract { From 2c9136435d351be901319d57f57d08279fd38772 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 5 Feb 2024 12:38:13 +0000 Subject: [PATCH 23/47] Make other_contract pub --- integration-tests/cross-contract-calls/other-contract/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/cross-contract-calls/other-contract/lib.rs b/integration-tests/cross-contract-calls/other-contract/lib.rs index 132ecbec264..ccb422bcbc8 100755 --- a/integration-tests/cross-contract-calls/other-contract/lib.rs +++ b/integration-tests/cross-contract-calls/other-contract/lib.rs @@ -1,7 +1,7 @@ #![cfg_attr(not(feature = "std"), no_std, no_main)] #[ink::contract] -mod other_contract { +pub mod other_contract { #[ink(storage)] pub struct OtherContract { From 649bc69e24769eff0569ee5125dceccda8e55cdc Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 5 Feb 2024 13:07:35 +0000 Subject: [PATCH 24/47] Revert prev --- integration-tests/cross-contract-calls/lib.rs | 2 +- .../cross-contract-calls/other-contract/lib.rs | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/integration-tests/cross-contract-calls/lib.rs b/integration-tests/cross-contract-calls/lib.rs index 51131077974..5d241641247 100755 --- a/integration-tests/cross-contract-calls/lib.rs +++ b/integration-tests/cross-contract-calls/lib.rs @@ -9,7 +9,7 @@ mod cross_contract_calls { ContractEnv, }, }; - use other_contract::other_contract::{ + use other_contract::{ OtherContract, OtherContractRef, }; diff --git a/integration-tests/cross-contract-calls/other-contract/lib.rs b/integration-tests/cross-contract-calls/other-contract/lib.rs index ccb422bcbc8..ed280b63812 100755 --- a/integration-tests/cross-contract-calls/other-contract/lib.rs +++ b/integration-tests/cross-contract-calls/other-contract/lib.rs @@ -1,7 +1,12 @@ #![cfg_attr(not(feature = "std"), no_std, no_main)] +pub use self::other_contract::{ + OtherContract, + OtherContractRef, +}; + #[ink::contract] -pub mod other_contract { +mod other_contract { #[ink(storage)] pub struct OtherContract { From 58f5104e9224ce802bc0b795d3ffec1c4e12a009 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 5 Feb 2024 14:48:15 +0000 Subject: [PATCH 25/47] docs --- crates/env/src/call/call_builder.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/env/src/call/call_builder.rs b/crates/env/src/call/call_builder.rs index 129e7c88e1a..c5508d1c8b4 100644 --- a/crates/env/src/call/call_builder.rs +++ b/crates/env/src/call/call_builder.rs @@ -452,7 +452,9 @@ where } } -/// todo: [AJ] docs +/// The new version (V2) of default call type [`Call`] for cross-contract calls. This adds +/// the additional weight limit parameter `proof_time_limit` as well as +/// `storage_deposit_limit`, which are passed to the new host function `call_v2`. #[derive(Clone)] pub struct CallV2 { callee: E::AccountId, From 7c9c85cd1a528c78db16a6d1f6c2bc04b7bda091 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 5 Feb 2024 14:48:37 +0000 Subject: [PATCH 26/47] top level gitignore for integration-tests --- integration-tests/{cross-contract-calls => }/.gitignore | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename integration-tests/{cross-contract-calls => }/.gitignore (100%) diff --git a/integration-tests/cross-contract-calls/.gitignore b/integration-tests/.gitignore similarity index 100% rename from integration-tests/cross-contract-calls/.gitignore rename to integration-tests/.gitignore From e909ecd6eb855f17af302767fac9f63f0aaf283d Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 5 Feb 2024 14:53:49 +0000 Subject: [PATCH 27/47] Remove unused setters --- crates/env/src/call/call_builder.rs | 38 ----------------------------- 1 file changed, 38 deletions(-) diff --git a/crates/env/src/call/call_builder.rs b/crates/env/src/call/call_builder.rs index c5508d1c8b4..aaa05070e16 100644 --- a/crates/env/src/call/call_builder.rs +++ b/crates/env/src/call/call_builder.rs @@ -477,44 +477,6 @@ impl CallV2 { } } -impl CallV2 -where - E: Environment, -{ - /// Sets the `weight_limit` for the current cross-contract call. - pub fn weight_limit(self, ref_time_limit: u64, proof_time_limit: u64) -> Self { - CallV2 { - callee: self.callee, - ref_time_limit, - proof_time_limit, - storage_deposit_limit: self.storage_deposit_limit, - transferred_value: self.transferred_value, - } - } - - /// todo: [AJ] storage_deposit_limit docs - pub fn storage_deposit_limit(self, storage_deposit_limit: E::Balance) -> Self { - CallV2 { - callee: self.callee, - ref_time_limit: self.ref_time_limit, - proof_time_limit: self.proof_time_limit, - storage_deposit_limit: Some(storage_deposit_limit), - transferred_value: self.transferred_value, - } - } - - /// Sets the `transferred_value` for the current cross-contract call. - pub fn transferred_value(self, transferred_value: E::Balance) -> Self { - CallV2 { - callee: self.callee, - ref_time_limit: self.ref_time_limit, - proof_time_limit: self.proof_time_limit, - storage_deposit_limit: self.storage_deposit_limit, - transferred_value, - } - } -} - /// The `delegatecall` call type. Performs a call with the given code hash. #[derive(Clone)] pub struct DelegateCall { From 6e75a0e2530b18548566fba0853333faa66f7b7b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 5 Feb 2024 15:21:41 +0000 Subject: [PATCH 28/47] Use ContractRef --- integration-tests/cross-contract-calls/lib.rs | 39 ++++++------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/integration-tests/cross-contract-calls/lib.rs b/integration-tests/cross-contract-calls/lib.rs index 5d241641247..b9da903517e 100755 --- a/integration-tests/cross-contract-calls/lib.rs +++ b/integration-tests/cross-contract-calls/lib.rs @@ -2,24 +2,12 @@ #[ink::contract] mod cross_contract_calls { - use ink::{ - codegen::ContractCallBuilder, - env::{ - call::FromAccountId, - ContractEnv, - }, - }; - use other_contract::{ - OtherContract, - OtherContractRef, - }; - - type Env = ::Env; - type OtherContractCallBuilder = ::Type; + use ink::codegen::TraitCallBuilder; + use other_contract::OtherContractRef; #[ink(storage)] pub struct CrossContractCalls { - other_contract_call_builder: OtherContractCallBuilder, + other_contract: OtherContractRef, } impl CrossContractCalls { @@ -32,14 +20,7 @@ mod cross_contract_calls { .salt_bytes([0xDE, 0xAD, 0xBE, 0xEF]) .instantiate(); - let other_contract_call_builder = - >::from_account_id( - *other_contract.as_ref(), - ); - - Self { - other_contract_call_builder, - } + Self { other_contract } } /// todo: [AJ] comment @@ -50,7 +31,9 @@ mod cross_contract_calls { proof_time_limit: u64, storage_deposit_limit: Balance, ) -> bool { - self.other_contract_call_builder + let call_builder = self.other_contract.call_mut(); + + call_builder .flip() .v2() .ref_time_limit(ref_time_limit) @@ -58,7 +41,7 @@ mod cross_contract_calls { .storage_deposit_limit(storage_deposit_limit) .invoke(); - self.other_contract_call_builder + call_builder .get() .v2() .ref_time_limit(ref_time_limit) @@ -69,8 +52,10 @@ mod cross_contract_calls { #[ink(message)] pub fn flip_and_get_invoke_v2_no_weight_limit(&mut self) -> bool { - self.other_contract_call_builder.flip().v2().invoke(); - self.other_contract_call_builder.get().v2().invoke() + let call_builder = self.other_contract.call_mut(); + + call_builder.flip().v2().invoke(); + call_builder.get().v2().invoke() } } } From f6e77dc57b20f34659cd645c6f02908ce0d83a35 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 5 Feb 2024 15:28:06 +0000 Subject: [PATCH 29/47] integration-test comments --- integration-tests/cross-contract-calls/lib.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/integration-tests/cross-contract-calls/lib.rs b/integration-tests/cross-contract-calls/lib.rs index b9da903517e..1360fadeca6 100755 --- a/integration-tests/cross-contract-calls/lib.rs +++ b/integration-tests/cross-contract-calls/lib.rs @@ -11,7 +11,8 @@ mod cross_contract_calls { } impl CrossContractCalls { - /// todo: [AJ] comment + /// Initializes the contract by instantiating the code at the given code hash and + /// storing the resulting account id. #[ink(constructor)] pub fn new(other_contract_code_hash: Hash) -> Self { let other_contract = OtherContractRef::new(true) @@ -23,7 +24,12 @@ mod cross_contract_calls { Self { other_contract } } - /// todo: [AJ] comment + /// Use the new `call_v2` host function via the call builder to forward calls to + /// the other contract, initially calling `flip` and then `get` to return the + /// result. + /// + /// This demonstrates how to set the new weight and storage limit parameters via + /// the call builder api. #[ink(message)] pub fn flip_and_get_invoke_v2_with_limits( &mut self, @@ -50,6 +56,8 @@ mod cross_contract_calls { .invoke() } + /// Demonstrate that the `call_v2` succeeds without having specified the weight + /// and storage limit parameters #[ink(message)] pub fn flip_and_get_invoke_v2_no_weight_limit(&mut self) -> bool { let call_builder = self.other_contract.call_mut(); From 7b0b5b1c7b916d6d7816af0e07d2c94deed73d01 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 5 Feb 2024 15:43:42 +0000 Subject: [PATCH 30/47] Rename to `call_v2` --- crates/env/src/call/call_builder.rs | 5 +++-- integration-tests/cross-contract-calls/lib.rs | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/crates/env/src/call/call_builder.rs b/crates/env/src/call/call_builder.rs index aaa05070e16..7cc268fe5a9 100644 --- a/crates/env/src/call/call_builder.rs +++ b/crates/env/src/call/call_builder.rs @@ -632,8 +632,9 @@ impl CallBuilder>, Args, RetType> where E: Environment, { - /// todo: [AJ] docs - pub fn v2(self) -> CallBuilder>, Args, RetType> { + /// Switch to the `call_v2` host function API, which allows configuring + /// `proof_time_limit` and `storage_deposit_limit`. + pub fn call_v2(self) -> CallBuilder>, Args, RetType> { let call_type = self.call_type.value(); CallBuilder { call_type: Set(CallV2 { diff --git a/integration-tests/cross-contract-calls/lib.rs b/integration-tests/cross-contract-calls/lib.rs index 1360fadeca6..f3031164a69 100755 --- a/integration-tests/cross-contract-calls/lib.rs +++ b/integration-tests/cross-contract-calls/lib.rs @@ -41,7 +41,7 @@ mod cross_contract_calls { call_builder .flip() - .v2() + .call_v2() .ref_time_limit(ref_time_limit) .proof_time_limit(proof_time_limit) .storage_deposit_limit(storage_deposit_limit) @@ -49,7 +49,7 @@ mod cross_contract_calls { call_builder .get() - .v2() + .call_v2() .ref_time_limit(ref_time_limit) .proof_time_limit(proof_time_limit) .storage_deposit_limit(storage_deposit_limit) @@ -62,8 +62,8 @@ mod cross_contract_calls { pub fn flip_and_get_invoke_v2_no_weight_limit(&mut self) -> bool { let call_builder = self.other_contract.call_mut(); - call_builder.flip().v2().invoke(); - call_builder.get().v2().invoke() + call_builder.flip().call_v2().invoke(); + call_builder.get().call_v2().invoke() } } } From b176da906e1abde1294affc27ababb4a3dfeed6e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 5 Feb 2024 16:07:50 +0000 Subject: [PATCH 31/47] Comments and builder method --- crates/env/src/api.rs | 19 ++++++++- crates/env/src/call/call_builder.rs | 18 +++++++++ crates/ink/src/env_access.rs | 60 ++++++++++++++++++++++++++++- 3 files changed, 95 insertions(+), 2 deletions(-) diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index b3ae5f22006..4582220a5bd 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -287,7 +287,24 @@ where }) } -/// todo: [AJ] docs +/// Invokes a contract message and returns its result. +/// +/// # Note +/// +/// **This will call into a new version of the host function which allows setting new +/// weight and storage limit parameters.** +/// +/// This is a low level way to evaluate another smart contract. +/// Prefer to use the ink! guided and type safe approach to using this. +/// +/// # Errors +/// +/// - If the called account does not exist. +/// - If the called account is not a contract. +/// - If arguments passed to the called contract message are invalid. +/// - If the called contract execution has trapped. +/// - If the called contract ran out of gas upon execution. +/// - If the returned value failed to decode properly. pub fn invoke_contract_v2( params: &CallParams, Args, R>, ) -> Result> diff --git a/crates/env/src/call/call_builder.rs b/crates/env/src/call/call_builder.rs index 7cc268fe5a9..6d8b5d788b5 100644 --- a/crates/env/src/call/call_builder.rs +++ b/crates/env/src/call/call_builder.rs @@ -613,6 +613,21 @@ where } } + /// Prepares the `CallBuilder` for a cross-contract [`CallV2`] to the new `call_v2` + /// host function. + pub fn call_v2( + self, + callee: E::AccountId, + ) -> CallBuilder>, Args, RetType> { + CallBuilder { + call_type: Set(CallV2::new(callee)), + call_flags: self.call_flags, + exec_input: self.exec_input, + return_type: self.return_type, + _phantom: Default::default(), + } + } + /// Prepares the `CallBuilder` for a cross-contract [`DelegateCall`]. pub fn delegate( self, @@ -634,6 +649,9 @@ where { /// Switch to the `call_v2` host function API, which allows configuring /// `proof_time_limit` and `storage_deposit_limit`. + /// + /// This method instance is used to allow usage of the generated call builder methods + /// for messages which initialize the builder with the original [`Call`] type. pub fn call_v2(self) -> CallBuilder>, Args, RetType> { let call_type = self.call_type.value(); CallBuilder { diff --git a/crates/ink/src/env_access.rs b/crates/ink/src/env_access.rs index de72cd5a448..1ae1c531564 100644 --- a/crates/ink/src/env_access.rs +++ b/crates/ink/src/env_access.rs @@ -579,7 +579,65 @@ where ink_env::invoke_contract::(params) } - /// todo: [AJ] docs + /// Invokes a contract message and returns its result. + /// + /// # Example + /// + /// ``` + /// # #[ink::contract] + /// # pub mod my_contract { + /// use ink::env::{ + /// call::{ + /// build_call, + /// Call, + /// ExecutionInput, + /// Selector, + /// }, + /// DefaultEnvironment, + /// }; + /// + /// # + /// # #[ink(storage)] + /// # pub struct MyContract { } + /// # + /// # impl MyContract { + /// # #[ink(constructor)] + /// # pub fn new() -> Self { + /// # Self {} + /// # } + /// # + /// /// Invokes a contract message and fetches the result. + /// #[ink(message)] + /// pub fn invoke_contract(&self) -> i32 { + /// let call_params = build_call::() + /// .call_v2() + /// .ref_time_limit(500_000_000) + /// .proof_time_limit(100_000) + /// .storage_deposit_limit(1_000_000_000) + /// .exec_input( + /// ExecutionInput::new(Selector::new([0xCA, 0xFE, 0xBA, 0xBE])) + /// .push_arg(42u8) + /// .push_arg(true) + /// .push_arg(&[0x10u8; 32]), + /// ) + /// .returns::() + /// .params(); + /// + /// self.env() + /// .invoke_contract(&call_params) + /// .unwrap_or_else(|env_err| { + /// panic!("Received an error from the Environment: {:?}", env_err) + /// }) + /// .unwrap_or_else(|lang_err| panic!("Received a `LangError`: {:?}", lang_err)) + /// } + /// # + /// # } + /// # } + /// ``` + /// + /// # Note + /// + /// For more details visit: [`ink_env::invoke_contract_v2`] pub fn invoke_contract_v2( self, params: &CallParams, Args, R>, From a3dd520a7a39cc927f7fd7449e0c6b711feb87bd Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 5 Feb 2024 16:15:25 +0000 Subject: [PATCH 32/47] SP --- integration-tests/cross-contract-calls/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/cross-contract-calls/lib.rs b/integration-tests/cross-contract-calls/lib.rs index f3031164a69..c2b3fb84456 100755 --- a/integration-tests/cross-contract-calls/lib.rs +++ b/integration-tests/cross-contract-calls/lib.rs @@ -29,7 +29,7 @@ mod cross_contract_calls { /// result. /// /// This demonstrates how to set the new weight and storage limit parameters via - /// the call builder api. + /// the call builder API. #[ink(message)] pub fn flip_and_get_invoke_v2_with_limits( &mut self, From 1d400adfacfcf827da5e1b990c0b33b10749bb0d Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 5 Feb 2024 16:16:48 +0000 Subject: [PATCH 33/47] comments --- crates/env/src/backend.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index 7f9a5338904..8a83d1c5bcf 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -305,6 +305,13 @@ pub trait TypedEnvBackend: EnvBackend { Args: scale::Encode, R: scale::Decode; + /// Invokes a contract message and returns its result. + /// + /// # Note + /// + /// **This will call into the new `call_v2` host function.** + /// + /// For more details visit: [`invoke_contract`][`crate::invoke_contract_v2`] fn invoke_contract_v2( &mut self, call_data: &CallParams, Args, R>, From dab7ab05af1c0d3372b19923cd0789dcbf4e008d Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 6 Feb 2024 09:37:57 +0000 Subject: [PATCH 34/47] fix doc test --- crates/ink/src/env_access.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/ink/src/env_access.rs b/crates/ink/src/env_access.rs index 1ae1c531564..19a4027d3ba 100644 --- a/crates/ink/src/env_access.rs +++ b/crates/ink/src/env_access.rs @@ -608,9 +608,9 @@ where /// # /// /// Invokes a contract message and fetches the result. /// #[ink(message)] - /// pub fn invoke_contract(&self) -> i32 { + /// pub fn invoke_contract_v2(&self) -> i32 { /// let call_params = build_call::() - /// .call_v2() + /// .call_v2(AccountId::from([0x42; 32])) /// .ref_time_limit(500_000_000) /// .proof_time_limit(100_000) /// .storage_deposit_limit(1_000_000_000) @@ -624,7 +624,7 @@ where /// .params(); /// /// self.env() - /// .invoke_contract(&call_params) + /// .invoke_contract_v2(&call_params) /// .unwrap_or_else(|env_err| { /// panic!("Received an error from the Environment: {:?}", env_err) /// }) From d29152cccf0c3d0f9d24b90aab1c517927ab6605 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 6 Feb 2024 09:54:21 +0000 Subject: [PATCH 35/47] merge `basic-contract-caller` into `cross-contract-calls` --- .../basic-contract-caller/.gitignore | 9 ---- .../basic-contract-caller/Cargo.toml | 32 -------------- .../basic-contract-caller/e2e_tests.rs | 35 --------------- .../basic-contract-caller/lib.rs | 44 ------------------- .../other-contract/.gitignore | 9 ---- .../other-contract/Cargo.toml | 23 ---------- .../other-contract/lib.rs | 33 -------------- .../cross-contract-calls/e2e_tests.rs | 31 +++++++++++++ integration-tests/cross-contract-calls/lib.rs | 9 ++++ 9 files changed, 40 insertions(+), 185 deletions(-) delete mode 100755 integration-tests/basic-contract-caller/.gitignore delete mode 100755 integration-tests/basic-contract-caller/Cargo.toml delete mode 100644 integration-tests/basic-contract-caller/e2e_tests.rs delete mode 100755 integration-tests/basic-contract-caller/lib.rs delete mode 100755 integration-tests/basic-contract-caller/other-contract/.gitignore delete mode 100755 integration-tests/basic-contract-caller/other-contract/Cargo.toml delete mode 100755 integration-tests/basic-contract-caller/other-contract/lib.rs diff --git a/integration-tests/basic-contract-caller/.gitignore b/integration-tests/basic-contract-caller/.gitignore deleted file mode 100755 index 8de8f877e47..00000000000 --- a/integration-tests/basic-contract-caller/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -# 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 diff --git a/integration-tests/basic-contract-caller/Cargo.toml b/integration-tests/basic-contract-caller/Cargo.toml deleted file mode 100755 index 0781400a2f4..00000000000 --- a/integration-tests/basic-contract-caller/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -[package] -name = "basic-contract-caller" -version = "5.0.0-rc" -authors = ["Parity Technologies "] -edition = "2021" -publish = false - -[dependencies] -ink = { path = "../../crates/ink", default-features = false } - -# Note: We **need** to specify the `ink-as-dependency` feature. -# -# If we don't we will end up with linking errors! -other-contract = { path = "other-contract", default-features = false, features = ["ink-as-dependency"] } - -[dev-dependencies] -ink_e2e = { path = "../../crates/e2e" } - -[lib] -path = "lib.rs" - -[features] -default = ["std"] -std = [ - "ink/std", - - # Note: The metadata generation step requires `std`. If we don't specify this the metadata - # generation for our contract will fail! - "other-contract/std", -] -ink-as-dependency = [] -e2e-tests = [] diff --git a/integration-tests/basic-contract-caller/e2e_tests.rs b/integration-tests/basic-contract-caller/e2e_tests.rs deleted file mode 100644 index e9ce86d4bc1..00000000000 --- a/integration-tests/basic-contract-caller/e2e_tests.rs +++ /dev/null @@ -1,35 +0,0 @@ -use super::basic_contract_caller::*; -use ink_e2e::ContractsBackend; - -type E2EResult = std::result::Result>; - -#[ink_e2e::test] -async fn flip_and_get(mut client: Client) -> E2EResult<()> { - // given - let other_contract_code = client - .upload("other-contract", &ink_e2e::alice()) - .submit() - .await - .expect("other_contract upload failed"); - - let mut constructor = BasicContractCallerRef::new(other_contract_code.code_hash); - let contract = client - .instantiate("basic-contract-caller", &ink_e2e::alice(), &mut constructor) - .submit() - .await - .expect("basic-contract-caller instantiate failed"); - let mut call_builder = contract.call_builder::(); - let call = call_builder.flip_and_get(); - - // when - let result = client - .call(&ink_e2e::alice(), &call) - .submit() - .await - .expect("Calling `flip_and_get` failed") - .return_value(); - - assert_eq!(result, false); - - Ok(()) -} diff --git a/integration-tests/basic-contract-caller/lib.rs b/integration-tests/basic-contract-caller/lib.rs deleted file mode 100755 index 78c999d7c26..00000000000 --- a/integration-tests/basic-contract-caller/lib.rs +++ /dev/null @@ -1,44 +0,0 @@ -#![cfg_attr(not(feature = "std"), no_std, no_main)] - -#[ink::contract] -mod basic_contract_caller { - /// We import the generated `ContractRef` of our other contract. - /// - /// Note that the other contract must have re-exported it (`pub use - /// OtherContractRef`) for us to have access to it. - use other_contract::OtherContractRef; - - #[ink(storage)] - pub struct BasicContractCaller { - /// We specify that our contract will store a reference to the `OtherContract`. - other_contract: OtherContractRef, - } - - impl BasicContractCaller { - /// In order to use the `OtherContract` we first need to **instantiate** it. - /// - /// To do this we will use the uploaded `code_hash` of `OtherContract`. - #[ink(constructor)] - pub fn new(other_contract_code_hash: Hash) -> Self { - let other_contract = OtherContractRef::new(true) - .code_hash(other_contract_code_hash) - .endowment(0) - .salt_bytes([0xDE, 0xAD, 0xBE, 0xEF]) - .instantiate(); - - Self { other_contract } - } - - /// Using the `ContractRef` we can call all the messages of the `OtherContract` as - /// if they were normal Rust methods (because at the end of the day, they - /// are!). - #[ink(message)] - pub fn flip_and_get(&mut self) -> bool { - self.other_contract.flip(); - self.other_contract.get() - } - } -} - -#[cfg(all(test, feature = "e2e-tests"))] -mod e2e_tests; diff --git a/integration-tests/basic-contract-caller/other-contract/.gitignore b/integration-tests/basic-contract-caller/other-contract/.gitignore deleted file mode 100755 index 8de8f877e47..00000000000 --- a/integration-tests/basic-contract-caller/other-contract/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -# 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 diff --git a/integration-tests/basic-contract-caller/other-contract/Cargo.toml b/integration-tests/basic-contract-caller/other-contract/Cargo.toml deleted file mode 100755 index c0b4748e22b..00000000000 --- a/integration-tests/basic-contract-caller/other-contract/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "other-contract" -version = "5.0.0-rc" -authors = ["Parity Technologies "] -edition = "2021" -publish = false - -[dependencies] -ink = { path = "../../../crates/ink", default-features = false } - -[dev-dependencies] -ink_e2e = { path = "../../../crates/e2e" } - -[lib] -path = "lib.rs" - -[features] -default = ["std"] -std = [ - "ink/std", -] -ink-as-dependency = [] -e2e-tests = [] diff --git a/integration-tests/basic-contract-caller/other-contract/lib.rs b/integration-tests/basic-contract-caller/other-contract/lib.rs deleted file mode 100755 index 53e51019476..00000000000 --- a/integration-tests/basic-contract-caller/other-contract/lib.rs +++ /dev/null @@ -1,33 +0,0 @@ -#![cfg_attr(not(feature = "std"), no_std, no_main)] - -/// Re-export the `ContractRef` generated by the ink! codegen. -/// -/// This let's other crates which pull this contract in as a dependency to interact -/// with this contract in a type-safe way. -pub use self::other_contract::OtherContractRef; - -#[ink::contract] -mod other_contract { - - #[ink(storage)] - pub struct OtherContract { - value: bool, - } - - impl OtherContract { - #[ink(constructor)] - pub fn new(init_value: bool) -> Self { - Self { value: init_value } - } - - #[ink(message)] - pub fn flip(&mut self) { - self.value = !self.value; - } - - #[ink(message)] - pub fn get(&self) -> bool { - self.value - } - } -} diff --git a/integration-tests/cross-contract-calls/e2e_tests.rs b/integration-tests/cross-contract-calls/e2e_tests.rs index b9f403ee20c..c72b81c1864 100644 --- a/integration-tests/cross-contract-calls/e2e_tests.rs +++ b/integration-tests/cross-contract-calls/e2e_tests.rs @@ -12,6 +12,37 @@ async fn flip_and_get(mut client: Client) -> E2EResult<()> { .await .expect("other_contract upload failed"); + let mut constructor = CrossContractCallsRef::new(other_contract_code.code_hash); + let contract = client + .instantiate("cross-contract-calls", &ink_e2e::alice(), &mut constructor) + .submit() + .await + .expect("basic-contract-caller instantiate failed"); + let mut call_builder = contract.call_builder::(); + let call = call_builder.flip_and_get(); + + // when + let result = client + .call(&ink_e2e::alice(), &call) + .submit() + .await + .expect("Calling `flip_and_get` failed") + .return_value(); + + assert_eq!(result, false); + + Ok(()) +} + +#[ink_e2e::test] +async fn flip_and_get_v2(mut client: Client) -> E2EResult<()> { + // given + let other_contract_code = client + .upload("other-contract", &ink_e2e::alice()) + .submit() + .await + .expect("other_contract upload failed"); + let mut constructor = CrossContractCallsRef::new(other_contract_code.code_hash); let contract = client .instantiate("cross-contract-calls", &ink_e2e::alice(), &mut constructor) diff --git a/integration-tests/cross-contract-calls/lib.rs b/integration-tests/cross-contract-calls/lib.rs index c2b3fb84456..73ca6e442a7 100755 --- a/integration-tests/cross-contract-calls/lib.rs +++ b/integration-tests/cross-contract-calls/lib.rs @@ -24,6 +24,15 @@ mod cross_contract_calls { Self { other_contract } } + /// Basic invocation of the other contract via the contract reference. + /// + /// *Note* this will invoke the original `call` (V1) host function. + #[ink(message)] + pub fn flip_and_get(&mut self) -> bool { + self.other_contract.flip(); + self.other_contract.get() + } + /// Use the new `call_v2` host function via the call builder to forward calls to /// the other contract, initially calling `flip` and then `get` to return the /// result. From fab7a540b9f896b29249de80654ccb6a5b7a9c3b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 6 Feb 2024 14:53:08 +0000 Subject: [PATCH 36/47] Make `call_v2` the default for cross contract calls --- crates/env/src/api.rs | 6 +- crates/env/src/backend.rs | 6 +- crates/env/src/call/call_builder.rs | 159 +++++++++--------- crates/env/src/call/mod.rs | 2 +- crates/env/src/engine/off_chain/impls.rs | 6 +- crates/env/src/engine/on_chain/impls.rs | 6 +- crates/ink/src/env_access.rs | 14 +- .../cross-contract-calls/e2e_tests.rs | 2 +- integration-tests/cross-contract-calls/lib.rs | 19 +-- 9 files changed, 110 insertions(+), 110 deletions(-) diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index 4582220a5bd..53edd4ca6dc 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -22,7 +22,7 @@ use crate::{ call::{ Call, CallParams, - CallV2, + CallV1, ConstructorReturnType, CreateParams, DelegateCall, @@ -275,7 +275,7 @@ where /// - If the called contract ran out of gas upon execution. /// - If the returned value failed to decode properly. pub fn invoke_contract( - params: &CallParams, Args, R>, + params: &CallParams, Args, R>, ) -> Result> where E: Environment, @@ -306,7 +306,7 @@ where /// - If the called contract ran out of gas upon execution. /// - If the returned value failed to decode properly. pub fn invoke_contract_v2( - params: &CallParams, Args, R>, + params: &CallParams, Args, R>, ) -> Result> where E: Environment, diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index 8a83d1c5bcf..7d49f50348a 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -16,7 +16,7 @@ use crate::{ call::{ Call, CallParams, - CallV2, + CallV1, ConstructorReturnType, CreateParams, DelegateCall, @@ -298,7 +298,7 @@ pub trait TypedEnvBackend: EnvBackend { /// For more details visit: [`invoke_contract`][`crate::invoke_contract`] fn invoke_contract( &mut self, - call_data: &CallParams, Args, R>, + call_data: &CallParams, Args, R>, ) -> Result> where E: Environment, @@ -314,7 +314,7 @@ pub trait TypedEnvBackend: EnvBackend { /// For more details visit: [`invoke_contract`][`crate::invoke_contract_v2`] fn invoke_contract_v2( &mut self, - call_data: &CallParams, Args, R>, + call_data: &CallParams, Args, R>, ) -> Result> where E: Environment, diff --git a/crates/env/src/call/call_builder.rs b/crates/env/src/call/call_builder.rs index 6d8b5d788b5..12c8d5b4829 100644 --- a/crates/env/src/call/call_builder.rs +++ b/crates/env/src/call/call_builder.rs @@ -65,7 +65,7 @@ where } } -impl CallParams, Args, R> +impl CallParams, Args, R> where E: Environment, { @@ -88,7 +88,7 @@ where } } -impl CallParams, Args, R> +impl CallParams, Args, R> where E: Environment, { @@ -134,7 +134,7 @@ where } } -impl CallParams, Args, R> +impl CallParams, Args, R> where E: Environment, Args: scale::Encode, @@ -173,7 +173,7 @@ where } } -impl CallParams, Args, R> +impl CallParams, Args, R> where E: Environment, Args: scale::Encode, @@ -278,11 +278,11 @@ where /// # DefaultEnvironment, /// # call::{build_call, Selector, ExecutionInput} /// # }; -/// # use ink_env::call::Call; +/// # use ink_env::call::CallV1; /// # type AccountId = ::AccountId; /// # type Balance = ::Balance; /// build_call::() -/// .call(AccountId::from([0x42; 32])) +/// .call_v1(AccountId::from([0x42; 32])) /// .gas_limit(5000) /// .transferred_value(10) /// .exec_input( @@ -310,11 +310,11 @@ where /// # use ::ink_env::{ /// # Environment, /// # DefaultEnvironment, -/// # call::{build_call, Selector, ExecutionInput, Call}, +/// # call::{build_call, Selector, ExecutionInput, CallV1}, /// # }; /// # type AccountId = ::AccountId; /// let my_return_value: i32 = build_call::() -/// .call_type(Call::new(AccountId::from([0x42; 32]))) +/// .call_type(CallV1::new(AccountId::from([0x42; 32]))) /// .gas_limit(5000) /// .transferred_value(10) /// .exec_input( @@ -374,11 +374,11 @@ where /// # DefaultEnvironment, /// # call::{build_call, Selector, ExecutionInput} /// # }; -/// # use ink_env::call::Call; +/// # use ink_env::call::CallV1; /// # type AccountId = ::AccountId; /// # type Balance = ::Balance; /// let call_result = build_call::() -/// .call(AccountId::from([0x42; 32])) +/// .call_v1(AccountId::from([0x42; 32])) /// .gas_limit(5000) /// .transferred_value(10) /// .try_invoke() @@ -393,7 +393,7 @@ where #[allow(clippy::type_complexity)] pub fn build_call() -> CallBuilder< E, - Unset>, + Unset>, Unset>, Unset>, > @@ -409,17 +409,19 @@ where } } -/// The default call type for cross-contract calls. Performs a cross-contract call to +/// The legacy call type for cross-contract calls. Performs a cross-contract call to /// `callee` with gas limit `gas_limit`, transferring `transferred_value` of currency. +/// +/// Calls into the original `call` host function. #[derive(Clone)] -pub struct Call { +pub struct CallV1 { callee: E::AccountId, gas_limit: Gas, transferred_value: E::Balance, } -impl Call { - /// Returns a clean builder for [`Call`]. +impl CallV1 { + /// Returns a clean builder for [`CallV1`]. pub fn new(callee: E::AccountId) -> Self { Self { callee, @@ -429,13 +431,13 @@ impl Call { } } -impl Call +impl CallV1 where E: Environment, { /// Sets the `gas_limit` for the current cross-contract call. pub fn gas_limit(self, gas_limit: Gas) -> Self { - Call { + CallV1 { callee: self.callee, gas_limit, transferred_value: self.transferred_value, @@ -444,7 +446,7 @@ where /// Sets the `transferred_value` for the current cross-contract call. pub fn transferred_value(self, transferred_value: E::Balance) -> Self { - Call { + CallV1 { callee: self.callee, gas_limit: self.gas_limit, transferred_value, @@ -452,11 +454,11 @@ where } } -/// The new version (V2) of default call type [`Call`] for cross-contract calls. This adds -/// the additional weight limit parameter `proof_time_limit` as well as -/// `storage_deposit_limit`, which are passed to the new host function `call_v2`. +/// The default call type for cross-contract calls, for calling into the latest `call_v2` +/// host function. This adds the additional weight limit parameter `proof_time_limit` as +/// well as `storage_deposit_limit`. #[derive(Clone)] -pub struct CallV2 { +pub struct Call { callee: E::AccountId, ref_time_limit: u64, proof_time_limit: u64, @@ -464,8 +466,8 @@ pub struct CallV2 { transferred_value: E::Balance, } -impl CallV2 { - /// Returns a clean builder for [`Call`]. +impl Call { + /// Returns a clean builder for [`CallV1`]. pub fn new(callee: E::AccountId) -> Self { Self { callee, @@ -599,13 +601,14 @@ impl CallBuilder, Args, RetType> where E: Environment, { - /// Prepares the `CallBuilder` for a cross-contract [`Call`]. - pub fn call( + /// Prepares the `CallBuilder` for a cross-contract [`CallV1`], calling into the + /// original `call` host function. + pub fn call_v1( self, callee: E::AccountId, - ) -> CallBuilder>, Args, RetType> { + ) -> CallBuilder>, Args, RetType> { CallBuilder { - call_type: Set(Call::new(callee)), + call_type: Set(CallV1::new(callee)), call_flags: self.call_flags, exec_input: self.exec_input, return_type: self.return_type, @@ -613,14 +616,14 @@ where } } - /// Prepares the `CallBuilder` for a cross-contract [`CallV2`] to the new `call_v2` + /// Prepares the `CallBuilder` for a cross-contract [`Call`] to the latest `call_v2` /// host function. - pub fn call_v2( + pub fn call( self, callee: E::AccountId, - ) -> CallBuilder>, Args, RetType> { + ) -> CallBuilder>, Args, RetType> { CallBuilder { - call_type: Set(CallV2::new(callee)), + call_type: Set(Call::new(callee)), call_flags: self.call_flags, exec_input: self.exec_input, return_type: self.return_type, @@ -643,37 +646,15 @@ where } } -impl CallBuilder>, Args, RetType> +impl CallBuilder>, Args, RetType> where E: Environment, { - /// Switch to the `call_v2` host function API, which allows configuring - /// `proof_time_limit` and `storage_deposit_limit`. - /// - /// This method instance is used to allow usage of the generated call builder methods - /// for messages which initialize the builder with the original [`Call`] type. - pub fn call_v2(self) -> CallBuilder>, Args, RetType> { - let call_type = self.call_type.value(); - CallBuilder { - call_type: Set(CallV2 { - callee: call_type.callee, - ref_time_limit: call_type.gas_limit, - proof_time_limit: Default::default(), - storage_deposit_limit: None, - transferred_value: call_type.transferred_value, - }), - call_flags: self.call_flags, - exec_input: self.exec_input, - return_type: self.return_type, - _phantom: Default::default(), - } - } - /// Sets the `gas_limit` for the current cross-contract call. pub fn gas_limit(self, gas_limit: Gas) -> Self { let call_type = self.call_type.value(); CallBuilder { - call_type: Set(Call { + call_type: Set(CallV1 { callee: call_type.callee, gas_limit, transferred_value: call_type.transferred_value, @@ -689,7 +670,7 @@ where pub fn transferred_value(self, transferred_value: E::Balance) -> Self { let call_type = self.call_type.value(); CallBuilder { - call_type: Set(Call { + call_type: Set(CallV1 { callee: call_type.callee, gas_limit: call_type.gas_limit, transferred_value, @@ -702,16 +683,36 @@ where } } -impl CallBuilder>, Args, RetType> +impl CallBuilder>, Args, RetType> where E: Environment, { + /// Switch to the original `call` host function API, which only allows the `gas_limit` + /// limit parameter (equivalent to the `ref_time_limit` in the latest `call_v2`). + /// + /// This method instance is used to allow usage of the generated call builder methods + /// for messages which initialize the builder with the original [`CallV1`] type. + pub fn call_v1(self) -> CallBuilder>, Args, RetType> { + let call_type = self.call_type.value(); + CallBuilder { + call_type: Set(CallV1 { + callee: call_type.callee, + gas_limit: call_type.ref_time_limit, + transferred_value: call_type.transferred_value, + }), + call_flags: self.call_flags, + exec_input: self.exec_input, + return_type: self.return_type, + _phantom: Default::default(), + } + } + /// Sets the `ref_time_limit` part of the weight limit for the current cross-contract /// call. pub fn ref_time_limit(self, ref_time_limit: Gas) -> Self { let call_type = self.call_type.value(); CallBuilder { - call_type: Set(CallV2 { + call_type: Set(Call { ref_time_limit, ..call_type }), @@ -724,7 +725,7 @@ where pub fn proof_time_limit(self, proof_time_limit: Gas) -> Self { let call_type = self.call_type.value(); CallBuilder { - call_type: Set(CallV2 { + call_type: Set(Call { proof_time_limit, ..call_type }), @@ -736,7 +737,7 @@ where pub fn storage_deposit_limit(self, storage_deposit_limit: E::Balance) -> Self { let call_type = self.call_type.value(); CallBuilder { - call_type: Set(CallV2 { + call_type: Set(Call { storage_deposit_limit: Some(storage_deposit_limit), ..call_type }), @@ -748,7 +749,7 @@ where pub fn transferred_value(self, transferred_value: E::Balance) -> Self { let call_type = self.call_type.value(); CallBuilder { - call_type: Set(CallV2 { + call_type: Set(Call { transferred_value, ..call_type }), @@ -774,12 +775,12 @@ where } impl - CallBuilder>, Set>, Set>> + CallBuilder>, Set>, Set>> where E: Environment, { /// Finalizes the call builder to call a function. - pub fn params(self) -> CallParams, Args, RetType> { + pub fn params(self) -> CallParams, Args, RetType> { CallParams { call_type: self.call_type.value(), call_flags: self.call_flags, @@ -791,12 +792,12 @@ where } impl - CallBuilder>, Set>, Set>> + CallBuilder>, Set>, Set>> where E: Environment, { /// Finalizes the call builder to call a function. - pub fn params(self) -> CallParams, Args, RetType> { + pub fn params(self) -> CallParams, Args, RetType> { CallParams { call_type: self.call_type.value(), call_flags: self.call_flags, @@ -830,12 +831,17 @@ where } impl - CallBuilder>, Unset>, Unset> + CallBuilder< + E, + Set>, + Unset>, + Unset, + > where E: Environment, { /// Finalizes the call builder to call a function. - pub fn params(self) -> CallParams, EmptyArgumentList, ()> { + pub fn params(self) -> CallParams, EmptyArgumentList, ()> { CallParams { call_type: self.call_type.value(), call_flags: self.call_flags, @@ -847,17 +853,12 @@ where } impl - CallBuilder< - E, - Set>, - Unset>, - Unset, - > + CallBuilder>, Unset>, Unset> where E: Environment, { /// Finalizes the call builder to call a function. - pub fn params(self) -> CallParams, EmptyArgumentList, ()> { + pub fn params(self) -> CallParams, EmptyArgumentList, ()> { CallParams { call_type: self.call_type.value(), call_flags: self.call_flags, @@ -893,7 +894,7 @@ where impl CallBuilder< E, - Set>, + Set>, Unset>, Unset>, > @@ -926,7 +927,7 @@ where impl CallBuilder< E, - Set>, + Set>, Unset>, Unset>, > @@ -989,7 +990,7 @@ where } impl - CallBuilder>, Set>, Set>> + CallBuilder>, Set>, Set>> where E: Environment, Args: scale::Encode, @@ -1019,7 +1020,7 @@ where } impl - CallBuilder>, Set>, Set>> + CallBuilder>, Set>, Set>> where E: Environment, Args: scale::Encode, diff --git a/crates/env/src/call/mod.rs b/crates/env/src/call/mod.rs index 463b96ce5f5..a3f97ec5de5 100644 --- a/crates/env/src/call/mod.rs +++ b/crates/env/src/call/mod.rs @@ -45,7 +45,7 @@ pub use self::{ Call, CallBuilder, CallParams, - CallV2, + CallV1, DelegateCall, }, create_builder::{ diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index d5dc7cad504..da52a42dea8 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -17,7 +17,7 @@ use crate::{ call::{ Call, CallParams, - CallV2, + CallV1, ConstructorReturnType, CreateParams, DelegateCall, @@ -439,7 +439,7 @@ impl TypedEnvBackend for EnvInstance { fn invoke_contract( &mut self, - _params: &CallParams, Args, R>, + _params: &CallParams, Args, R>, ) -> Result> where E: Environment, @@ -451,7 +451,7 @@ impl TypedEnvBackend for EnvInstance { fn invoke_contract_v2( &mut self, - _params: &CallParams, Args, R>, + _params: &CallParams, Args, R>, ) -> Result> where E: Environment, diff --git a/crates/env/src/engine/on_chain/impls.rs b/crates/env/src/engine/on_chain/impls.rs index 935c01b90a2..6dd18a8034b 100644 --- a/crates/env/src/engine/on_chain/impls.rs +++ b/crates/env/src/engine/on_chain/impls.rs @@ -20,7 +20,7 @@ use crate::{ call::{ Call, CallParams, - CallV2, + CallV1, ConstructorReturnType, CreateParams, DelegateCall, @@ -426,7 +426,7 @@ impl TypedEnvBackend for EnvInstance { fn invoke_contract( &mut self, - params: &CallParams, Args, R>, + params: &CallParams, Args, R>, ) -> Result> where E: Environment, @@ -466,7 +466,7 @@ impl TypedEnvBackend for EnvInstance { fn invoke_contract_v2( &mut self, - params: &CallParams, Args, R>, + params: &CallParams, Args, R>, ) -> Result> where E: Environment, diff --git a/crates/ink/src/env_access.rs b/crates/ink/src/env_access.rs index 19a4027d3ba..6f84ab8002e 100644 --- a/crates/ink/src/env_access.rs +++ b/crates/ink/src/env_access.rs @@ -18,7 +18,7 @@ use ink_env::{ call::{ Call, CallParams, - CallV2, + CallV1, ConstructorReturnType, CreateParams, DelegateCall, @@ -518,7 +518,7 @@ where /// use ink::env::{ /// call::{ /// build_call, - /// Call, + /// CallV1, /// ExecutionInput, /// Selector, /// }, @@ -540,7 +540,7 @@ where /// pub fn invoke_contract(&self) -> i32 { /// let call_params = build_call::() /// .call_type( - /// Call::new(AccountId::from([0x42; 32])) + /// CallV1::new(AccountId::from([0x42; 32])) /// .gas_limit(5000) /// .transferred_value(10), /// ) @@ -570,7 +570,7 @@ where /// For more details visit: [`ink_env::invoke_contract`] pub fn invoke_contract( self, - params: &CallParams, Args, R>, + params: &CallParams, Args, R>, ) -> Result> where Args: scale::Encode, @@ -589,7 +589,7 @@ where /// use ink::env::{ /// call::{ /// build_call, - /// Call, + /// CallV1, /// ExecutionInput, /// Selector, /// }, @@ -610,7 +610,7 @@ where /// #[ink(message)] /// pub fn invoke_contract_v2(&self) -> i32 { /// let call_params = build_call::() - /// .call_v2(AccountId::from([0x42; 32])) + /// .call(AccountId::from([0x42; 32])) /// .ref_time_limit(500_000_000) /// .proof_time_limit(100_000) /// .storage_deposit_limit(1_000_000_000) @@ -640,7 +640,7 @@ where /// For more details visit: [`ink_env::invoke_contract_v2`] pub fn invoke_contract_v2( self, - params: &CallParams, Args, R>, + params: &CallParams, Args, R>, ) -> Result> where Args: scale::Encode, diff --git a/integration-tests/cross-contract-calls/e2e_tests.rs b/integration-tests/cross-contract-calls/e2e_tests.rs index c72b81c1864..d26301dc694 100644 --- a/integration-tests/cross-contract-calls/e2e_tests.rs +++ b/integration-tests/cross-contract-calls/e2e_tests.rs @@ -19,7 +19,7 @@ async fn flip_and_get(mut client: Client) -> E2EResult<()> { .await .expect("basic-contract-caller instantiate failed"); let mut call_builder = contract.call_builder::(); - let call = call_builder.flip_and_get(); + let call = call_builder.flip_and_get_v1(); // when let result = client diff --git a/integration-tests/cross-contract-calls/lib.rs b/integration-tests/cross-contract-calls/lib.rs index 73ca6e442a7..3cd90fc1371 100755 --- a/integration-tests/cross-contract-calls/lib.rs +++ b/integration-tests/cross-contract-calls/lib.rs @@ -26,11 +26,14 @@ mod cross_contract_calls { /// Basic invocation of the other contract via the contract reference. /// - /// *Note* this will invoke the original `call` (V1) host function. + /// *Note* this will invoke the original `call` (V1) host function, which will be + /// deprecated in the future. #[ink(message)] - pub fn flip_and_get(&mut self) -> bool { - self.other_contract.flip(); - self.other_contract.get() + pub fn flip_and_get_v1(&mut self) -> bool { + let call_builder = self.other_contract.call_mut(); + + call_builder.flip().call_v1().invoke(); + call_builder.get().call_v1().invoke() } /// Use the new `call_v2` host function via the call builder to forward calls to @@ -50,7 +53,6 @@ mod cross_contract_calls { call_builder .flip() - .call_v2() .ref_time_limit(ref_time_limit) .proof_time_limit(proof_time_limit) .storage_deposit_limit(storage_deposit_limit) @@ -58,7 +60,6 @@ mod cross_contract_calls { call_builder .get() - .call_v2() .ref_time_limit(ref_time_limit) .proof_time_limit(proof_time_limit) .storage_deposit_limit(storage_deposit_limit) @@ -69,10 +70,8 @@ mod cross_contract_calls { /// and storage limit parameters #[ink(message)] pub fn flip_and_get_invoke_v2_no_weight_limit(&mut self) -> bool { - let call_builder = self.other_contract.call_mut(); - - call_builder.flip().call_v2().invoke(); - call_builder.get().call_v2().invoke() + self.other_contract.flip(); + self.other_contract.get() } } } From 2fdb9ab965ecdfd6ab7017e27df0c2312b7de536 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 6 Feb 2024 15:03:21 +0000 Subject: [PATCH 37/47] Complete switch to make `call_v2` default --- crates/env/src/api.rs | 13 ++++++++----- crates/env/src/backend.rs | 12 +++++++----- crates/env/src/call/call_builder.rs | 8 ++++---- crates/env/src/engine/off_chain/impls.rs | 4 ++-- crates/env/src/engine/on_chain/impls.rs | 4 ++-- crates/ink/src/env_access.rs | 8 ++++---- 6 files changed, 27 insertions(+), 22 deletions(-) diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index 53edd4ca6dc..a8315598656 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -266,6 +266,9 @@ where /// This is a low level way to evaluate another smart contract. /// Prefer to use the ink! guided and type safe approach to using this. /// +/// **This will call into the original version of the host function. It is recommended to +/// use [`invoke_contract`] to use the latest version if the target runtime supports it.** +/// /// # Errors /// /// - If the called account does not exist. @@ -274,7 +277,7 @@ where /// - If the called contract execution has trapped. /// - If the called contract ran out of gas upon execution. /// - If the returned value failed to decode properly. -pub fn invoke_contract( +pub fn invoke_contract_v1( params: &CallParams, Args, R>, ) -> Result> where @@ -283,7 +286,7 @@ where R: scale::Decode, { ::on_instance(|instance| { - TypedEnvBackend::invoke_contract::(instance, params) + TypedEnvBackend::invoke_contract_v1::(instance, params) }) } @@ -291,7 +294,7 @@ where /// /// # Note /// -/// **This will call into a new version of the host function which allows setting new +/// **This will call into the latest version of the host function which allows setting new /// weight and storage limit parameters.** /// /// This is a low level way to evaluate another smart contract. @@ -305,7 +308,7 @@ where /// - If the called contract execution has trapped. /// - If the called contract ran out of gas upon execution. /// - If the returned value failed to decode properly. -pub fn invoke_contract_v2( +pub fn invoke_contract( params: &CallParams, Args, R>, ) -> Result> where @@ -314,7 +317,7 @@ where R: scale::Decode, { ::on_instance(|instance| { - TypedEnvBackend::invoke_contract_v2::(instance, params) + TypedEnvBackend::invoke_contract::(instance, params) }) } diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index 7d49f50348a..43597082b37 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -295,8 +295,10 @@ pub trait TypedEnvBackend: EnvBackend { /// /// # Note /// - /// For more details visit: [`invoke_contract`][`crate::invoke_contract`] - fn invoke_contract( + /// **This will call into the original `call` host function.** + /// + /// For more details visit: [`invoke_contract`][`crate::invoke_contract_v1`] + fn invoke_contract_v1( &mut self, call_data: &CallParams, Args, R>, ) -> Result> @@ -309,10 +311,10 @@ pub trait TypedEnvBackend: EnvBackend { /// /// # Note /// - /// **This will call into the new `call_v2` host function.** + /// **This will call into the latest `call_v2` host function.** /// - /// For more details visit: [`invoke_contract`][`crate::invoke_contract_v2`] - fn invoke_contract_v2( + /// For more details visit: [`invoke_contract`][`crate::invoke_contract`] + fn invoke_contract( &mut self, call_data: &CallParams, Args, R>, ) -> Result> diff --git a/crates/env/src/call/call_builder.rs b/crates/env/src/call/call_builder.rs index 12c8d5b4829..fa37e2cf557 100644 --- a/crates/env/src/call/call_builder.rs +++ b/crates/env/src/call/call_builder.rs @@ -150,7 +150,7 @@ where /// [`ink::primitives::LangError`][`ink_primitives::LangError`]. If you want to handle /// those use the [`try_invoke`][`CallParams::try_invoke`] method instead. pub fn invoke(&self) -> R { - crate::invoke_contract(self) + crate::invoke_contract_v1(self) .unwrap_or_else(|env_error| { panic!("Cross-contract call failed with {env_error:?}") }) @@ -169,7 +169,7 @@ where /// [`ink::primitives::LangError`][`ink_primitives::LangError`], both of which can be /// handled by the caller. pub fn try_invoke(&self) -> Result, crate::Error> { - crate::invoke_contract(self) + crate::invoke_contract_v1(self) } } @@ -189,7 +189,7 @@ where /// [`ink::primitives::LangError`][`ink_primitives::LangError`]. If you want to handle /// those use the [`try_invoke`][`CallParams::try_invoke`] method instead. pub fn invoke(&self) -> R { - crate::invoke_contract_v2(self) + crate::invoke_contract(self) .unwrap_or_else(|env_error| { panic!("Cross-contract call failed with {env_error:?}") }) @@ -208,7 +208,7 @@ where /// [`ink::primitives::LangError`][`ink_primitives::LangError`], both of which can be /// handled by the caller. pub fn try_invoke(&self) -> Result, crate::Error> { - crate::invoke_contract_v2(self) + crate::invoke_contract(self) } } diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index da52a42dea8..2e567004f2b 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -437,7 +437,7 @@ impl TypedEnvBackend for EnvInstance { self.engine.deposit_event(&enc_topics[..], enc_data); } - fn invoke_contract( + fn invoke_contract_v1( &mut self, _params: &CallParams, Args, R>, ) -> Result> @@ -449,7 +449,7 @@ impl TypedEnvBackend for EnvInstance { unimplemented!("off-chain environment does not support contract invocation") } - fn invoke_contract_v2( + fn invoke_contract( &mut self, _params: &CallParams, Args, R>, ) -> Result> diff --git a/crates/env/src/engine/on_chain/impls.rs b/crates/env/src/engine/on_chain/impls.rs index 6dd18a8034b..ce36767ab90 100644 --- a/crates/env/src/engine/on_chain/impls.rs +++ b/crates/env/src/engine/on_chain/impls.rs @@ -424,7 +424,7 @@ impl TypedEnvBackend for EnvInstance { ext::deposit_event(enc_topics, enc_data); } - fn invoke_contract( + fn invoke_contract_v1( &mut self, params: &CallParams, Args, R>, ) -> Result> @@ -464,7 +464,7 @@ impl TypedEnvBackend for EnvInstance { } } - fn invoke_contract_v2( + fn invoke_contract( &mut self, params: &CallParams, Args, R>, ) -> Result> diff --git a/crates/ink/src/env_access.rs b/crates/ink/src/env_access.rs index 6f84ab8002e..91a9823fcfb 100644 --- a/crates/ink/src/env_access.rs +++ b/crates/ink/src/env_access.rs @@ -568,7 +568,7 @@ where /// # Note /// /// For more details visit: [`ink_env::invoke_contract`] - pub fn invoke_contract( + pub fn invoke_contract_v1( self, params: &CallParams, Args, R>, ) -> Result> @@ -576,7 +576,7 @@ where Args: scale::Encode, R: scale::Decode, { - ink_env::invoke_contract::(params) + ink_env::invoke_contract_v1::(params) } /// Invokes a contract message and returns its result. @@ -638,7 +638,7 @@ where /// # Note /// /// For more details visit: [`ink_env::invoke_contract_v2`] - pub fn invoke_contract_v2( + pub fn invoke_contract( self, params: &CallParams, Args, R>, ) -> Result> @@ -646,7 +646,7 @@ where Args: scale::Encode, R: scale::Decode, { - ink_env::invoke_contract_v2::(params) + ink_env::invoke_contract::(params) } /// Invokes in delegate manner a code message and returns its result. From fc409f10f3fb25f3f24e10a7001954381909ac0f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 6 Feb 2024 15:10:54 +0000 Subject: [PATCH 38/47] Fix doc test --- crates/ink/src/env_access.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ink/src/env_access.rs b/crates/ink/src/env_access.rs index 91a9823fcfb..c57ce278439 100644 --- a/crates/ink/src/env_access.rs +++ b/crates/ink/src/env_access.rs @@ -554,7 +554,7 @@ where /// .params(); /// /// self.env() - /// .invoke_contract(&call_params) + /// .invoke_contract_v1(&call_params) /// .unwrap_or_else(|env_err| { /// panic!("Received an error from the Environment: {:?}", env_err) /// }) @@ -624,7 +624,7 @@ where /// .params(); /// /// self.env() - /// .invoke_contract_v2(&call_params) + /// .invoke_contract(&call_params) /// .unwrap_or_else(|env_err| { /// panic!("Received an error from the Environment: {:?}", env_err) /// }) From dbd4d87783fe02f8eb1f4192e6f3cc93455bc01f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 6 Feb 2024 15:17:44 +0000 Subject: [PATCH 39/47] Update crates/env/src/call/call_builder.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michael Müller --- crates/env/src/call/call_builder.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/env/src/call/call_builder.rs b/crates/env/src/call/call_builder.rs index fa37e2cf557..7f1015dce7e 100644 --- a/crates/env/src/call/call_builder.rs +++ b/crates/env/src/call/call_builder.rs @@ -746,6 +746,9 @@ where } /// Sets the `transferred_value` for the current cross-contract call. + /// + /// This value specifies the amount of user funds that are transferred + /// to the other contract with this call. pub fn transferred_value(self, transferred_value: E::Balance) -> Self { let call_type = self.call_type.value(); CallBuilder { From 35b0907fe33bc6e7bd9d622c19fd0a214e3c9581 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 6 Feb 2024 15:17:57 +0000 Subject: [PATCH 40/47] Update crates/env/src/call/call_builder.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michael Müller --- crates/env/src/call/call_builder.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/env/src/call/call_builder.rs b/crates/env/src/call/call_builder.rs index 7f1015dce7e..28c579fa3e3 100644 --- a/crates/env/src/call/call_builder.rs +++ b/crates/env/src/call/call_builder.rs @@ -709,6 +709,10 @@ where /// Sets the `ref_time_limit` part of the weight limit for the current cross-contract /// call. + /// + /// `ref_time` refers to the amount of computational time that can be + /// used for execution, in picoseconds. You can find more info + /// [here](https://use.ink/basics/cross-contract-calling/). pub fn ref_time_limit(self, ref_time_limit: Gas) -> Self { let call_type = self.call_type.value(); CallBuilder { From e766fae4bda2c157dc9f4c1aef5c8cb5ca45353c Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 6 Feb 2024 15:18:13 +0000 Subject: [PATCH 41/47] Update crates/env/src/call/call_builder.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michael Müller --- crates/env/src/call/call_builder.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/env/src/call/call_builder.rs b/crates/env/src/call/call_builder.rs index 28c579fa3e3..e296d6d2246 100644 --- a/crates/env/src/call/call_builder.rs +++ b/crates/env/src/call/call_builder.rs @@ -726,6 +726,10 @@ where /// Sets the `proof_time_limit` part of the weight limit for the current /// cross-contract call. + /// + /// `proof_time` refers to the amount of storage in bytes that a transaction + /// is allowed to read. You can find more info + /// [here](https://use.ink/basics/cross-contract-calling/). pub fn proof_time_limit(self, proof_time_limit: Gas) -> Self { let call_type = self.call_type.value(); CallBuilder { From 75ebea3ecf65476900a40970d00b195a439bd205 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 6 Feb 2024 15:18:30 +0000 Subject: [PATCH 42/47] Update crates/env/src/call/call_builder.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michael Müller --- crates/env/src/call/call_builder.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/env/src/call/call_builder.rs b/crates/env/src/call/call_builder.rs index e296d6d2246..c9fcfaf5557 100644 --- a/crates/env/src/call/call_builder.rs +++ b/crates/env/src/call/call_builder.rs @@ -742,6 +742,10 @@ where } /// Sets the `storage_deposit_limit` for the current cross-contract call. + /// + /// The `storage_deposit_limit` specifies the amount of user funds that + /// can be charged for creating storage. You can find more info + /// [here](https://use.ink/basics/cross-contract-calling/). pub fn storage_deposit_limit(self, storage_deposit_limit: E::Balance) -> Self { let call_type = self.call_type.value(); CallBuilder { From b777fbf12dd73ad477ba240d7e9238597dc8a0ae Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 6 Feb 2024 15:20:41 +0000 Subject: [PATCH 43/47] Review suggestion --- crates/env/src/api.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index a8315598656..8816a426c6a 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -306,7 +306,7 @@ where /// - If the called account is not a contract. /// - If arguments passed to the called contract message are invalid. /// - If the called contract execution has trapped. -/// - If the called contract ran out of gas upon execution. +/// - If the called contract ran out of gas, proof time, or storage deposit upon execution. /// - If the returned value failed to decode properly. pub fn invoke_contract( params: &CallParams, Args, R>, From 4d3a1d50586dde5c0a45c1e10abbae8f15261e14 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 6 Feb 2024 15:23:00 +0000 Subject: [PATCH 44/47] Fmt --- crates/env/src/api.rs | 3 ++- crates/env/src/call/call_builder.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index 8816a426c6a..daac732e899 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -306,7 +306,8 @@ where /// - If the called account is not a contract. /// - If arguments passed to the called contract message are invalid. /// - If the called contract execution has trapped. -/// - If the called contract ran out of gas, proof time, or storage deposit upon execution. +/// - If the called contract ran out of gas, proof time, or storage deposit upon +/// execution. /// - If the returned value failed to decode properly. pub fn invoke_contract( params: &CallParams, Args, R>, diff --git a/crates/env/src/call/call_builder.rs b/crates/env/src/call/call_builder.rs index c9fcfaf5557..85540cd7ae5 100644 --- a/crates/env/src/call/call_builder.rs +++ b/crates/env/src/call/call_builder.rs @@ -759,7 +759,7 @@ where /// Sets the `transferred_value` for the current cross-contract call. /// - /// This value specifies the amount of user funds that are transferred + /// This value specifies the amount of user funds that are transferred /// to the other contract with this call. pub fn transferred_value(self, transferred_value: E::Balance) -> Self { let call_type = self.call_type.value(); From 6a5008e0511aa29076f7d19d442c688e3e9505e7 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 6 Feb 2024 16:49:21 +0000 Subject: [PATCH 45/47] Review suggestion and spellcheck --- .config/cargo_spellcheck.dic | 2 ++ crates/env/src/call/call_builder.rs | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/.config/cargo_spellcheck.dic b/.config/cargo_spellcheck.dic index 5d6a9cfb7be..4831da94b3e 100644 --- a/.config/cargo_spellcheck.dic +++ b/.config/cargo_spellcheck.dic @@ -109,6 +109,8 @@ instantiation/S layout/JG namespace/S parameterize/SD +parachain/S +picosecond/S runtime/S storable struct/S diff --git a/crates/env/src/call/call_builder.rs b/crates/env/src/call/call_builder.rs index 85540cd7ae5..f5c31f8f58c 100644 --- a/crates/env/src/call/call_builder.rs +++ b/crates/env/src/call/call_builder.rs @@ -730,6 +730,11 @@ where /// `proof_time` refers to the amount of storage in bytes that a transaction /// is allowed to read. You can find more info /// [here](https://use.ink/basics/cross-contract-calling/). + /// + /// **Note** + /// + /// This limit is only relevant for parachains, not for standalone chains which do not + /// require sending a Proof-of-validity to the relay chain. pub fn proof_time_limit(self, proof_time_limit: Gas) -> Self { let call_type = self.call_type.value(); CallBuilder { From 845c8cdd294a1a19dbb4f404b3f580c5cff03a0e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 6 Feb 2024 17:18:56 +0000 Subject: [PATCH 46/47] Use call_v2 in other examples --- integration-tests/erc1155/lib.rs | 2 +- integration-tests/multisig/lib.rs | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/integration-tests/erc1155/lib.rs b/integration-tests/erc1155/lib.rs index ba06c1ea052..f6cbf56971d 100644 --- a/integration-tests/erc1155/lib.rs +++ b/integration-tests/erc1155/lib.rs @@ -383,7 +383,7 @@ mod erc1155 { // reject this transfer. If they reject it we need to revert the call. let result = build_call::() .call(to) - .gas_limit(5000) + .ref_time_limit(5000) .exec_input( ExecutionInput::new(Selector::new(ON_ERC_1155_RECEIVED_SELECTOR)) .push_arg(caller) diff --git a/integration-tests/multisig/lib.rs b/integration-tests/multisig/lib.rs index 623919891e5..f7c0bf62146 100755 --- a/integration-tests/multisig/lib.rs +++ b/integration-tests/multisig/lib.rs @@ -127,7 +127,7 @@ mod multisig { /// The amount of chain balance that is transferred to the callee. pub transferred_value: Balance, /// Gas limit for the execution of the call. - pub gas_limit: u64, + pub ref_time_limit: u64, /// If set to true the transaction will be allowed to re-enter the multisig /// contract. Re-entrancy can lead to vulnerabilities. Use at your own /// risk. @@ -335,7 +335,7 @@ mod multisig { /// selector: selector_bytes!("add_owner"), /// input: add_owner_args.encode(), /// transferred_value: 0, - /// gas_limit: 0, + /// ref_time_limit: 0, /// allow_reentry: true, /// }; /// @@ -345,7 +345,7 @@ mod multisig { /// // are `[86, 244, 13, 223]`. /// let (id, _status) = ink::env::call::build_call::() /// .call_type(Call::new(wallet_id)) - /// .gas_limit(0) + /// .ref_time_limit(0) /// .exec_input( /// ExecutionInput::new(Selector::new([86, 244, 13, 223])) /// .push_arg(&transaction_candidate), @@ -359,7 +359,7 @@ mod multisig { /// // are `[185, 50, 225, 236]`. /// ink::env::call::build_call::() /// .call_type(Call::new(wallet_id)) - /// .gas_limit(0) + /// .ref_time_limit(0) /// .exec_input(ExecutionInput::new(Selector::new([185, 50, 225, 236])).push_arg(&id)) /// .returns::<()>() /// .invoke(); @@ -553,7 +553,7 @@ mod multisig { let result = build_call::<::Env>() .call(t.callee) - .gas_limit(t.gas_limit) + .ref_time_limit(t.ref_time_limit) .transferred_value(t.transferred_value) .call_flags(call_flags) .exec_input( @@ -594,7 +594,7 @@ mod multisig { let result = build_call::<::Env>() .call(t.callee) - .gas_limit(t.gas_limit) + .ref_time_limit(t.ref_time_limit) .transferred_value(t.transferred_value) .call_flags(call_flags) .exec_input( @@ -758,7 +758,7 @@ mod multisig { selector: ink::selector_bytes!("change_requirement"), input: call_args.encode(), transferred_value: 0, - gas_limit: 1000000, + ref_time_limit: 1000000, allow_reentry: false, } } From 85edec20d22ad731f99ac387a579f7424c1966c8 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 6 Feb 2024 17:38:57 +0000 Subject: [PATCH 47/47] Docs --- crates/ink/src/env_access.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ink/src/env_access.rs b/crates/ink/src/env_access.rs index c57ce278439..7dc17992ae9 100644 --- a/crates/ink/src/env_access.rs +++ b/crates/ink/src/env_access.rs @@ -567,7 +567,7 @@ where /// /// # Note /// - /// For more details visit: [`ink_env::invoke_contract`] + /// For more details visit: [`ink_env::invoke_contract_v1`] pub fn invoke_contract_v1( self, params: &CallParams, Args, R>, @@ -637,7 +637,7 @@ where /// /// # Note /// - /// For more details visit: [`ink_env::invoke_contract_v2`] + /// For more details visit: [`ink_env::invoke_contract`] pub fn invoke_contract( self, params: &CallParams, Args, R>,