From e7f1b8f2930ea46a85a3dfbbf87633428da1de75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Fri, 27 Oct 2023 17:43:11 -0300 Subject: [PATCH 01/44] Implementing stuff needed for instantiate_contract(). --- crates/env/Cargo.toml | 2 ++ crates/env/src/api.rs | 25 +++++++++++++++++++ crates/env/src/contract.rs | 7 ++++++ crates/env/src/lib.rs | 1 + crates/ink/Cargo.toml | 3 +++ .../generator/as_dependency/contract_ref.rs | 4 +++ crates/ink/codegen/src/generator/dispatch.rs | 8 ++++++ 7 files changed, 50 insertions(+) diff --git a/crates/env/Cargo.toml b/crates/env/Cargo.toml index 5dd9275d2a..737ea0eb58 100644 --- a/crates/env/Cargo.toml +++ b/crates/env/Cargo.toml @@ -60,6 +60,7 @@ ink = { path = "../ink" } [features] default = ["std"] std = [ + "ink/std", "ink_allocator/std", "ink_prelude/std", "ink_primitives/std", @@ -77,6 +78,7 @@ std = [ "sha3", "blake2", ] +storage_test = [] # Enable contract debug messages via `debug_print!` and `debug_println!`. ink-debug = [] diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index c0880cc9e8..b18f36b6bf 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -202,6 +202,31 @@ where }) } +/// Same as set_contract_storage(), but gets the key from a function pointer. +/// This is necessary for integration tests, because we can't get the key from +/// the type declaration. +#[cfg(feature="storage_test")] +pub fn set_contract_storage_test(value: &V) -> Option +where + V: Storable, + Ref: ink_storage_traits::StorageLayout, +{ + let x = Ref::layout as u64; + let x = ((x | (x >> 32)) & 0xFFFFFFFF) as u32; + set_contract_storage(&x, value) +} + +/// Dummy set_contract_storage_test() for non-test environments. The compiler +/// should optimize this away. +#[cfg(not(feature="storage_test"))] +pub fn set_contract_storage_test(value: &V) -> Option +where + V: Storable, + Ref: ink_storage_traits::StorageLayout, +{ + None +} + /// Returns the value stored under the given storage key in the contract's storage if any. /// /// # Errors diff --git a/crates/env/src/contract.rs b/crates/env/src/contract.rs index 86b5d1b524..319a2aaf96 100644 --- a/crates/env/src/contract.rs +++ b/crates/env/src/contract.rs @@ -139,3 +139,10 @@ pub trait ContractReference { /// The generated contract reference type. type Type; } + +/// Refers back to the original contract from the generated ink! smart contract +/// reference type. +pub trait ContractReverseReference{ + /// The original contract type. + type Type; +} diff --git a/crates/env/src/lib.rs b/crates/env/src/lib.rs index 881de49344..7f15f79574 100644 --- a/crates/env/src/lib.rs +++ b/crates/env/src/lib.rs @@ -116,6 +116,7 @@ pub use self::{ contract::{ ContractEnv, ContractReference, + ContractReverseReference, }, error::{ Error, diff --git a/crates/ink/Cargo.toml b/crates/ink/Cargo.toml index 7afe993fd7..bb6d5dfecf 100644 --- a/crates/ink/Cargo.toml +++ b/crates/ink/Cargo.toml @@ -50,6 +50,9 @@ std = [ ink-debug = [ "ink_env/ink-debug", ] +storage_test = [ + "ink_env/storage_test" +] show-codegen-docs = [] diff --git a/crates/ink/codegen/src/generator/as_dependency/contract_ref.rs b/crates/ink/codegen/src/generator/as_dependency/contract_ref.rs index bbedecc333..461ba595d4 100644 --- a/crates/ink/codegen/src/generator/as_dependency/contract_ref.rs +++ b/crates/ink/codegen/src/generator/as_dependency/contract_ref.rs @@ -107,6 +107,10 @@ impl ContractRef<'_> { type Type = #ref_ident; } + impl ::ink::env::ContractReverseReference for #ref_ident { + type Type = #storage_ident; + } + impl ::ink::env::call::ConstructorReturnType<#ref_ident> for #storage_ident { type Output = #ref_ident; type Error = (); diff --git a/crates/ink/codegen/src/generator/dispatch.rs b/crates/ink/codegen/src/generator/dispatch.rs index 40711d1a9a..64c33ccdba 100644 --- a/crates/ink/codegen/src/generator/dispatch.rs +++ b/crates/ink/codegen/src/generator/dispatch.rs @@ -476,6 +476,7 @@ impl Dispatch<'_> { let span = self.contract.module().storage().span(); let storage_ident = self.contract.module().storage().ident(); + let ref_ident = quote::format_ident!("{}Ref", self.contract.module().storage().ident()); let constructors_variants = constructors.iter().enumerate().map(|(index, item)| { let constructor_span = item.constructor.span(); @@ -586,6 +587,13 @@ impl Dispatch<'_> { &<#storage_ident as ::ink::storage::traits::StorageKey>::KEY, contract, ); + ::ink::env::set_contract_storage_test::<#storage_ident, #ref_ident>( + contract, + ); + } + + if let ::core::result::Result::Ok(contract) = output_result.as_ref() { + } ::ink::env::return_value::< From 506e95de9ae2a41788db230bcfe70562b710d4a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Fri, 27 Oct 2023 17:47:14 -0300 Subject: [PATCH 02/44] Implemented return_value() on integration tests. # Conflicts: # crates/env/src/lib.rs # crates/env/src/reflect/event.rs # crates/ink/codegen/Cargo.toml --- crates/env/Cargo.toml | 2 +- crates/env/src/api.rs | 26 ++++++++-- crates/env/src/backend.rs | 18 ++++++- crates/env/src/call/create_builder.rs | 6 ++- crates/env/src/engine/off_chain/impls.rs | 39 ++++++++++++-- crates/env/src/engine/off_chain/mod.rs | 2 +- crates/env/src/lib.rs | 1 + crates/{ink => env}/src/reflect/contract.rs | 0 crates/{ink => env}/src/reflect/dispatch.rs | 2 + crates/env/src/reflect/event.rs | 52 +++++++++++++++++++ crates/{ink => env}/src/reflect/mod.rs | 0 .../src/reflect/trait_def/info.rs | 0 .../{ink => env}/src/reflect/trait_def/mod.rs | 0 .../src/reflect/trait_def/registry.rs | 4 +- crates/ink/Cargo.toml | 4 +- crates/ink/codegen/Cargo.toml | 2 +- crates/ink/codegen/src/generator/dispatch.rs | 16 +++--- crates/ink/codegen/src/lib.rs | 1 + crates/ink/src/env_access.rs | 3 +- crates/ink/src/lib.rs | 2 +- 20 files changed, 152 insertions(+), 28 deletions(-) rename crates/{ink => env}/src/reflect/contract.rs (100%) rename crates/{ink => env}/src/reflect/dispatch.rs (99%) create mode 100644 crates/env/src/reflect/event.rs rename crates/{ink => env}/src/reflect/mod.rs (100%) rename crates/{ink => env}/src/reflect/trait_def/info.rs (100%) rename crates/{ink => env}/src/reflect/trait_def/mod.rs (100%) rename crates/{ink => env}/src/reflect/trait_def/registry.rs (97%) diff --git a/crates/env/Cargo.toml b/crates/env/Cargo.toml index 737ea0eb58..129f3aa2d5 100644 --- a/crates/env/Cargo.toml +++ b/crates/env/Cargo.toml @@ -78,7 +78,7 @@ std = [ "sha3", "blake2", ] -storage_test = [] +test_instantiate = [] # Enable contract debug messages via `debug_print!` and `debug_println!`. ink-debug = [] diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index b18f36b6bf..34cb326a04 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -205,7 +205,7 @@ where /// Same as set_contract_storage(), but gets the key from a function pointer. /// This is necessary for integration tests, because we can't get the key from /// the type declaration. -#[cfg(feature="storage_test")] +#[cfg(feature="test_instantiate")] pub fn set_contract_storage_test(value: &V) -> Option where V: Storable, @@ -218,8 +218,8 @@ where /// Dummy set_contract_storage_test() for non-test environments. The compiler /// should optimize this away. -#[cfg(not(feature="storage_test"))] -pub fn set_contract_storage_test(value: &V) -> Option +#[cfg(not(feature="test_instantiate"))] +pub fn set_contract_storage_test(_value: &V) -> Option where V: Storable, Ref: ink_storage_traits::StorageLayout, @@ -361,7 +361,8 @@ pub fn instantiate_contract( > where E: Environment, - ContractRef: FromAccountId, + ContractRef: FromAccountId + crate::contract::ContractReverseReference, + ::Type: crate::reflect::ContractConstructorDecoder, Args: scale::Encode, Salt: AsRef<[u8]>, R: ConstructorReturnType, @@ -451,6 +452,7 @@ where /// # Note /// /// This function stops the execution of the contract immediately. +#[cfg(not(feature="test_instantiate"))] pub fn return_value(return_flags: ReturnFlags, return_value: &R) -> ! where R: scale::Encode, @@ -460,6 +462,22 @@ where }) } +/// Returns the value back to the caller of the executed contract. +/// +/// # Note +/// +/// When the test_instantiate feature is used, the contract is allowed to +/// return normally. This feature should only be used for integration tests. +#[cfg(feature="test_instantiate")] +pub fn return_value(return_flags: ReturnFlags, return_value: &R) -> () +where + R: scale::Encode, +{ + ::on_instance(|instance| { + EnvBackend::return_value::(instance, return_flags, return_value) + }) +} + /// Appends the given message to the debug message buffer. pub fn debug_message(message: &str) { ::on_instance(|instance| { diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index 99455b5786..22b29c84c8 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -247,10 +247,25 @@ pub trait EnvBackend { /// /// The `flags` parameter can be used to revert the state changes of the /// entire execution if necessary. + #[cfg(not(feature="test_instantiate"))] fn return_value(&mut self, flags: ReturnFlags, return_value: &R) -> ! where R: scale::Encode; + /// Returns the value back to the caller of the executed contract. + /// + /// # Note + /// + /// When the test_instantiate feature is used, the contract is allowed to + /// return normally. This feature should only be used for integration tests. + /// + /// The `flags` parameter can be used to revert the state changes of the + /// entire execution if necessary. + #[cfg(feature="test_instantiate")] + fn return_value(&mut self, flags: ReturnFlags, return_value: &R) -> () + where + R: scale::Encode; + /// Emit a custom debug message. /// /// The message is appended to the debug buffer which is then supplied to the calling @@ -469,7 +484,8 @@ pub trait TypedEnvBackend: EnvBackend { > where E: Environment, - ContractRef: FromAccountId, + ContractRef: FromAccountId + crate::contract::ContractReverseReference, + ::Type: crate::reflect::ContractConstructorDecoder, Args: scale::Encode, Salt: AsRef<[u8]>, R: ConstructorReturnType; diff --git a/crates/env/src/call/create_builder.rs b/crates/env/src/call/create_builder.rs index 74dc429287..3ae1fe1fc9 100644 --- a/crates/env/src/call/create_builder.rs +++ b/crates/env/src/call/create_builder.rs @@ -240,7 +240,8 @@ where impl CreateParams where E: Environment, - ContractRef: FromAccountId, + ContractRef: FromAccountId + crate::contract::ContractReverseReference, + ::Type: crate::reflect::ContractConstructorDecoder, Args: scale::Encode, Salt: AsRef<[u8]>, R: ConstructorReturnType, @@ -721,7 +722,8 @@ impl > where E: Environment, - ContractRef: FromAccountId, + ContractRef: FromAccountId + crate::contract::ContractReverseReference, + ::Type: crate::reflect::ContractConstructorDecoder, GasLimit: Unwrap, Args: scale::Encode, Salt: AsRef<[u8]>, diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index f170a8ab53..398b18d0a1 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -251,11 +251,22 @@ impl EnvBackend for EnvInstance { unimplemented!("the off-chain env does not implement `input`") } + #[cfg(not(feature="test_instantiate"))] fn return_value(&mut self, _flags: ReturnFlags, _return_value: &R) -> ! where R: scale::Encode, { - unimplemented!("the off-chain env does not implement `return_value`") + panic!("enable feature test_instantiate to use return_value()") + } + + #[cfg(feature="test_instantiate")] + fn return_value(&mut self, _flags: ReturnFlags, return_value: &R) -> () + where + R: scale::Encode, + { + let mut v = vec![]; + return_value.encode_to(&mut v); + self.engine.set_storage(&[0, 0, 0, 0], &v[..]); } fn debug_message(&mut self, message: &str) { @@ -498,7 +509,8 @@ impl TypedEnvBackend for EnvInstance { > where E: Environment, - ContractRef: FromAccountId, + ContractRef: FromAccountId + crate::contract::ContractReverseReference, + ::Type: crate::reflect::ContractConstructorDecoder, Args: scale::Encode, Salt: AsRef<[u8]>, R: ConstructorReturnType, @@ -506,9 +518,28 @@ impl TypedEnvBackend for EnvInstance { let _code_hash = params.code_hash(); let _gas_limit = params.gas_limit(); let _endowment = params.endowment(); - let _input = params.exec_input(); let _salt_bytes = params.salt_bytes(); - unimplemented!("off-chain environment does not support contract instantiation") + + let input = params.exec_input(); + let input = ::scale::Encode::encode(input); + let dispatch = < + < + < + ContractRef + as crate::contract::ContractReverseReference + >::Type + as crate::reflect::ContractConstructorDecoder + >::Type + as scale::Decode + >::decode(&mut &input[..]) + .unwrap_or_else(|e| panic!("Failed to decode constructor call: {:?}", e)); + crate::reflect::ExecuteDispatchable::execute_dispatchable(dispatch) + .unwrap_or_else(|e| panic!("Constructor call failed: {:?}", e)); + + //self.get_contract_storage::(&0_u32) + // .unwrap_or_else(|e| panic!("Failed to decode return value: {:?}", e)) + let id = ::AccountId::decode(&mut &(vec![0_u8; 32][..])).unwrap(); + Ok(Ok(R::ok(>::from_account_id(id)))) } fn terminate_contract(&mut self, beneficiary: E::AccountId) -> ! diff --git a/crates/env/src/engine/off_chain/mod.rs b/crates/env/src/engine/off_chain/mod.rs index 1f463b4427..5ceb4a1313 100644 --- a/crates/env/src/engine/off_chain/mod.rs +++ b/crates/env/src/engine/off_chain/mod.rs @@ -46,7 +46,7 @@ impl OnInstance for EnvInstance { } ) ); - INSTANCE.with(|instance| f(&mut instance.borrow_mut())) + INSTANCE.with(|instance| f(unsafe{ &mut *instance.as_ptr() })) } } diff --git a/crates/env/src/lib.rs b/crates/env/src/lib.rs index 7f15f79574..351c15eb73 100644 --- a/crates/env/src/lib.rs +++ b/crates/env/src/lib.rs @@ -91,6 +91,7 @@ pub mod chain_extension; mod contract; mod engine; mod error; +pub mod reflect; #[doc(hidden)] pub mod event; pub mod hash; diff --git a/crates/ink/src/reflect/contract.rs b/crates/env/src/reflect/contract.rs similarity index 100% rename from crates/ink/src/reflect/contract.rs rename to crates/env/src/reflect/contract.rs diff --git a/crates/ink/src/reflect/dispatch.rs b/crates/env/src/reflect/dispatch.rs similarity index 99% rename from crates/ink/src/reflect/dispatch.rs rename to crates/env/src/reflect/dispatch.rs index 2ff9822f13..6e46464668 100644 --- a/crates/ink/src/reflect/dispatch.rs +++ b/crates/env/src/reflect/dispatch.rs @@ -263,6 +263,7 @@ pub trait ConstructorOutput: private::Sealed { pub struct ConstructorOutputValue(T); impl ConstructorOutputValue { + /// Stores the actual value of the constructor return type. pub fn new(val: T) -> Self { Self(val) } @@ -615,5 +616,6 @@ impl From for scale::Error { /// } /// ``` pub trait DecodeDispatch: scale::Decode { + /// Decodes an ink! dispatch input into a known selector and its expected parameters. fn decode_dispatch(input: &mut I) -> Result; } diff --git a/crates/env/src/reflect/event.rs b/crates/env/src/reflect/event.rs new file mode 100644 index 0000000000..69181659e3 --- /dev/null +++ b/crates/env/src/reflect/event.rs @@ -0,0 +1,52 @@ +// Copyright 2018-2022 Parity Technologies (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/// Defines a base event type for the contract. +/// +/// This is usually the event enum that comprises all defined event types. +/// +/// # Usage +/// +/// ``` +/// #[ink::contract] +/// pub mod contract { +/// #[ink(storage)] +/// pub struct Contract {} +/// +/// #[ink(event)] +/// pub struct Event1 {} +/// +/// #[ink(event)] +/// pub struct Event2 {} +/// +/// impl Contract { +/// #[ink(constructor)] +/// pub fn constructor() -> Self { +/// Self {} +/// } +/// +/// #[ink(message)] +/// pub fn message(&self) {} +/// } +/// } +/// +/// use contract::Contract; +/// # use ink::reflect::ContractEventBase; +/// +/// type BaseEvent = ::Type; +/// ``` +pub trait ContractEventBase { + /// The generated base event enum. + type Type; +} diff --git a/crates/ink/src/reflect/mod.rs b/crates/env/src/reflect/mod.rs similarity index 100% rename from crates/ink/src/reflect/mod.rs rename to crates/env/src/reflect/mod.rs diff --git a/crates/ink/src/reflect/trait_def/info.rs b/crates/env/src/reflect/trait_def/info.rs similarity index 100% rename from crates/ink/src/reflect/trait_def/info.rs rename to crates/env/src/reflect/trait_def/info.rs diff --git a/crates/ink/src/reflect/trait_def/mod.rs b/crates/env/src/reflect/trait_def/mod.rs similarity index 100% rename from crates/ink/src/reflect/trait_def/mod.rs rename to crates/env/src/reflect/trait_def/mod.rs diff --git a/crates/ink/src/reflect/trait_def/registry.rs b/crates/env/src/reflect/trait_def/registry.rs similarity index 97% rename from crates/ink/src/reflect/trait_def/registry.rs rename to crates/env/src/reflect/trait_def/registry.rs index 558a218ff7..5c47419b7d 100644 --- a/crates/ink/src/reflect/trait_def/registry.rs +++ b/crates/env/src/reflect/trait_def/registry.rs @@ -13,7 +13,7 @@ // limitations under the License. use core::marker::PhantomData; -use ink_env::ContractEnv; +use crate::ContractEnv; /// Type that is guaranteed by ink! to implement all ink! trait definitions. /// @@ -56,7 +56,7 @@ pub struct TraitDefinitionRegistry { impl ContractEnv for TraitDefinitionRegistry where - E: ink_env::Environment, + E: crate::Environment, { type Env = E; } diff --git a/crates/ink/Cargo.toml b/crates/ink/Cargo.toml index bb6d5dfecf..12d4a6ba8a 100644 --- a/crates/ink/Cargo.toml +++ b/crates/ink/Cargo.toml @@ -50,8 +50,8 @@ std = [ ink-debug = [ "ink_env/ink-debug", ] -storage_test = [ - "ink_env/storage_test" +test_instantiate = [ + "ink_env/test_instantiate" ] show-codegen-docs = [] diff --git a/crates/ink/codegen/Cargo.toml b/crates/ink/codegen/Cargo.toml index f0a9a4541b..a47902ed0d 100644 --- a/crates/ink/codegen/Cargo.toml +++ b/crates/ink/codegen/Cargo.toml @@ -19,7 +19,7 @@ name = "ink_codegen" [dependencies] ink_primitives = { workspace = true } -ir = { version = "=5.0.0-alpha", package = "ink_ir", path = "../ir", default-features = false } +ink_env = { workspace = true } quote = { workspace = true } syn = { workspace = true, features = ["parsing", "full", "extra-traits"] } proc-macro2 = { workspace = true } diff --git a/crates/ink/codegen/src/generator/dispatch.rs b/crates/ink/codegen/src/generator/dispatch.rs index 64c33ccdba..4f3980f494 100644 --- a/crates/ink/codegen/src/generator/dispatch.rs +++ b/crates/ink/codegen/src/generator/dispatch.rs @@ -590,10 +590,6 @@ impl Dispatch<'_> { ::ink::env::set_contract_storage_test::<#storage_ident, #ref_ident>( contract, ); - } - - if let ::core::result::Result::Ok(contract) = output_result.as_ref() { - } ::ink::env::return_value::< @@ -606,6 +602,8 @@ impl Dispatch<'_> { // dispatch logic so `Ok` is always returned to the caller. &::ink::ConstructorResult::Ok(output_result.map(|_| ())), ); + + Ok(()) } ) }); @@ -647,9 +645,9 @@ impl Dispatch<'_> { impl ::ink::reflect::ExecuteDispatchable for __ink_ConstructorDecoder { #[allow(clippy::nonminimal_bool)] fn execute_dispatchable(self) -> ::core::result::Result<(), ::ink::reflect::DispatchError> { - match self { + return match self { #( #constructor_execute ),* - } + }; } } @@ -801,7 +799,9 @@ impl Dispatch<'_> { // Currently no `LangError`s are raised at this level of the // dispatch logic so `Ok` is always returned to the caller. &::ink::MessageResult::Ok(result), - ) + ); + + Ok(()) } ) }); @@ -871,7 +871,7 @@ impl Dispatch<'_> { match self { #( #message_execute ),* - }; + } } } diff --git a/crates/ink/codegen/src/lib.rs b/crates/ink/codegen/src/lib.rs index b9c97ee994..95287f36a7 100644 --- a/crates/ink/codegen/src/lib.rs +++ b/crates/ink/codegen/src/lib.rs @@ -35,6 +35,7 @@ html_favicon_url = "https://use.ink/crate-docs/favicon.png" )] +pub use ink_env::reflect; mod enforced_error; mod generator; mod traits; diff --git a/crates/ink/src/env_access.rs b/crates/ink/src/env_access.rs index 0cc8e871e8..1a1a336437 100644 --- a/crates/ink/src/env_access.rs +++ b/crates/ink/src/env_access.rs @@ -499,7 +499,8 @@ where >, > where - ContractRef: FromAccountId, + ContractRef: FromAccountId + ink_env::ContractReverseReference, + ::Type: ink_env::reflect::ContractConstructorDecoder, Args: scale::Encode, Salt: AsRef<[u8]>, R: ConstructorReturnType, diff --git a/crates/ink/src/lib.rs b/crates/ink/src/lib.rs index 4c00a39d9a..0af35c2bbb 100644 --- a/crates/ink/src/lib.rs +++ b/crates/ink/src/lib.rs @@ -29,7 +29,7 @@ pub mod result_info; #[cfg_attr(not(feature = "show-codegen-docs"), doc(hidden))] pub mod codegen; -pub mod reflect; +pub use ink_env::reflect as reflect; mod chain_extension; mod contract_ref; From bc8688b24c3b9760c54908df6a72c232b67b8fee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Fri, 27 Oct 2023 17:48:05 -0300 Subject: [PATCH 03/44] A couple fixes for E2E environment. --- crates/env/src/api.rs | 3 --- crates/ink/codegen/src/generator/dispatch.rs | 10 +++++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index 34cb326a04..9132ef38f0 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -220,9 +220,6 @@ where /// should optimize this away. #[cfg(not(feature="test_instantiate"))] pub fn set_contract_storage_test(_value: &V) -> Option -where - V: Storable, - Ref: ink_storage_traits::StorageLayout, { None } diff --git a/crates/ink/codegen/src/generator/dispatch.rs b/crates/ink/codegen/src/generator/dispatch.rs index 4f3980f494..d4c4fd3e04 100644 --- a/crates/ink/codegen/src/generator/dispatch.rs +++ b/crates/ink/codegen/src/generator/dispatch.rs @@ -602,7 +602,7 @@ impl Dispatch<'_> { // dispatch logic so `Ok` is always returned to the caller. &::ink::ConstructorResult::Ok(output_result.map(|_| ())), ); - + Ok(()) } ) @@ -643,11 +643,11 @@ impl Dispatch<'_> { } impl ::ink::reflect::ExecuteDispatchable for __ink_ConstructorDecoder { - #[allow(clippy::nonminimal_bool)] + #[allow(clippy::nonminimal_bool, dead_code)] fn execute_dispatchable(self) -> ::core::result::Result<(), ::ink::reflect::DispatchError> { - return match self { + match self { #( #constructor_execute ),* - }; + } } } @@ -851,7 +851,7 @@ impl Dispatch<'_> { } impl ::ink::reflect::ExecuteDispatchable for __ink_MessageDecoder { - #[allow(clippy::nonminimal_bool, clippy::let_unit_value)] + #[allow(clippy::nonminimal_bool, clippy::let_unit_value, dead_code)] fn execute_dispatchable( self ) -> ::core::result::Result<(), ::ink::reflect::DispatchError> { From 6ccd54bb7de9b6d4a37b07fa6704b848b6f9779f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Fri, 27 Oct 2023 17:48:21 -0300 Subject: [PATCH 04/44] Forgot to delete some fluff. --- crates/env/src/engine/off_chain/impls.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index 398b18d0a1..edca40d222 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -536,8 +536,6 @@ impl TypedEnvBackend for EnvInstance { crate::reflect::ExecuteDispatchable::execute_dispatchable(dispatch) .unwrap_or_else(|e| panic!("Constructor call failed: {:?}", e)); - //self.get_contract_storage::(&0_u32) - // .unwrap_or_else(|e| panic!("Failed to decode return value: {:?}", e)) let id = ::AccountId::decode(&mut &(vec![0_u8; 32][..])).unwrap(); Ok(Ok(R::ok(>::from_account_id(id)))) } From 34854c581c6e2efd17c493d50113e0df094f9fb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Fri, 27 Oct 2023 17:48:42 -0300 Subject: [PATCH 05/44] Fixed dead code warnings. --- crates/ink/codegen/src/generator/dispatch.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/ink/codegen/src/generator/dispatch.rs b/crates/ink/codegen/src/generator/dispatch.rs index d4c4fd3e04..6833c0ce18 100644 --- a/crates/ink/codegen/src/generator/dispatch.rs +++ b/crates/ink/codegen/src/generator/dispatch.rs @@ -603,6 +603,7 @@ impl Dispatch<'_> { &::ink::ConstructorResult::Ok(output_result.map(|_| ())), ); + #[cfg(feature="test_instantiate")] Ok(()) } ) @@ -801,6 +802,7 @@ impl Dispatch<'_> { &::ink::MessageResult::Ok(result), ); + #[cfg(feature="test_instantiate")] Ok(()) } ) From c75ed7dcb4110ed066e4af9bdc2da2e6f28ac998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Fri, 27 Oct 2023 17:56:08 -0300 Subject: [PATCH 06/44] Added tests. --- .../instantiate-contract/Cargo.toml | 44 ++++++++ .../instantiate-contract/README.md | 41 +++++++ integration-tests/instantiate-contract/lib.rs | 104 ++++++++++++++++++ .../other_contract/Cargo.toml | 35 ++++++ .../other_contract/lib.rs | 44 ++++++++ 5 files changed, 268 insertions(+) create mode 100644 integration-tests/instantiate-contract/Cargo.toml create mode 100644 integration-tests/instantiate-contract/README.md create mode 100644 integration-tests/instantiate-contract/lib.rs create mode 100644 integration-tests/instantiate-contract/other_contract/Cargo.toml create mode 100644 integration-tests/instantiate-contract/other_contract/lib.rs diff --git a/integration-tests/instantiate-contract/Cargo.toml b/integration-tests/instantiate-contract/Cargo.toml new file mode 100644 index 0000000000..6a834c0eca --- /dev/null +++ b/integration-tests/instantiate-contract/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "instantiate_contract" +version = "0.1.0" +edition = "2021" +authors = ["Víctor M. González "] + +[lib] +path = "lib.rs" + +[features] +default = ["std", "test_instantiate"] +std = [ + "ink/std", + "scale/std", + "scale-info/std", + "other_contract/std" +] +ink-as-dependency = [] +e2e-tests = [] +test_instantiate = [ + "ink/test_instantiate", + "other_contract/test_instantiate" +] + +[dependencies] +ink = { path = "../../crates/ink", default-features = false } +scale = { package = "parity-scale-codec", version = "=3.6.5", default-features = false, features = [ + "derive", +] } +scale-info = { version = "2.6", default-features = false, features = [ + "derive", +], optional = true } +other_contract = { path = "./other_contract", default-features = false, features = [ + "ink-as-dependency", +] } + +[dev-dependencies] +ink_e2e = { path = "../../crates/e2e" } + +[profile.dev] +overflow-checks = false + +[profile.release] +overflow-checks = false diff --git a/integration-tests/instantiate-contract/README.md b/integration-tests/instantiate-contract/README.md new file mode 100644 index 0000000000..c0a2056625 --- /dev/null +++ b/integration-tests/instantiate-contract/README.md @@ -0,0 +1,41 @@ +# Function `instantiate_contract` + +```rust +pub fn instantiate_contract( + params: &CreateParams +) -> Result>::Output>> +where + E: Environment, + ContractRef: FromAccountId, + Args: Encode, + Salt: AsRef<[u8]>, + R: ConstructorReturnType, +``` + +## Description + +`instantiate_contract` is a low level way to instantiate another smart contract. + +## Related ink! functions + +- [instantiate_contract](https://paritytech.github.io/ink/ink_env/fn.instantiate_contract.html) + +## Test case (original status) + +### Comparison Integration vs E2E + +The End-to-End test works correctly since it invokes successfully the call to the second contract. In Integration did not work since it's [unimplemented](https://github.com/paritytech/ink/blob/c2af39883aab48c71dc09dac5d06583f2e84dc54/crates/env/src/engine/off_chain/impls.rs#L464). + +| \# | Test | Integration | E2E | +| --- | --------------------------------------------------------------- | :---------: | :-: | +| 1 | Attempts to instantiate a contract. | ❌ | ✅ | + +### Result + +The implementation of instantiate_contract() is somewhat tied to that of code_hash and own_code_hash(). The strategy picked for one will condition the solution for the other. The simpler of the two may take up to roughly 15 days. There are some things to work out, such as how to call the required function, that add some uncertainty to the estimate. + +## Status after implementation + +| \# | Test | Integration | E2E | +| --- | --------------------------------------------------------------- | :---------: | :-: | +| 1 | Attempts to instantiate a contract. | ✅ | ✅ | diff --git a/integration-tests/instantiate-contract/lib.rs b/integration-tests/instantiate-contract/lib.rs new file mode 100644 index 0000000000..6b7aa4cdbf --- /dev/null +++ b/integration-tests/instantiate-contract/lib.rs @@ -0,0 +1,104 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + +#[ink::contract] +mod instantiate_contract { + use other_contract::OtherContractRef; + + #[ink(storage)] + pub struct InstantiateContract {} + + impl InstantiateContract { + #[ink(constructor)] + pub fn new() -> Self { + Self {} + } + + #[ink(message)] + pub fn instantiate_other_contract(&self, code_hash: Hash) -> OtherContractRef { + let create_params = ink::env::call::build_create::() + .code_hash(code_hash) + .gas_limit(0) + .endowment(0) + .exec_input(ink::env::call::ExecutionInput::new( + ink::env::call::Selector::new(ink::selector_bytes!("new")), + )) + .salt_bytes(&[0x0; 4]) + .returns::() + .params(); + + self.env() + .instantiate_contract(&create_params) + .unwrap_or_else(|error| { + panic!( + "Received an error from the Contracts pallet while instantiating: {:?}", + error + ) + }) + .unwrap_or_else(|error| { + panic!("Received a `LangError` while instatiating: {:?}", error) + }) + } + } + + impl Default for InstantiateContract { + fn default() -> Self { + Self::new() + } + } + + #[cfg(all(test, feature = "test_instantiate"))] + mod tests { + use super::*; + + #[ink::test] + fn instantiate_other_contract() { + let contract = InstantiateContract::new(); + let code_hash = Hash::from([0x42; 32]); + let _ = contract.instantiate_other_contract(code_hash); + } + } + + #[cfg(all(test, feature = "e2e-tests", not(feature = "test_instantiate")))] + mod e2e_tests { + use ink_e2e::build_message; + + use super::*; + + type E2EResult = std::result::Result>; + + #[ink_e2e::test(additional_contracts = "other_contract/Cargo.toml")] + async fn instantiate_other_contract(mut client: ink_e2e::Client) -> E2EResult<()> { + let constructor = InstantiateContractRef::new(); + + let contract_acc_id = client + .instantiate( + "instantiate_contract", + &ink_e2e::bob(), + constructor, + 0, + None, + ) + .await + .expect("instantiate failed") + .account_id; + + let other_contract_code_hash = client + .upload("other_contract", &ink_e2e::bob(), None) + .await + .expect("instantiate failed") + .code_hash; + + let instantiate_other_contract = + build_message::(contract_acc_id.clone()) + .call(|contract| contract.instantiate_other_contract(other_contract_code_hash)); + + let instantiate_other_contract_res = client + .call_dry_run(&ink_e2e::bob(), &instantiate_other_contract, 0, None) + .await; + + assert!(instantiate_other_contract_res.exec_result.result.is_ok()); + + Ok(()) + } + } +} diff --git a/integration-tests/instantiate-contract/other_contract/Cargo.toml b/integration-tests/instantiate-contract/other_contract/Cargo.toml new file mode 100644 index 0000000000..94f4c9c0f7 --- /dev/null +++ b/integration-tests/instantiate-contract/other_contract/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "other_contract" +version = "0.1.0" +edition = "2021" +authors = ["Víctor M. González "] + +[lib] +path = "lib.rs" + +[features] +default = ["std", "test_instantiate"] +std = ["ink/std", "scale/std", "scale-info/std"] +ink-as-dependency = [] +e2e-tests = [] +test_instantiate = [ + "ink/test_instantiate" +] + +[dependencies] +ink = { path = "../../../crates/ink", default-features = false } +scale = { package = "parity-scale-codec", version = "=3.6.5", default-features = false, features = [ + "derive", +] } +scale-info = { version = "2.6", default-features = false, features = [ + "derive", +], optional = true } + +[dev-dependencies] +ink_e2e = { path = "../../../crates/e2e" } + +[profile.dev] +overflow-checks = false + +[profile.release] +overflow-checks = false diff --git a/integration-tests/instantiate-contract/other_contract/lib.rs b/integration-tests/instantiate-contract/other_contract/lib.rs new file mode 100644 index 0000000000..f0dce841de --- /dev/null +++ b/integration-tests/instantiate-contract/other_contract/lib.rs @@ -0,0 +1,44 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + +pub use self::other_contract::OtherContractRef; + +#[ink::contract()] +mod other_contract { + + #[ink(storage)] + pub struct OtherContract { + x: u32, + } + + impl OtherContract { + /// Creates a new Template contract. + #[ink(constructor)] + pub fn new() -> Self { + Self { + x: 42, + } + } + + #[ink(message)] + pub fn set_x(&mut self, x: u32){ + self.x = x; + } + + #[ink(message)] + pub fn get_x(&self) -> u32{ + self.x + } + + /// Returns the hash code of the contract through the function 'own_code_hash'. + #[ink(message)] + pub fn own_code_hash(&self) -> Hash { + self.env().own_code_hash().unwrap() + } + } + + impl Default for OtherContract { + fn default() -> Self { + Self::new() + } + } +} From 3ccb01f808713f169a249a18620d909a504d1cac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Fri, 27 Oct 2023 18:59:17 -0300 Subject: [PATCH 07/44] Fixed-up tomls. --- crates/ink/codegen/Cargo.toml | 3 ++- crates/ink/macro/Cargo.toml | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/ink/codegen/Cargo.toml b/crates/ink/codegen/Cargo.toml index a47902ed0d..5f566002fa 100644 --- a/crates/ink/codegen/Cargo.toml +++ b/crates/ink/codegen/Cargo.toml @@ -20,6 +20,7 @@ name = "ink_codegen" [dependencies] ink_primitives = { workspace = true } ink_env = { workspace = true } +ir = { version = "=5.0.0-alpha", package = "ink_ir", path = "../ir", default-features = false } quote = { workspace = true } syn = { workspace = true, features = ["parsing", "full", "extra-traits"] } proc-macro2 = { workspace = true } @@ -39,5 +40,5 @@ default = ["std"] std = [ "itertools/use_std", "either/use_std", - "ir/std" + "ink_env/std", ] diff --git a/crates/ink/macro/Cargo.toml b/crates/ink/macro/Cargo.toml index e6e785f382..31813b4cb7 100644 --- a/crates/ink/macro/Cargo.toml +++ b/crates/ink/macro/Cargo.toml @@ -43,4 +43,5 @@ std = [ "scale/std", "ink_ir/std", "ink_primitives/std", + "ink_codegen/std", ] From 2d1950a6d46c257c058550ea031aeea57abceb3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Fri, 27 Oct 2023 18:59:29 -0300 Subject: [PATCH 08/44] Updated stderr test files. --- .../fail/constructor-input-non-codec.stderr | 20 +++++--------- .../constructor-return-result-invalid.stderr | 2 +- ...uctor-return-result-non-codec-error.stderr | 27 +++++++------------ .../fail/constructor-self-receiver-03.stderr | 2 +- .../fail/message-input-non-codec.stderr | 22 ++++++--------- .../fail/message-returns-non-codec.stderr | 16 ++++------- ...packed_is_not_derived_automatically.stderr | 12 ++++----- .../fail/message_input_non_codec.stderr | 20 +++++--------- .../fail/message_output_non_codec.stderr | 13 ++++----- 9 files changed, 49 insertions(+), 85 deletions(-) diff --git a/crates/ink/tests/ui/contract/fail/constructor-input-non-codec.stderr b/crates/ink/tests/ui/contract/fail/constructor-input-non-codec.stderr index 6889d1639f..852fdefd45 100644 --- a/crates/ink/tests/ui/contract/fail/constructor-input-non-codec.stderr +++ b/crates/ink/tests/ui/contract/fail/constructor-input-non-codec.stderr @@ -5,16 +5,13 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeDecode` is not satisfied | ^^^^^^ the trait `WrapperTypeDecode` is not implemented for `NonCodecType` | = help: the following other types implement trait `WrapperTypeDecode`: + Arc Box Rc - Arc = note: required for `NonCodecType` to implement `ink::parity_scale_codec::Decode` note: required by a bound in `DispatchInput` --> src/codegen/dispatch/type_check.rs | - | pub struct DispatchInput(T) - | ------------- required by a bound in this struct - | where | T: scale::Decode + 'static; | ^^^^^^^^^^^^^ required by this bound in `DispatchInput` @@ -25,9 +22,9 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeDecode` is not satisfied | ^^^ the trait `WrapperTypeDecode` is not implemented for `NonCodecType` | = help: the following other types implement trait `WrapperTypeDecode`: + Arc Box Rc - Arc = note: required for `NonCodecType` to implement `ink::parity_scale_codec::Decode` error[E0277]: the trait bound `NonCodecType: WrapperTypeEncode` is not satisfied @@ -40,21 +37,18 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeEncode` is not satisfied | --- required by a bound introduced by this call | = help: the following other types implement trait `WrapperTypeEncode`: + &T + &mut T + Arc Box Cow<'a, T> - ink::parity_scale_codec::Ref<'a, T, U> Rc - Arc - Vec String - &T - &mut T + Vec + ink::parity_scale_codec::Ref<'a, T, U> = note: required for `NonCodecType` to implement `Encode` note: required by a bound in `ExecutionInput::>::push_arg` --> $WORKSPACE/crates/env/src/call/execution_input.rs | - | pub fn push_arg( - | -------- required by a bound in this associated function -... | T: scale::Encode, | ^^^^^^^^^^^^^ required by this bound in `ExecutionInput::>::push_arg` diff --git a/crates/ink/tests/ui/contract/fail/constructor-return-result-invalid.stderr b/crates/ink/tests/ui/contract/fail/constructor-return-result-invalid.stderr index c09f9af224..7101544b93 100644 --- a/crates/ink/tests/ui/contract/fail/constructor-return-result-invalid.stderr +++ b/crates/ink/tests/ui/contract/fail/constructor-return-result-invalid.stderr @@ -5,5 +5,5 @@ error[E0277]: the trait bound `ConstructorOutputValue` is not implemented for `ConstructorOutputValue>` | = help: the following other types implement trait `ConstructorOutput`: - ConstructorOutputValue> ConstructorOutputValue + ConstructorOutputValue> diff --git a/crates/ink/tests/ui/contract/fail/constructor-return-result-non-codec-error.stderr b/crates/ink/tests/ui/contract/fail/constructor-return-result-non-codec-error.stderr index ba04fb8f65..5917e23164 100644 --- a/crates/ink/tests/ui/contract/fail/constructor-return-result-non-codec-error.stderr +++ b/crates/ink/tests/ui/contract/fail/constructor-return-result-non-codec-error.stderr @@ -8,9 +8,6 @@ error[E0277]: the trait bound `Result, LangError>: note: required by a bound in `return_value` --> $WORKSPACE/crates/env/src/api.rs | - | pub fn return_value(return_flags: ReturnFlags, return_value: &R) -> ! - | ------------ required by a bound in this function - | where | R: scale::Encode, | ^^^^^^^^^^^^^ required by this bound in `return_value` @@ -21,17 +18,14 @@ error[E0277]: the trait bound `contract::Error: WrapperTypeDecode` is not satisf | ^^^ the trait `WrapperTypeDecode` is not implemented for `contract::Error` | = help: the following other types implement trait `WrapperTypeDecode`: + Arc Box Rc - Arc = note: required for `contract::Error` to implement `ink::parity_scale_codec::Decode` = note: required for `Result` to implement `ConstructorReturnType` note: required by a bound in `CreateBuilder::>>::returns` --> $WORKSPACE/crates/env/src/call/create_builder.rs | - | pub fn returns( - | ------- required by a bound in this associated function -... | R: ConstructorReturnType, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `CreateBuilder::>>::returns` @@ -42,14 +36,14 @@ error[E0277]: the trait bound `contract::Error: TypeInfo` is not satisfied | ^^^^^^^^ the trait `TypeInfo` is not implemented for `contract::Error` | = help: the following other types implement trait `TypeInfo`: - bool - char - i8 - i16 - i32 - i64 - i128 - u8 + &T + &mut T + () + (A, B) + (A, B, C) + (A, B, C, D) + (A, B, C, D, E) + (A, B, C, D, E, F) and $N others = note: required for `Result<(), contract::Error>` to implement `TypeInfo` = note: 1 redundant requirement hidden @@ -57,8 +51,5 @@ error[E0277]: the trait bound `contract::Error: TypeInfo` is not satisfied note: required by a bound in `TypeSpec::with_name_str` --> $WORKSPACE/crates/metadata/src/specs.rs | - | pub fn with_name_str(display_name: &'static str) -> Self - | ------------- required by a bound in this associated function - | where | T: TypeInfo + 'static, | ^^^^^^^^ required by this bound in `TypeSpec::with_name_str` diff --git a/crates/ink/tests/ui/contract/fail/constructor-self-receiver-03.stderr b/crates/ink/tests/ui/contract/fail/constructor-self-receiver-03.stderr index 2f261fa67c..eea8a1c23b 100644 --- a/crates/ink/tests/ui/contract/fail/constructor-self-receiver-03.stderr +++ b/crates/ink/tests/ui/contract/fail/constructor-self-receiver-03.stderr @@ -29,7 +29,7 @@ error[E0277]: the trait bound `&Contract: WrapperTypeDecode` is not satisfied | ^^^ the trait `WrapperTypeDecode` is not implemented for `&Contract` | = help: the following other types implement trait `WrapperTypeDecode`: + Arc Box Rc - Arc = note: required for `&Contract` to implement `ink::parity_scale_codec::Decode` diff --git a/crates/ink/tests/ui/contract/fail/message-input-non-codec.stderr b/crates/ink/tests/ui/contract/fail/message-input-non-codec.stderr index 3eff91fc43..992da8a93c 100644 --- a/crates/ink/tests/ui/contract/fail/message-input-non-codec.stderr +++ b/crates/ink/tests/ui/contract/fail/message-input-non-codec.stderr @@ -5,16 +5,13 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeDecode` is not satisfied | ^^^^^^ the trait `WrapperTypeDecode` is not implemented for `NonCodecType` | = help: the following other types implement trait `WrapperTypeDecode`: + Arc Box Rc - Arc = note: required for `NonCodecType` to implement `ink::parity_scale_codec::Decode` note: required by a bound in `DispatchInput` --> src/codegen/dispatch/type_check.rs | - | pub struct DispatchInput(T) - | ------------- required by a bound in this struct - | where | T: scale::Decode + 'static; | ^^^^^^^^^^^^^ required by this bound in `DispatchInput` @@ -25,9 +22,9 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeDecode` is not satisfied | ^^^ the trait `WrapperTypeDecode` is not implemented for `NonCodecType` | = help: the following other types implement trait `WrapperTypeDecode`: + Arc Box Rc - Arc = note: required for `NonCodecType` to implement `ink::parity_scale_codec::Decode` error[E0277]: the trait bound `NonCodecType: WrapperTypeEncode` is not satisfied @@ -40,22 +37,19 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeEncode` is not satisfied | --- required by a bound introduced by this call | = help: the following other types implement trait `WrapperTypeEncode`: + &T + &mut T + Arc Box Cow<'a, T> - ink::parity_scale_codec::Ref<'a, T, U> Rc - Arc - Vec String - &T - &mut T + Vec + ink::parity_scale_codec::Ref<'a, T, U> = note: required for `NonCodecType` to implement `Encode` note: required by a bound in `ExecutionInput::>::push_arg` --> $WORKSPACE/crates/env/src/call/execution_input.rs | - | pub fn push_arg( - | -------- required by a bound in this associated function -... | T: scale::Encode, | ^^^^^^^^^^^^^ required by this bound in `ExecutionInput::>::push_arg` @@ -71,4 +65,4 @@ error[E0599]: the method `try_invoke` exists for struct `CallBuilder, ArgumentList>: Encode` + `ArgumentList, ArgumentList>: Encode` diff --git a/crates/ink/tests/ui/contract/fail/message-returns-non-codec.stderr b/crates/ink/tests/ui/contract/fail/message-returns-non-codec.stderr index 3474db6f08..754cc3744f 100644 --- a/crates/ink/tests/ui/contract/fail/message-returns-non-codec.stderr +++ b/crates/ink/tests/ui/contract/fail/message-returns-non-codec.stderr @@ -5,22 +5,19 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeEncode` is not satisfied | ^^^^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `NonCodecType` | = help: the following other types implement trait `WrapperTypeEncode`: + &T + &mut T + Arc Box Cow<'a, T> - ink::parity_scale_codec::Ref<'a, T, U> Rc - Arc - Vec String - &T - &mut T + Vec + ink::parity_scale_codec::Ref<'a, T, U> = note: required for `NonCodecType` to implement `Encode` note: required by a bound in `DispatchOutput` --> src/codegen/dispatch/type_check.rs | - | pub struct DispatchOutput(T) - | -------------- required by a bound in this struct - | where | T: scale::Encode + 'static; | ^^^^^^^^^^^^^ required by this bound in `DispatchOutput` @@ -34,9 +31,6 @@ error[E0277]: the trait bound `Result: Encode` is not s note: required by a bound in `return_value` --> $WORKSPACE/crates/env/src/api.rs | - | pub fn return_value(return_flags: ReturnFlags, return_value: &R) -> ! - | ------------ required by a bound in this function - | where | R: scale::Encode, | ^^^^^^^^^^^^^ required by this bound in `return_value` diff --git a/crates/ink/tests/ui/storage_item/fail/packed_is_not_derived_automatically.stderr b/crates/ink/tests/ui/storage_item/fail/packed_is_not_derived_automatically.stderr index 4863fb334b..ad0c10fe99 100644 --- a/crates/ink/tests/ui/storage_item/fail/packed_is_not_derived_automatically.stderr +++ b/crates/ink/tests/ui/storage_item/fail/packed_is_not_derived_automatically.stderr @@ -5,9 +5,9 @@ error[E0277]: the trait bound `NonPacked: WrapperTypeDecode` is not satisfied | ^^^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `NonPacked` | = help: the following other types implement trait `WrapperTypeDecode`: + Arc Box Rc - Arc = note: required for `NonPacked` to implement `ink::parity_scale_codec::Decode` = note: required for `NonPacked` to implement `Packed` note: required by a bound in `consume_packed` @@ -23,15 +23,15 @@ error[E0277]: the trait bound `NonPacked: WrapperTypeEncode` is not satisfied | ^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `NonPacked` | = help: the following other types implement trait `WrapperTypeEncode`: + &T + &mut T + Arc Box Cow<'a, T> - ink::parity_scale_codec::Ref<'a, T, U> Rc - Arc - Vec String - &T - &mut T + Vec + ink::parity_scale_codec::Ref<'a, T, U> = note: required for `NonPacked` to implement `Encode` = note: required for `NonPacked` to implement `Packed` note: required by a bound in `consume_packed` diff --git a/crates/ink/tests/ui/trait_def/fail/message_input_non_codec.stderr b/crates/ink/tests/ui/trait_def/fail/message_input_non_codec.stderr index 775914c95b..1f7a0c1e89 100644 --- a/crates/ink/tests/ui/trait_def/fail/message_input_non_codec.stderr +++ b/crates/ink/tests/ui/trait_def/fail/message_input_non_codec.stderr @@ -5,16 +5,13 @@ error[E0277]: the trait bound `NonCodec: WrapperTypeDecode` is not satisfied | ^^^^^ the trait `WrapperTypeDecode` is not implemented for `NonCodec` | = help: the following other types implement trait `WrapperTypeDecode`: + Arc Box Rc - Arc = note: required for `NonCodec` to implement `ink::parity_scale_codec::Decode` note: required by a bound in `DispatchInput` --> src/codegen/dispatch/type_check.rs | - | pub struct DispatchInput(T) - | ------------- required by a bound in this struct - | where | T: scale::Decode + 'static; | ^^^^^^^^^^^^^ required by this bound in `DispatchInput` @@ -28,22 +25,19 @@ error[E0277]: the trait bound `NonCodec: WrapperTypeEncode` is not satisfied | - required by a bound introduced by this call | = help: the following other types implement trait `WrapperTypeEncode`: + &T + &mut T + Arc Box Cow<'a, T> - ink::parity_scale_codec::Ref<'a, T, U> Rc - Arc - Vec String - &T - &mut T + Vec + ink::parity_scale_codec::Ref<'a, T, U> = note: required for `NonCodec` to implement `Encode` note: required by a bound in `ExecutionInput::>::push_arg` --> $WORKSPACE/crates/env/src/call/execution_input.rs | - | pub fn push_arg( - | -------- required by a bound in this associated function -... | T: scale::Encode, | ^^^^^^^^^^^^^ required by this bound in `ExecutionInput::>::push_arg` @@ -59,4 +53,4 @@ error[E0599]: the method `try_invoke` exists for struct `CallBuilder, ArgumentList>: Encode` + `ArgumentList, ArgumentList>: Encode` diff --git a/crates/ink/tests/ui/trait_def/fail/message_output_non_codec.stderr b/crates/ink/tests/ui/trait_def/fail/message_output_non_codec.stderr index 983b1b3b88..3f52f0fe96 100644 --- a/crates/ink/tests/ui/trait_def/fail/message_output_non_codec.stderr +++ b/crates/ink/tests/ui/trait_def/fail/message_output_non_codec.stderr @@ -5,22 +5,19 @@ error[E0277]: the trait bound `NonCodec: WrapperTypeEncode` is not satisfied | ^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `NonCodec` | = help: the following other types implement trait `WrapperTypeEncode`: + &T + &mut T + Arc Box Cow<'a, T> - ink::parity_scale_codec::Ref<'a, T, U> Rc - Arc - Vec String - &T - &mut T + Vec + ink::parity_scale_codec::Ref<'a, T, U> = note: required for `NonCodec` to implement `Encode` note: required by a bound in `DispatchOutput` --> src/codegen/dispatch/type_check.rs | - | pub struct DispatchOutput(T) - | -------------- required by a bound in this struct - | where | T: scale::Encode + 'static; | ^^^^^^^^^^^^^ required by this bound in `DispatchOutput` From 2d13b218145a18a20238626c160799cc8d52c8c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Fri, 27 Oct 2023 19:27:32 -0300 Subject: [PATCH 09/44] Updated CHANGELOG. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71543f99cc..1c9bca7643 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [E2E] Call builders and extra gas margin option - [#1917](https://github.com/paritytech/ink/pull/1917) - Make `set_code_hash` generic - [#1906](https://github.com/paritytech/ink/pull/1906) - Clean E2E configuration parsing - [#1922](https://github.com/paritytech/ink/pull/1922) +- Implement instantiate_contract() in off-chain environment engine - [#1957](https://github.com/paritytech/ink/pull/1957) ### Changed - Fail when decoding from storage and not all bytes consumed - [#1897](https://github.com/paritytech/ink/pull/1897) From 817f3ccf557c2ede367f8645508160caccb98226 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Fri, 27 Oct 2023 19:30:56 -0300 Subject: [PATCH 10/44] Passed through rustfmt. --- crates/env/src/api.rs | 14 +++++++------- crates/env/src/backend.rs | 7 ++++--- crates/env/src/call/create_builder.rs | 6 ++++-- crates/env/src/contract.rs | 2 +- crates/env/src/engine/off_chain/impls.rs | 14 +++++++++----- crates/env/src/engine/off_chain/mod.rs | 2 +- crates/env/src/lib.rs | 2 +- crates/env/src/reflect/trait_def/registry.rs | 2 +- crates/ink/codegen/src/generator/dispatch.rs | 5 +++-- crates/ink/src/env_access.rs | 3 ++- crates/ink/src/lib.rs | 2 +- 11 files changed, 34 insertions(+), 25 deletions(-) diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index 9132ef38f0..43636050ee 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -205,7 +205,7 @@ where /// Same as set_contract_storage(), but gets the key from a function pointer. /// This is necessary for integration tests, because we can't get the key from /// the type declaration. -#[cfg(feature="test_instantiate")] +#[cfg(feature = "test_instantiate")] pub fn set_contract_storage_test(value: &V) -> Option where V: Storable, @@ -218,9 +218,8 @@ where /// Dummy set_contract_storage_test() for non-test environments. The compiler /// should optimize this away. -#[cfg(not(feature="test_instantiate"))] -pub fn set_contract_storage_test(_value: &V) -> Option -{ +#[cfg(not(feature = "test_instantiate"))] +pub fn set_contract_storage_test(_value: &V) -> Option { None } @@ -359,7 +358,8 @@ pub fn instantiate_contract( where E: Environment, ContractRef: FromAccountId + crate::contract::ContractReverseReference, - ::Type: crate::reflect::ContractConstructorDecoder, + ::Type: + crate::reflect::ContractConstructorDecoder, Args: scale::Encode, Salt: AsRef<[u8]>, R: ConstructorReturnType, @@ -449,7 +449,7 @@ where /// # Note /// /// This function stops the execution of the contract immediately. -#[cfg(not(feature="test_instantiate"))] +#[cfg(not(feature = "test_instantiate"))] pub fn return_value(return_flags: ReturnFlags, return_value: &R) -> ! where R: scale::Encode, @@ -465,7 +465,7 @@ where /// /// When the test_instantiate feature is used, the contract is allowed to /// return normally. This feature should only be used for integration tests. -#[cfg(feature="test_instantiate")] +#[cfg(feature = "test_instantiate")] pub fn return_value(return_flags: ReturnFlags, return_value: &R) -> () where R: scale::Encode, diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index 22b29c84c8..1d0f5fddab 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -247,7 +247,7 @@ pub trait EnvBackend { /// /// The `flags` parameter can be used to revert the state changes of the /// entire execution if necessary. - #[cfg(not(feature="test_instantiate"))] + #[cfg(not(feature = "test_instantiate"))] fn return_value(&mut self, flags: ReturnFlags, return_value: &R) -> ! where R: scale::Encode; @@ -261,7 +261,7 @@ pub trait EnvBackend { /// /// The `flags` parameter can be used to revert the state changes of the /// entire execution if necessary. - #[cfg(feature="test_instantiate")] + #[cfg(feature = "test_instantiate")] fn return_value(&mut self, flags: ReturnFlags, return_value: &R) -> () where R: scale::Encode; @@ -485,7 +485,8 @@ pub trait TypedEnvBackend: EnvBackend { where E: Environment, ContractRef: FromAccountId + crate::contract::ContractReverseReference, - ::Type: crate::reflect::ContractConstructorDecoder, + ::Type: + crate::reflect::ContractConstructorDecoder, Args: scale::Encode, Salt: AsRef<[u8]>, R: ConstructorReturnType; diff --git a/crates/env/src/call/create_builder.rs b/crates/env/src/call/create_builder.rs index 3ae1fe1fc9..50fd65bc34 100644 --- a/crates/env/src/call/create_builder.rs +++ b/crates/env/src/call/create_builder.rs @@ -241,7 +241,8 @@ impl CreateParams where E: Environment, ContractRef: FromAccountId + crate::contract::ContractReverseReference, - ::Type: crate::reflect::ContractConstructorDecoder, + ::Type: + crate::reflect::ContractConstructorDecoder, Args: scale::Encode, Salt: AsRef<[u8]>, R: ConstructorReturnType, @@ -723,7 +724,8 @@ impl where E: Environment, ContractRef: FromAccountId + crate::contract::ContractReverseReference, - ::Type: crate::reflect::ContractConstructorDecoder, + ::Type: + crate::reflect::ContractConstructorDecoder, GasLimit: Unwrap, Args: scale::Encode, Salt: AsRef<[u8]>, diff --git a/crates/env/src/contract.rs b/crates/env/src/contract.rs index 319a2aaf96..5c3f3d65ea 100644 --- a/crates/env/src/contract.rs +++ b/crates/env/src/contract.rs @@ -142,7 +142,7 @@ pub trait ContractReference { /// Refers back to the original contract from the generated ink! smart contract /// reference type. -pub trait ContractReverseReference{ +pub trait ContractReverseReference { /// The original contract type. type Type; } diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index edca40d222..ba56fbd4b6 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -251,7 +251,7 @@ impl EnvBackend for EnvInstance { unimplemented!("the off-chain env does not implement `input`") } - #[cfg(not(feature="test_instantiate"))] + #[cfg(not(feature = "test_instantiate"))] fn return_value(&mut self, _flags: ReturnFlags, _return_value: &R) -> ! where R: scale::Encode, @@ -259,7 +259,7 @@ impl EnvBackend for EnvInstance { panic!("enable feature test_instantiate to use return_value()") } - #[cfg(feature="test_instantiate")] + #[cfg(feature = "test_instantiate")] fn return_value(&mut self, _flags: ReturnFlags, return_value: &R) -> () where R: scale::Encode, @@ -510,7 +510,8 @@ impl TypedEnvBackend for EnvInstance { where E: Environment, ContractRef: FromAccountId + crate::contract::ContractReverseReference, - ::Type: crate::reflect::ContractConstructorDecoder, + ::Type: + crate::reflect::ContractConstructorDecoder, Args: scale::Encode, Salt: AsRef<[u8]>, R: ConstructorReturnType, @@ -536,8 +537,11 @@ impl TypedEnvBackend for EnvInstance { crate::reflect::ExecuteDispatchable::execute_dispatchable(dispatch) .unwrap_or_else(|e| panic!("Constructor call failed: {:?}", e)); - let id = ::AccountId::decode(&mut &(vec![0_u8; 32][..])).unwrap(); - Ok(Ok(R::ok(>::from_account_id(id)))) + let id = + ::AccountId::decode(&mut &(vec![0_u8; 32][..])).unwrap(); + Ok(Ok(R::ok( + >::from_account_id(id), + ))) } fn terminate_contract(&mut self, beneficiary: E::AccountId) -> ! diff --git a/crates/env/src/engine/off_chain/mod.rs b/crates/env/src/engine/off_chain/mod.rs index 5ceb4a1313..589b794df1 100644 --- a/crates/env/src/engine/off_chain/mod.rs +++ b/crates/env/src/engine/off_chain/mod.rs @@ -46,7 +46,7 @@ impl OnInstance for EnvInstance { } ) ); - INSTANCE.with(|instance| f(unsafe{ &mut *instance.as_ptr() })) + INSTANCE.with(|instance| f(unsafe { &mut *instance.as_ptr() })) } } diff --git a/crates/env/src/lib.rs b/crates/env/src/lib.rs index 351c15eb73..1204475cfa 100644 --- a/crates/env/src/lib.rs +++ b/crates/env/src/lib.rs @@ -91,10 +91,10 @@ pub mod chain_extension; mod contract; mod engine; mod error; -pub mod reflect; #[doc(hidden)] pub mod event; pub mod hash; +pub mod reflect; mod types; #[cfg(test)] diff --git a/crates/env/src/reflect/trait_def/registry.rs b/crates/env/src/reflect/trait_def/registry.rs index 5c47419b7d..dc1cc1683c 100644 --- a/crates/env/src/reflect/trait_def/registry.rs +++ b/crates/env/src/reflect/trait_def/registry.rs @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use core::marker::PhantomData; use crate::ContractEnv; +use core::marker::PhantomData; /// Type that is guaranteed by ink! to implement all ink! trait definitions. /// diff --git a/crates/ink/codegen/src/generator/dispatch.rs b/crates/ink/codegen/src/generator/dispatch.rs index 6833c0ce18..49453ea081 100644 --- a/crates/ink/codegen/src/generator/dispatch.rs +++ b/crates/ink/codegen/src/generator/dispatch.rs @@ -476,7 +476,8 @@ impl Dispatch<'_> { let span = self.contract.module().storage().span(); let storage_ident = self.contract.module().storage().ident(); - let ref_ident = quote::format_ident!("{}Ref", self.contract.module().storage().ident()); + let ref_ident = + quote::format_ident!("{}Ref", self.contract.module().storage().ident()); let constructors_variants = constructors.iter().enumerate().map(|(index, item)| { let constructor_span = item.constructor.span(); @@ -602,7 +603,7 @@ impl Dispatch<'_> { // dispatch logic so `Ok` is always returned to the caller. &::ink::ConstructorResult::Ok(output_result.map(|_| ())), ); - + #[cfg(feature="test_instantiate")] Ok(()) } diff --git a/crates/ink/src/env_access.rs b/crates/ink/src/env_access.rs index 1a1a336437..ad17a9df18 100644 --- a/crates/ink/src/env_access.rs +++ b/crates/ink/src/env_access.rs @@ -500,7 +500,8 @@ where > where ContractRef: FromAccountId + ink_env::ContractReverseReference, - ::Type: ink_env::reflect::ContractConstructorDecoder, + ::Type: + ink_env::reflect::ContractConstructorDecoder, Args: scale::Encode, Salt: AsRef<[u8]>, R: ConstructorReturnType, diff --git a/crates/ink/src/lib.rs b/crates/ink/src/lib.rs index 0af35c2bbb..3e3fc5af56 100644 --- a/crates/ink/src/lib.rs +++ b/crates/ink/src/lib.rs @@ -29,7 +29,7 @@ pub mod result_info; #[cfg_attr(not(feature = "show-codegen-docs"), doc(hidden))] pub mod codegen; -pub use ink_env::reflect as reflect; +pub use ink_env::reflect; mod chain_extension; mod contract_ref; From 6c4efc63534b4b3260b118ed9f0babb7c3711739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Fri, 27 Oct 2023 19:38:33 -0300 Subject: [PATCH 11/44] Passed through clippy. --- crates/env/src/api.rs | 4 ++-- crates/env/src/backend.rs | 2 +- crates/env/src/engine/off_chain/impls.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index 43636050ee..f4d6bd257f 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -211,7 +211,7 @@ where V: Storable, Ref: ink_storage_traits::StorageLayout, { - let x = Ref::layout as u64; + let x = Ref::layout as usize; let x = ((x | (x >> 32)) & 0xFFFFFFFF) as u32; set_contract_storage(&x, value) } @@ -466,7 +466,7 @@ where /// When the test_instantiate feature is used, the contract is allowed to /// return normally. This feature should only be used for integration tests. #[cfg(feature = "test_instantiate")] -pub fn return_value(return_flags: ReturnFlags, return_value: &R) -> () +pub fn return_value(return_flags: ReturnFlags, return_value: &R) where R: scale::Encode, { diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index 1d0f5fddab..9301f30423 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -262,7 +262,7 @@ pub trait EnvBackend { /// The `flags` parameter can be used to revert the state changes of the /// entire execution if necessary. #[cfg(feature = "test_instantiate")] - fn return_value(&mut self, flags: ReturnFlags, return_value: &R) -> () + fn return_value(&mut self, flags: ReturnFlags, return_value: &R) where R: scale::Encode; diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index ba56fbd4b6..c19d67881d 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -260,7 +260,7 @@ impl EnvBackend for EnvInstance { } #[cfg(feature = "test_instantiate")] - fn return_value(&mut self, _flags: ReturnFlags, return_value: &R) -> () + fn return_value(&mut self, _flags: ReturnFlags, return_value: &R) where R: scale::Encode, { From 25e18104a00a6d75bcc984ce483f2b923fda49ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Mon, 30 Oct 2023 15:15:36 -0300 Subject: [PATCH 12/44] Passed through rustfmt again. --- .../src/generator/trait_def/trait_registry.rs | 4 +++- crates/ink/ir/src/ir/attrs.rs | 4 +++- integration-tests/instantiate-contract/lib.rs | 13 +++++++++---- .../instantiate-contract/other_contract/lib.rs | 8 +++----- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/crates/ink/codegen/src/generator/trait_def/trait_registry.rs b/crates/ink/codegen/src/generator/trait_def/trait_registry.rs index 6d6471e53e..b0fe1a25bd 100644 --- a/crates/ink/codegen/src/generator/trait_def/trait_registry.rs +++ b/crates/ink/codegen/src/generator/trait_def/trait_registry.rs @@ -21,7 +21,9 @@ use super::TraitDefinition; use crate::{ - generator::{self,}, + generator::{ + self, + }, traits::GenerateCode, EnforcedErrors, }; diff --git a/crates/ink/ir/src/ir/attrs.rs b/crates/ink/ir/src/ir/attrs.rs index 4cd8320f43..100efa0654 100644 --- a/crates/ink/ir/src/ir/attrs.rs +++ b/crates/ink/ir/src/ir/attrs.rs @@ -32,7 +32,9 @@ use syn::{ }; use crate::{ - ast::{self,}, + ast::{ + self, + }, error::ExtError as _, ir, ir::{ diff --git a/integration-tests/instantiate-contract/lib.rs b/integration-tests/instantiate-contract/lib.rs index 6b7aa4cdbf..b628dd9df1 100644 --- a/integration-tests/instantiate-contract/lib.rs +++ b/integration-tests/instantiate-contract/lib.rs @@ -67,7 +67,9 @@ mod instantiate_contract { type E2EResult = std::result::Result>; #[ink_e2e::test(additional_contracts = "other_contract/Cargo.toml")] - async fn instantiate_other_contract(mut client: ink_e2e::Client) -> E2EResult<()> { + async fn instantiate_other_contract( + mut client: ink_e2e::Client, + ) -> E2EResult<()> { let constructor = InstantiateContractRef::new(); let contract_acc_id = client @@ -88,9 +90,12 @@ mod instantiate_contract { .expect("instantiate failed") .code_hash; - let instantiate_other_contract = - build_message::(contract_acc_id.clone()) - .call(|contract| contract.instantiate_other_contract(other_contract_code_hash)); + let instantiate_other_contract = build_message::( + contract_acc_id.clone(), + ) + .call(|contract| { + contract.instantiate_other_contract(other_contract_code_hash) + }); let instantiate_other_contract_res = client .call_dry_run(&ink_e2e::bob(), &instantiate_other_contract, 0, None) diff --git a/integration-tests/instantiate-contract/other_contract/lib.rs b/integration-tests/instantiate-contract/other_contract/lib.rs index f0dce841de..ab96aea2e7 100644 --- a/integration-tests/instantiate-contract/other_contract/lib.rs +++ b/integration-tests/instantiate-contract/other_contract/lib.rs @@ -14,18 +14,16 @@ mod other_contract { /// Creates a new Template contract. #[ink(constructor)] pub fn new() -> Self { - Self { - x: 42, - } + Self { x: 42 } } #[ink(message)] - pub fn set_x(&mut self, x: u32){ + pub fn set_x(&mut self, x: u32) { self.x = x; } #[ink(message)] - pub fn get_x(&self) -> u32{ + pub fn get_x(&self) -> u32 { self.x } From 3042f4df31c69ca1718b0e656faebb87ab36e089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Tue, 31 Oct 2023 02:18:14 -0300 Subject: [PATCH 13/44] Fixed failing contract builds. Moved reflection, contract, arithmetic, and miscellaneous types from ink_env to ink_primitives. --- crates/env/src/api.rs | 10 +- crates/env/src/backend.rs | 6 +- crates/env/src/call/call_builder.rs | 6 +- crates/env/src/call/create_builder.rs | 10 +- crates/env/src/engine/mod.rs | 4 +- crates/env/src/engine/off_chain/impls.rs | 8 +- crates/env/src/engine/off_chain/test_api.rs | 2 +- crates/env/src/engine/on_chain/impls.rs | 2 +- crates/env/src/event.rs | 2 +- crates/env/src/lib.rs | 22 +- crates/env/src/types.rs | 224 ------------------ crates/ink/codegen/Cargo.toml | 2 - crates/ink/codegen/src/lib.rs | 2 +- crates/primitives/Cargo.toml | 2 + crates/{env => primitives}/src/arithmetic.rs | 0 crates/{env => primitives}/src/contract.rs | 0 crates/primitives/src/lib.rs | 6 +- .../src/reflect/contract.rs | 0 .../src/reflect/dispatch.rs | 0 .../{env => primitives}/src/reflect/event.rs | 0 crates/{env => primitives}/src/reflect/mod.rs | 0 .../src/reflect/trait_def/info.rs | 0 .../src/reflect/trait_def/mod.rs | 0 .../src/reflect/trait_def/registry.rs | 2 +- crates/primitives/src/types.rs | 184 ++++++++++++++ 25 files changed, 233 insertions(+), 261 deletions(-) delete mode 100644 crates/env/src/types.rs rename crates/{env => primitives}/src/arithmetic.rs (100%) rename crates/{env => primitives}/src/contract.rs (100%) rename crates/{env => primitives}/src/reflect/contract.rs (100%) rename crates/{env => primitives}/src/reflect/dispatch.rs (100%) rename crates/{env => primitives}/src/reflect/event.rs (100%) rename crates/{env => primitives}/src/reflect/mod.rs (100%) rename crates/{env => primitives}/src/reflect/trait_def/info.rs (100%) rename crates/{env => primitives}/src/reflect/trait_def/mod.rs (100%) rename crates/{env => primitives}/src/reflect/trait_def/registry.rs (98%) diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index f4d6bd257f..8aa235d322 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -37,8 +37,10 @@ use crate::{ CryptoHash, HashOutput, }, - types::Gas, - Environment, + types::{ + Environment, + Gas, + }, Result, }; use ink_storage_traits::Storable; @@ -357,8 +359,8 @@ pub fn instantiate_contract( > where E: Environment, - ContractRef: FromAccountId + crate::contract::ContractReverseReference, - ::Type: + ContractRef: FromAccountId + crate::ContractReverseReference, + ::Type: crate::reflect::ContractConstructorDecoder, Args: scale::Encode, Salt: AsRef<[u8]>, diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index 9301f30423..7756e79fbc 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -26,7 +26,7 @@ use crate::{ CryptoHash, HashOutput, }, - Environment, + types::Environment, Result, }; use ink_storage_traits::Storable; @@ -484,8 +484,8 @@ pub trait TypedEnvBackend: EnvBackend { > where E: Environment, - ContractRef: FromAccountId + crate::contract::ContractReverseReference, - ::Type: + ContractRef: FromAccountId + crate::ContractReverseReference, + ::Type: crate::reflect::ContractConstructorDecoder, Args: scale::Encode, Salt: AsRef<[u8]>, diff --git a/crates/env/src/call/call_builder.rs b/crates/env/src/call/call_builder.rs index c5e803a25d..06194ba389 100644 --- a/crates/env/src/call/call_builder.rs +++ b/crates/env/src/call/call_builder.rs @@ -23,8 +23,10 @@ use crate::{ }, ExecutionInput, }, - types::Gas, - Environment, + types::{ + Environment, + Gas, + }, Error, }; use core::marker::PhantomData; diff --git a/crates/env/src/call/create_builder.rs b/crates/env/src/call/create_builder.rs index 50fd65bc34..aefad28d65 100644 --- a/crates/env/src/call/create_builder.rs +++ b/crates/env/src/call/create_builder.rs @@ -24,8 +24,8 @@ use crate::{ ExecutionInput, Selector, }, + types::Environment, ContractEnv, - Environment, Error, }; use core::marker::PhantomData; @@ -240,8 +240,8 @@ where impl CreateParams where E: Environment, - ContractRef: FromAccountId + crate::contract::ContractReverseReference, - ::Type: + ContractRef: FromAccountId + crate::ContractReverseReference, + ::Type: crate::reflect::ContractConstructorDecoder, Args: scale::Encode, Salt: AsRef<[u8]>, @@ -723,8 +723,8 @@ impl > where E: Environment, - ContractRef: FromAccountId + crate::contract::ContractReverseReference, - ::Type: + ContractRef: FromAccountId + crate::ContractReverseReference, + ::Type: crate::reflect::ContractConstructorDecoder, GasLimit: Unwrap, Args: scale::Encode, diff --git a/crates/env/src/engine/mod.rs b/crates/env/src/engine/mod.rs index 3d94f99678..256c2393d6 100644 --- a/crates/env/src/engine/mod.rs +++ b/crates/env/src/engine/mod.rs @@ -77,7 +77,7 @@ pub(crate) fn decode_instantiate_result( ) -> EnvResult>::Output>> where I: scale::Input, - E: crate::Environment, + E: crate::types::Environment, ContractRef: FromAccountId, R: ConstructorReturnType, { @@ -102,7 +102,7 @@ fn decode_instantiate_err( ) -> EnvResult>::Output>> where I: scale::Input, - E: crate::Environment, + E: crate::types::Environment, ContractRef: FromAccountId, R: ConstructorReturnType, { diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index c19d67881d..cda57bde43 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -34,9 +34,9 @@ use crate::{ Keccak256, Sha2x256, }, + types::Environment, Clear, EnvBackend, - Environment, Error, Result, ReturnFlags, @@ -509,8 +509,8 @@ impl TypedEnvBackend for EnvInstance { > where E: Environment, - ContractRef: FromAccountId + crate::contract::ContractReverseReference, - ::Type: + ContractRef: FromAccountId + crate::ContractReverseReference, + ::Type: crate::reflect::ContractConstructorDecoder, Args: scale::Encode, Salt: AsRef<[u8]>, @@ -527,7 +527,7 @@ impl TypedEnvBackend for EnvInstance { < < ContractRef - as crate::contract::ContractReverseReference + as crate::ContractReverseReference >::Type as crate::reflect::ContractConstructorDecoder >::Type diff --git a/crates/env/src/engine/off_chain/test_api.rs b/crates/env/src/engine/off_chain/test_api.rs index b36c58d225..7e00c335b8 100644 --- a/crates/env/src/engine/off_chain/test_api.rs +++ b/crates/env/src/engine/off_chain/test_api.rs @@ -19,7 +19,7 @@ use super::{ OnInstance, }; use crate::{ - Environment, + types::Environment, Result, }; use core::fmt::Debug; diff --git a/crates/env/src/engine/on_chain/impls.rs b/crates/env/src/engine/on_chain/impls.rs index 3c5df7613e..54f77cb419 100644 --- a/crates/env/src/engine/on_chain/impls.rs +++ b/crates/env/src/engine/on_chain/impls.rs @@ -39,11 +39,11 @@ use crate::{ Keccak256, Sha2x256, }, + types::FromLittleEndian, Clear, EnvBackend, Environment, Error, - FromLittleEndian, Result, ReturnFlags, TypedEnvBackend, diff --git a/crates/env/src/event.rs b/crates/env/src/event.rs index 859ef7515e..9c7f78cf83 100644 --- a/crates/env/src/event.rs +++ b/crates/env/src/event.rs @@ -14,7 +14,7 @@ //! This module contains the implementation for the event topic logic. -use crate::Environment; +use crate::types::Environment; /// The concrete implementation that is guided by the topics builder. /// diff --git a/crates/env/src/lib.rs b/crates/env/src/lib.rs index 1204475cfa..31c950f459 100644 --- a/crates/env/src/lib.rs +++ b/crates/env/src/lib.rs @@ -84,18 +84,14 @@ fn panic(info: &core::panic::PanicInfo) -> ! { extern crate ink_allocator; mod api; -mod arithmetic; mod backend; pub mod call; pub mod chain_extension; -mod contract; mod engine; mod error; #[doc(hidden)] pub mod event; pub mod hash; -pub mod reflect; -mod types; #[cfg(test)] mod tests; @@ -114,11 +110,6 @@ pub use self::{ CallFlags, ReturnFlags, }, - contract::{ - ContractEnv, - ContractReference, - ContractReverseReference, - }, error::{ Error, Result, @@ -126,14 +117,27 @@ pub use self::{ event::Event, types::{ AccountIdGuard, + Balance, + BlockNumber, + CodecAsType, DefaultEnvironment, Environment, FromLittleEndian, Gas, NoChainExtension, + Timestamp, }, }; use ink_primitives::Clear; +pub use ink_primitives::{ + contract::{ + ContractEnv, + ContractReference, + ContractReverseReference, + }, + reflect, + types, +}; cfg_if::cfg_if! { if #[cfg(any(feature = "ink-debug", feature = "std"))] { diff --git a/crates/env/src/types.rs b/crates/env/src/types.rs deleted file mode 100644 index b4507437b3..0000000000 --- a/crates/env/src/types.rs +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Types for the default environment. -//! -//! These are simple mirrored types from the default substrate FRAME configuration. -//! Their interfaces and functionality might not be complete. -//! -//! Users are required to provide their own type definitions and `Environment` -//! implementations in order to write ink! contracts for other chain configurations. -//! -//! # Note -//! -//! When authoring a contract, the concrete `Environment` are available via aliases -//! generated by the `lang` macro. Therefore all functionality of the concrete -//! types is accessible in the contract, not constrained by the required trait -//! bounds. -//! -//! Outside the contract and its tests (e.g. in the off-chain environment), where -//! there is no knowledge of the concrete types, the functionality is restricted to -//! the trait bounds on the `Environment` trait types. - -use super::arithmetic::AtLeast32BitUnsigned; -use ink_primitives::{ - AccountId, - Clear, - Hash, -}; -#[cfg(feature = "std")] -use scale_info::TypeInfo; - -/// Allows to instantiate a type from its little-endian bytes representation. -pub trait FromLittleEndian { - /// The little-endian bytes representation. - type Bytes: Default + AsRef<[u8]> + AsMut<[u8]>; - - /// Create a new instance from the little-endian bytes representation. - fn from_le_bytes(bytes: Self::Bytes) -> Self; -} - -impl FromLittleEndian for u8 { - type Bytes = [u8; 1]; - - #[inline] - fn from_le_bytes(bytes: Self::Bytes) -> Self { - u8::from_le_bytes(bytes) - } -} - -impl FromLittleEndian for u16 { - type Bytes = [u8; 2]; - - #[inline] - fn from_le_bytes(bytes: Self::Bytes) -> Self { - u16::from_le_bytes(bytes) - } -} - -impl FromLittleEndian for u32 { - type Bytes = [u8; 4]; - - #[inline] - fn from_le_bytes(bytes: Self::Bytes) -> Self { - u32::from_le_bytes(bytes) - } -} - -impl FromLittleEndian for u64 { - type Bytes = [u8; 8]; - - #[inline] - fn from_le_bytes(bytes: Self::Bytes) -> Self { - u64::from_le_bytes(bytes) - } -} - -impl FromLittleEndian for u128 { - type Bytes = [u8; 16]; - - #[inline] - fn from_le_bytes(bytes: Self::Bytes) -> Self { - u128::from_le_bytes(bytes) - } -} - -/// A trait to enforce that a type should be an [`Environment::AccountId`]. -/// -/// If you have an [`Environment`] which uses an [`Environment::AccountId`] type other -/// than the ink! provided [`AccountId`](https://docs.rs/ink_primitives/latest/ink_primitives/struct.AccountId.html) -/// you will need to implement this trait for your [`Environment::AccountId`] concrete -/// type. -pub trait AccountIdGuard {} - -/// The ink! provided [`AccountId`](https://docs.rs/ink_primitives/latest/ink_primitives/struct.AccountId.html) -/// used in the [`DefaultEnvironment`]. -impl AccountIdGuard for AccountId {} - -cfg_if::cfg_if! { - if #[cfg(feature = "std")] { - pub trait CodecAsType: scale_decode::DecodeAsType + scale_encode::EncodeAsType {} - impl CodecAsType for T {} - } else { - pub trait CodecAsType {} - impl CodecAsType for T {} - } -} - -/// The environmental types usable by contracts defined with ink!. -pub trait Environment: Clone { - /// The maximum number of supported event topics provided by the runtime. - /// - /// The value must match the maximum number of supported event topics of the used - /// runtime. - const MAX_EVENT_TOPICS: usize; - - /// The account id type. - type AccountId: 'static - + scale::Codec - + CodecAsType - + Clone - + PartialEq - + Eq - + Ord - + AsRef<[u8]> - + AsMut<[u8]>; - - /// The type of balances. - type Balance: 'static - + scale::Codec - + CodecAsType - + Copy - + Clone - + PartialEq - + Eq - + AtLeast32BitUnsigned - + FromLittleEndian; - - /// The type of hash. - type Hash: 'static - + scale::Codec - + CodecAsType - + Copy - + Clone - + Clear - + PartialEq - + Eq - + Ord - + AsRef<[u8]> - + AsMut<[u8]>; - - /// The type of a timestamp. - type Timestamp: 'static - + scale::Codec - + CodecAsType - + Copy - + Clone - + PartialEq - + Eq - + AtLeast32BitUnsigned - + FromLittleEndian; - - /// The type of block number. - type BlockNumber: 'static - + scale::Codec - + CodecAsType - + Copy - + Clone - + PartialEq - + Eq - + AtLeast32BitUnsigned - + FromLittleEndian; - - /// The chain extension for the environment. - /// - /// This is a type that is defined through the `#[ink::chain_extension]` procedural - /// macro. For more information about usage and definition click - /// [this][chain_extension] link. - /// - /// [chain_extension]: https://paritytech.github.io/ink/ink/attr.chain_extension.html - type ChainExtension; -} - -/// Placeholder for chains that have no defined chain extension. -#[cfg_attr(feature = "std", derive(TypeInfo))] -pub enum NoChainExtension {} - -/// The fundamental types of the default configuration. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(TypeInfo))] -pub enum DefaultEnvironment {} - -impl Environment for DefaultEnvironment { - const MAX_EVENT_TOPICS: usize = 4; - - type AccountId = AccountId; - type Balance = Balance; - type Hash = Hash; - type Timestamp = Timestamp; - type BlockNumber = BlockNumber; - type ChainExtension = NoChainExtension; -} - -/// The default balance type. -pub type Balance = u128; - -/// The default timestamp type. -pub type Timestamp = u64; - -/// The default gas type. -pub type Gas = u64; - -/// The default block number type. -pub type BlockNumber = u32; diff --git a/crates/ink/codegen/Cargo.toml b/crates/ink/codegen/Cargo.toml index 5f566002fa..38090e3ede 100644 --- a/crates/ink/codegen/Cargo.toml +++ b/crates/ink/codegen/Cargo.toml @@ -19,7 +19,6 @@ name = "ink_codegen" [dependencies] ink_primitives = { workspace = true } -ink_env = { workspace = true } ir = { version = "=5.0.0-alpha", package = "ink_ir", path = "../ir", default-features = false } quote = { workspace = true } syn = { workspace = true, features = ["parsing", "full", "extra-traits"] } @@ -40,5 +39,4 @@ default = ["std"] std = [ "itertools/use_std", "either/use_std", - "ink_env/std", ] diff --git a/crates/ink/codegen/src/lib.rs b/crates/ink/codegen/src/lib.rs index 95287f36a7..bc7f9c41f6 100644 --- a/crates/ink/codegen/src/lib.rs +++ b/crates/ink/codegen/src/lib.rs @@ -35,7 +35,7 @@ html_favicon_url = "https://use.ink/crate-docs/favicon.png" )] -pub use ink_env::reflect; +pub use ink_primitives::reflect; mod enforced_error; mod generator; mod traits; diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 155369edd5..190caaed1f 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -22,6 +22,8 @@ scale-decode = { workspace = true, features = ["derive"], optional = true } scale-encode = { workspace = true, features = ["derive"], optional = true } scale-info = { workspace = true, features = ["derive"], optional = true } xxhash-rust = { workspace = true, features = ["const_xxh32"] } +cfg-if = { workspace = true } +num-traits = { workspace = true, features = ["i128"] } [features] default = ["std"] diff --git a/crates/env/src/arithmetic.rs b/crates/primitives/src/arithmetic.rs similarity index 100% rename from crates/env/src/arithmetic.rs rename to crates/primitives/src/arithmetic.rs diff --git a/crates/env/src/contract.rs b/crates/primitives/src/contract.rs similarity index 100% rename from crates/env/src/contract.rs rename to crates/primitives/src/contract.rs diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index b43c31162b..6c2e157886 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -28,8 +28,10 @@ )] #![cfg_attr(not(feature = "std"), no_std)] +mod arithmetic; mod key; -mod types; +pub mod reflect; +pub mod types; pub use self::{ key::{ @@ -39,9 +41,11 @@ pub use self::{ types::{ AccountId, Clear, + Environment, Hash, }, }; +pub mod contract; /// An error emitted by the smart contracting language. /// diff --git a/crates/env/src/reflect/contract.rs b/crates/primitives/src/reflect/contract.rs similarity index 100% rename from crates/env/src/reflect/contract.rs rename to crates/primitives/src/reflect/contract.rs diff --git a/crates/env/src/reflect/dispatch.rs b/crates/primitives/src/reflect/dispatch.rs similarity index 100% rename from crates/env/src/reflect/dispatch.rs rename to crates/primitives/src/reflect/dispatch.rs diff --git a/crates/env/src/reflect/event.rs b/crates/primitives/src/reflect/event.rs similarity index 100% rename from crates/env/src/reflect/event.rs rename to crates/primitives/src/reflect/event.rs diff --git a/crates/env/src/reflect/mod.rs b/crates/primitives/src/reflect/mod.rs similarity index 100% rename from crates/env/src/reflect/mod.rs rename to crates/primitives/src/reflect/mod.rs diff --git a/crates/env/src/reflect/trait_def/info.rs b/crates/primitives/src/reflect/trait_def/info.rs similarity index 100% rename from crates/env/src/reflect/trait_def/info.rs rename to crates/primitives/src/reflect/trait_def/info.rs diff --git a/crates/env/src/reflect/trait_def/mod.rs b/crates/primitives/src/reflect/trait_def/mod.rs similarity index 100% rename from crates/env/src/reflect/trait_def/mod.rs rename to crates/primitives/src/reflect/trait_def/mod.rs diff --git a/crates/env/src/reflect/trait_def/registry.rs b/crates/primitives/src/reflect/trait_def/registry.rs similarity index 98% rename from crates/env/src/reflect/trait_def/registry.rs rename to crates/primitives/src/reflect/trait_def/registry.rs index dc1cc1683c..38a3743998 100644 --- a/crates/env/src/reflect/trait_def/registry.rs +++ b/crates/primitives/src/reflect/trait_def/registry.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::ContractEnv; +use crate::contract::ContractEnv; use core::marker::PhantomData; /// Type that is guaranteed by ink! to implement all ink! trait definitions. diff --git a/crates/primitives/src/types.rs b/crates/primitives/src/types.rs index 3eb77c66fe..66987d1f71 100644 --- a/crates/primitives/src/types.rs +++ b/crates/primitives/src/types.rs @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::arithmetic::AtLeast32BitUnsigned; use core::array::TryFromSliceError; use derive_more::From; use scale::{ @@ -150,3 +151,186 @@ impl Clear for Hash { <[u8; 32] as Clear>::is_clear(&self.0) } } + +/// Allows to instantiate a type from its little-endian bytes representation. +pub trait FromLittleEndian { + /// The little-endian bytes representation. + type Bytes: Default + AsRef<[u8]> + AsMut<[u8]>; + + /// Create a new instance from the little-endian bytes representation. + fn from_le_bytes(bytes: Self::Bytes) -> Self; +} + +impl FromLittleEndian for u8 { + type Bytes = [u8; 1]; + + #[inline] + fn from_le_bytes(bytes: Self::Bytes) -> Self { + u8::from_le_bytes(bytes) + } +} + +impl FromLittleEndian for u16 { + type Bytes = [u8; 2]; + + #[inline] + fn from_le_bytes(bytes: Self::Bytes) -> Self { + u16::from_le_bytes(bytes) + } +} + +impl FromLittleEndian for u32 { + type Bytes = [u8; 4]; + + #[inline] + fn from_le_bytes(bytes: Self::Bytes) -> Self { + u32::from_le_bytes(bytes) + } +} + +impl FromLittleEndian for u64 { + type Bytes = [u8; 8]; + + #[inline] + fn from_le_bytes(bytes: Self::Bytes) -> Self { + u64::from_le_bytes(bytes) + } +} + +impl FromLittleEndian for u128 { + type Bytes = [u8; 16]; + + #[inline] + fn from_le_bytes(bytes: Self::Bytes) -> Self { + u128::from_le_bytes(bytes) + } +} + +/// A trait to enforce that a type should be an [`Environment::AccountId`]. +/// +/// If you have an [`Environment`] which uses an [`Environment::AccountId`] type other +/// than the ink! provided [`AccountId`](https://docs.rs/ink_primitives/latest/ink_primitives/struct.AccountId.html) +/// you will need to implement this trait for your [`Environment::AccountId`] concrete +/// type. +pub trait AccountIdGuard {} + +/// The ink! provided [`AccountId`](https://docs.rs/ink_primitives/latest/ink_primitives/struct.AccountId.html) +/// used in the [`DefaultEnvironment`]. +impl AccountIdGuard for AccountId {} + +cfg_if::cfg_if! { + if #[cfg(feature = "std")] { + pub trait CodecAsType: scale_decode::DecodeAsType + scale_encode::EncodeAsType {} + impl CodecAsType for T {} + } else { + pub trait CodecAsType {} + impl CodecAsType for T {} + } +} + +/// The environmental types usable by contracts defined with ink!. +pub trait Environment: Clone { + /// The maximum number of supported event topics provided by the runtime. + /// + /// The value must match the maximum number of supported event topics of the used + /// runtime. + const MAX_EVENT_TOPICS: usize; + + /// The account id type. + type AccountId: 'static + + scale::Codec + + CodecAsType + + Clone + + PartialEq + + Eq + + Ord + + AsRef<[u8]> + + AsMut<[u8]>; + + /// The type of balances. + type Balance: 'static + + scale::Codec + + CodecAsType + + Copy + + Clone + + PartialEq + + Eq + + AtLeast32BitUnsigned + + FromLittleEndian; + + /// The type of hash. + type Hash: 'static + + scale::Codec + + CodecAsType + + Copy + + Clone + + Clear + + PartialEq + + Eq + + Ord + + AsRef<[u8]> + + AsMut<[u8]>; + + /// The type of a timestamp. + type Timestamp: 'static + + scale::Codec + + CodecAsType + + Copy + + Clone + + PartialEq + + Eq + + AtLeast32BitUnsigned + + FromLittleEndian; + + /// The type of block number. + type BlockNumber: 'static + + scale::Codec + + CodecAsType + + Copy + + Clone + + PartialEq + + Eq + + AtLeast32BitUnsigned + + FromLittleEndian; + + /// The chain extension for the environment. + /// + /// This is a type that is defined through the `#[ink::chain_extension]` procedural + /// macro. For more information about usage and definition click + /// [this][chain_extension] link. + /// + /// [chain_extension]: https://paritytech.github.io/ink/ink/attr.chain_extension.html + type ChainExtension; +} + +/// Placeholder for chains that have no defined chain extension. +#[cfg_attr(feature = "std", derive(TypeInfo))] +pub enum NoChainExtension {} + +/// The fundamental types of the default configuration. +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "std", derive(TypeInfo))] +pub enum DefaultEnvironment {} + +impl Environment for DefaultEnvironment { + const MAX_EVENT_TOPICS: usize = 4; + + type AccountId = AccountId; + type Balance = Balance; + type Hash = Hash; + type Timestamp = Timestamp; + type BlockNumber = BlockNumber; + type ChainExtension = NoChainExtension; +} + +/// The default balance type. +pub type Balance = u128; + +/// The default timestamp type. +pub type Timestamp = u64; + +/// The default gas type. +pub type Gas = u64; + +/// The default block number type. +pub type BlockNumber = u32; From 8f78fddf5965d050c96fe070ef8edca41fe79839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Tue, 31 Oct 2023 02:20:54 -0300 Subject: [PATCH 14/44] Revert "Updated stderr test files." This reverts commit 2d1950a6d46c257c058550ea031aeea57abceb3c. --- .../fail/constructor-input-non-codec.stderr | 20 +++++++++----- .../constructor-return-result-invalid.stderr | 2 +- ...uctor-return-result-non-codec-error.stderr | 27 ++++++++++++------- .../fail/constructor-self-receiver-03.stderr | 2 +- .../fail/message-input-non-codec.stderr | 22 +++++++++------ .../fail/message-returns-non-codec.stderr | 16 +++++++---- ...packed_is_not_derived_automatically.stderr | 12 ++++----- .../fail/message_input_non_codec.stderr | 20 +++++++++----- .../fail/message_output_non_codec.stderr | 13 +++++---- 9 files changed, 85 insertions(+), 49 deletions(-) diff --git a/crates/ink/tests/ui/contract/fail/constructor-input-non-codec.stderr b/crates/ink/tests/ui/contract/fail/constructor-input-non-codec.stderr index 852fdefd45..6889d1639f 100644 --- a/crates/ink/tests/ui/contract/fail/constructor-input-non-codec.stderr +++ b/crates/ink/tests/ui/contract/fail/constructor-input-non-codec.stderr @@ -5,13 +5,16 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeDecode` is not satisfied | ^^^^^^ the trait `WrapperTypeDecode` is not implemented for `NonCodecType` | = help: the following other types implement trait `WrapperTypeDecode`: - Arc Box Rc + Arc = note: required for `NonCodecType` to implement `ink::parity_scale_codec::Decode` note: required by a bound in `DispatchInput` --> src/codegen/dispatch/type_check.rs | + | pub struct DispatchInput(T) + | ------------- required by a bound in this struct + | where | T: scale::Decode + 'static; | ^^^^^^^^^^^^^ required by this bound in `DispatchInput` @@ -22,9 +25,9 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeDecode` is not satisfied | ^^^ the trait `WrapperTypeDecode` is not implemented for `NonCodecType` | = help: the following other types implement trait `WrapperTypeDecode`: - Arc Box Rc + Arc = note: required for `NonCodecType` to implement `ink::parity_scale_codec::Decode` error[E0277]: the trait bound `NonCodecType: WrapperTypeEncode` is not satisfied @@ -37,18 +40,21 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeEncode` is not satisfied | --- required by a bound introduced by this call | = help: the following other types implement trait `WrapperTypeEncode`: - &T - &mut T - Arc Box Cow<'a, T> + ink::parity_scale_codec::Ref<'a, T, U> Rc - String + Arc Vec - ink::parity_scale_codec::Ref<'a, T, U> + String + &T + &mut T = note: required for `NonCodecType` to implement `Encode` note: required by a bound in `ExecutionInput::>::push_arg` --> $WORKSPACE/crates/env/src/call/execution_input.rs | + | pub fn push_arg( + | -------- required by a bound in this associated function +... | T: scale::Encode, | ^^^^^^^^^^^^^ required by this bound in `ExecutionInput::>::push_arg` diff --git a/crates/ink/tests/ui/contract/fail/constructor-return-result-invalid.stderr b/crates/ink/tests/ui/contract/fail/constructor-return-result-invalid.stderr index 7101544b93..c09f9af224 100644 --- a/crates/ink/tests/ui/contract/fail/constructor-return-result-invalid.stderr +++ b/crates/ink/tests/ui/contract/fail/constructor-return-result-invalid.stderr @@ -5,5 +5,5 @@ error[E0277]: the trait bound `ConstructorOutputValue` is not implemented for `ConstructorOutputValue>` | = help: the following other types implement trait `ConstructorOutput`: - ConstructorOutputValue ConstructorOutputValue> + ConstructorOutputValue diff --git a/crates/ink/tests/ui/contract/fail/constructor-return-result-non-codec-error.stderr b/crates/ink/tests/ui/contract/fail/constructor-return-result-non-codec-error.stderr index 5917e23164..ba04fb8f65 100644 --- a/crates/ink/tests/ui/contract/fail/constructor-return-result-non-codec-error.stderr +++ b/crates/ink/tests/ui/contract/fail/constructor-return-result-non-codec-error.stderr @@ -8,6 +8,9 @@ error[E0277]: the trait bound `Result, LangError>: note: required by a bound in `return_value` --> $WORKSPACE/crates/env/src/api.rs | + | pub fn return_value(return_flags: ReturnFlags, return_value: &R) -> ! + | ------------ required by a bound in this function + | where | R: scale::Encode, | ^^^^^^^^^^^^^ required by this bound in `return_value` @@ -18,14 +21,17 @@ error[E0277]: the trait bound `contract::Error: WrapperTypeDecode` is not satisf | ^^^ the trait `WrapperTypeDecode` is not implemented for `contract::Error` | = help: the following other types implement trait `WrapperTypeDecode`: - Arc Box Rc + Arc = note: required for `contract::Error` to implement `ink::parity_scale_codec::Decode` = note: required for `Result` to implement `ConstructorReturnType` note: required by a bound in `CreateBuilder::>>::returns` --> $WORKSPACE/crates/env/src/call/create_builder.rs | + | pub fn returns( + | ------- required by a bound in this associated function +... | R: ConstructorReturnType, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `CreateBuilder::>>::returns` @@ -36,14 +42,14 @@ error[E0277]: the trait bound `contract::Error: TypeInfo` is not satisfied | ^^^^^^^^ the trait `TypeInfo` is not implemented for `contract::Error` | = help: the following other types implement trait `TypeInfo`: - &T - &mut T - () - (A, B) - (A, B, C) - (A, B, C, D) - (A, B, C, D, E) - (A, B, C, D, E, F) + bool + char + i8 + i16 + i32 + i64 + i128 + u8 and $N others = note: required for `Result<(), contract::Error>` to implement `TypeInfo` = note: 1 redundant requirement hidden @@ -51,5 +57,8 @@ error[E0277]: the trait bound `contract::Error: TypeInfo` is not satisfied note: required by a bound in `TypeSpec::with_name_str` --> $WORKSPACE/crates/metadata/src/specs.rs | + | pub fn with_name_str(display_name: &'static str) -> Self + | ------------- required by a bound in this associated function + | where | T: TypeInfo + 'static, | ^^^^^^^^ required by this bound in `TypeSpec::with_name_str` diff --git a/crates/ink/tests/ui/contract/fail/constructor-self-receiver-03.stderr b/crates/ink/tests/ui/contract/fail/constructor-self-receiver-03.stderr index eea8a1c23b..2f261fa67c 100644 --- a/crates/ink/tests/ui/contract/fail/constructor-self-receiver-03.stderr +++ b/crates/ink/tests/ui/contract/fail/constructor-self-receiver-03.stderr @@ -29,7 +29,7 @@ error[E0277]: the trait bound `&Contract: WrapperTypeDecode` is not satisfied | ^^^ the trait `WrapperTypeDecode` is not implemented for `&Contract` | = help: the following other types implement trait `WrapperTypeDecode`: - Arc Box Rc + Arc = note: required for `&Contract` to implement `ink::parity_scale_codec::Decode` diff --git a/crates/ink/tests/ui/contract/fail/message-input-non-codec.stderr b/crates/ink/tests/ui/contract/fail/message-input-non-codec.stderr index 992da8a93c..3eff91fc43 100644 --- a/crates/ink/tests/ui/contract/fail/message-input-non-codec.stderr +++ b/crates/ink/tests/ui/contract/fail/message-input-non-codec.stderr @@ -5,13 +5,16 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeDecode` is not satisfied | ^^^^^^ the trait `WrapperTypeDecode` is not implemented for `NonCodecType` | = help: the following other types implement trait `WrapperTypeDecode`: - Arc Box Rc + Arc = note: required for `NonCodecType` to implement `ink::parity_scale_codec::Decode` note: required by a bound in `DispatchInput` --> src/codegen/dispatch/type_check.rs | + | pub struct DispatchInput(T) + | ------------- required by a bound in this struct + | where | T: scale::Decode + 'static; | ^^^^^^^^^^^^^ required by this bound in `DispatchInput` @@ -22,9 +25,9 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeDecode` is not satisfied | ^^^ the trait `WrapperTypeDecode` is not implemented for `NonCodecType` | = help: the following other types implement trait `WrapperTypeDecode`: - Arc Box Rc + Arc = note: required for `NonCodecType` to implement `ink::parity_scale_codec::Decode` error[E0277]: the trait bound `NonCodecType: WrapperTypeEncode` is not satisfied @@ -37,19 +40,22 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeEncode` is not satisfied | --- required by a bound introduced by this call | = help: the following other types implement trait `WrapperTypeEncode`: - &T - &mut T - Arc Box Cow<'a, T> + ink::parity_scale_codec::Ref<'a, T, U> Rc - String + Arc Vec - ink::parity_scale_codec::Ref<'a, T, U> + String + &T + &mut T = note: required for `NonCodecType` to implement `Encode` note: required by a bound in `ExecutionInput::>::push_arg` --> $WORKSPACE/crates/env/src/call/execution_input.rs | + | pub fn push_arg( + | -------- required by a bound in this associated function +... | T: scale::Encode, | ^^^^^^^^^^^^^ required by this bound in `ExecutionInput::>::push_arg` @@ -65,4 +71,4 @@ error[E0599]: the method `try_invoke` exists for struct `CallBuilder, ArgumentList>: Encode` + `ArgumentList, ArgumentList>: Encode` diff --git a/crates/ink/tests/ui/contract/fail/message-returns-non-codec.stderr b/crates/ink/tests/ui/contract/fail/message-returns-non-codec.stderr index 754cc3744f..3474db6f08 100644 --- a/crates/ink/tests/ui/contract/fail/message-returns-non-codec.stderr +++ b/crates/ink/tests/ui/contract/fail/message-returns-non-codec.stderr @@ -5,19 +5,22 @@ error[E0277]: the trait bound `NonCodecType: WrapperTypeEncode` is not satisfied | ^^^^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `NonCodecType` | = help: the following other types implement trait `WrapperTypeEncode`: - &T - &mut T - Arc Box Cow<'a, T> + ink::parity_scale_codec::Ref<'a, T, U> Rc - String + Arc Vec - ink::parity_scale_codec::Ref<'a, T, U> + String + &T + &mut T = note: required for `NonCodecType` to implement `Encode` note: required by a bound in `DispatchOutput` --> src/codegen/dispatch/type_check.rs | + | pub struct DispatchOutput(T) + | -------------- required by a bound in this struct + | where | T: scale::Encode + 'static; | ^^^^^^^^^^^^^ required by this bound in `DispatchOutput` @@ -31,6 +34,9 @@ error[E0277]: the trait bound `Result: Encode` is not s note: required by a bound in `return_value` --> $WORKSPACE/crates/env/src/api.rs | + | pub fn return_value(return_flags: ReturnFlags, return_value: &R) -> ! + | ------------ required by a bound in this function + | where | R: scale::Encode, | ^^^^^^^^^^^^^ required by this bound in `return_value` diff --git a/crates/ink/tests/ui/storage_item/fail/packed_is_not_derived_automatically.stderr b/crates/ink/tests/ui/storage_item/fail/packed_is_not_derived_automatically.stderr index ad0c10fe99..4863fb334b 100644 --- a/crates/ink/tests/ui/storage_item/fail/packed_is_not_derived_automatically.stderr +++ b/crates/ink/tests/ui/storage_item/fail/packed_is_not_derived_automatically.stderr @@ -5,9 +5,9 @@ error[E0277]: the trait bound `NonPacked: WrapperTypeDecode` is not satisfied | ^^^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `NonPacked` | = help: the following other types implement trait `WrapperTypeDecode`: - Arc Box Rc + Arc = note: required for `NonPacked` to implement `ink::parity_scale_codec::Decode` = note: required for `NonPacked` to implement `Packed` note: required by a bound in `consume_packed` @@ -23,15 +23,15 @@ error[E0277]: the trait bound `NonPacked: WrapperTypeEncode` is not satisfied | ^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `NonPacked` | = help: the following other types implement trait `WrapperTypeEncode`: - &T - &mut T - Arc Box Cow<'a, T> + ink::parity_scale_codec::Ref<'a, T, U> Rc - String + Arc Vec - ink::parity_scale_codec::Ref<'a, T, U> + String + &T + &mut T = note: required for `NonPacked` to implement `Encode` = note: required for `NonPacked` to implement `Packed` note: required by a bound in `consume_packed` diff --git a/crates/ink/tests/ui/trait_def/fail/message_input_non_codec.stderr b/crates/ink/tests/ui/trait_def/fail/message_input_non_codec.stderr index 1f7a0c1e89..775914c95b 100644 --- a/crates/ink/tests/ui/trait_def/fail/message_input_non_codec.stderr +++ b/crates/ink/tests/ui/trait_def/fail/message_input_non_codec.stderr @@ -5,13 +5,16 @@ error[E0277]: the trait bound `NonCodec: WrapperTypeDecode` is not satisfied | ^^^^^ the trait `WrapperTypeDecode` is not implemented for `NonCodec` | = help: the following other types implement trait `WrapperTypeDecode`: - Arc Box Rc + Arc = note: required for `NonCodec` to implement `ink::parity_scale_codec::Decode` note: required by a bound in `DispatchInput` --> src/codegen/dispatch/type_check.rs | + | pub struct DispatchInput(T) + | ------------- required by a bound in this struct + | where | T: scale::Decode + 'static; | ^^^^^^^^^^^^^ required by this bound in `DispatchInput` @@ -25,19 +28,22 @@ error[E0277]: the trait bound `NonCodec: WrapperTypeEncode` is not satisfied | - required by a bound introduced by this call | = help: the following other types implement trait `WrapperTypeEncode`: - &T - &mut T - Arc Box Cow<'a, T> + ink::parity_scale_codec::Ref<'a, T, U> Rc - String + Arc Vec - ink::parity_scale_codec::Ref<'a, T, U> + String + &T + &mut T = note: required for `NonCodec` to implement `Encode` note: required by a bound in `ExecutionInput::>::push_arg` --> $WORKSPACE/crates/env/src/call/execution_input.rs | + | pub fn push_arg( + | -------- required by a bound in this associated function +... | T: scale::Encode, | ^^^^^^^^^^^^^ required by this bound in `ExecutionInput::>::push_arg` @@ -53,4 +59,4 @@ error[E0599]: the method `try_invoke` exists for struct `CallBuilder, ArgumentList>: Encode` + `ArgumentList, ArgumentList>: Encode` diff --git a/crates/ink/tests/ui/trait_def/fail/message_output_non_codec.stderr b/crates/ink/tests/ui/trait_def/fail/message_output_non_codec.stderr index 3f52f0fe96..983b1b3b88 100644 --- a/crates/ink/tests/ui/trait_def/fail/message_output_non_codec.stderr +++ b/crates/ink/tests/ui/trait_def/fail/message_output_non_codec.stderr @@ -5,19 +5,22 @@ error[E0277]: the trait bound `NonCodec: WrapperTypeEncode` is not satisfied | ^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `NonCodec` | = help: the following other types implement trait `WrapperTypeEncode`: - &T - &mut T - Arc Box Cow<'a, T> + ink::parity_scale_codec::Ref<'a, T, U> Rc - String + Arc Vec - ink::parity_scale_codec::Ref<'a, T, U> + String + &T + &mut T = note: required for `NonCodec` to implement `Encode` note: required by a bound in `DispatchOutput` --> src/codegen/dispatch/type_check.rs | + | pub struct DispatchOutput(T) + | -------------- required by a bound in this struct + | where | T: scale::Encode + 'static; | ^^^^^^^^^^^^^ required by this bound in `DispatchOutput` From b350252e7ff5f83e8fcecdecd5deebb46a92b02f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Tue, 31 Oct 2023 02:35:10 -0300 Subject: [PATCH 15/44] Fixed format errors. --- crates/ink/codegen/src/generator/trait_def/trait_registry.rs | 4 +--- crates/ink/ir/src/ir/attrs.rs | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/crates/ink/codegen/src/generator/trait_def/trait_registry.rs b/crates/ink/codegen/src/generator/trait_def/trait_registry.rs index b0fe1a25bd..63017a0202 100644 --- a/crates/ink/codegen/src/generator/trait_def/trait_registry.rs +++ b/crates/ink/codegen/src/generator/trait_def/trait_registry.rs @@ -21,9 +21,7 @@ use super::TraitDefinition; use crate::{ - generator::{ - self, - }, + generator::self, traits::GenerateCode, EnforcedErrors, }; diff --git a/crates/ink/ir/src/ir/attrs.rs b/crates/ink/ir/src/ir/attrs.rs index 100efa0654..4fd16ef7b0 100644 --- a/crates/ink/ir/src/ir/attrs.rs +++ b/crates/ink/ir/src/ir/attrs.rs @@ -32,9 +32,7 @@ use syn::{ }; use crate::{ - ast::{ - self, - }, + ast::self, error::ExtError as _, ir, ir::{ From 2dfb9eddfc60fbe3093dc484c80c3be6acaffd89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Tue, 31 Oct 2023 03:09:56 -0300 Subject: [PATCH 16/44] Fixed failing test. --- crates/ink/codegen/src/generator/dispatch.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ink/codegen/src/generator/dispatch.rs b/crates/ink/codegen/src/generator/dispatch.rs index 49453ea081..a5721996e4 100644 --- a/crates/ink/codegen/src/generator/dispatch.rs +++ b/crates/ink/codegen/src/generator/dispatch.rs @@ -605,7 +605,7 @@ impl Dispatch<'_> { ); #[cfg(feature="test_instantiate")] - Ok(()) + ::core::result::Result::Ok(()) } ) }); @@ -804,7 +804,7 @@ impl Dispatch<'_> { ); #[cfg(feature="test_instantiate")] - Ok(()) + ::core::result::Result::Ok(()) } ) }); From a715026d28863db573a370d8f9a93c4a603a35f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Tue, 31 Oct 2023 03:27:41 -0300 Subject: [PATCH 17/44] Updated stderr test values. --- .../fail/constructor-return-result-non-codec-error.stderr | 2 +- .../ink/tests/ui/contract/fail/message-returns-non-codec.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ink/tests/ui/contract/fail/constructor-return-result-non-codec-error.stderr b/crates/ink/tests/ui/contract/fail/constructor-return-result-non-codec-error.stderr index ba04fb8f65..fa9169c252 100644 --- a/crates/ink/tests/ui/contract/fail/constructor-return-result-non-codec-error.stderr +++ b/crates/ink/tests/ui/contract/fail/constructor-return-result-non-codec-error.stderr @@ -8,7 +8,7 @@ error[E0277]: the trait bound `Result, LangError>: note: required by a bound in `return_value` --> $WORKSPACE/crates/env/src/api.rs | - | pub fn return_value(return_flags: ReturnFlags, return_value: &R) -> ! + | pub fn return_value(return_flags: ReturnFlags, return_value: &R) | ------------ required by a bound in this function | where | R: scale::Encode, diff --git a/crates/ink/tests/ui/contract/fail/message-returns-non-codec.stderr b/crates/ink/tests/ui/contract/fail/message-returns-non-codec.stderr index 3474db6f08..f3b3f43a73 100644 --- a/crates/ink/tests/ui/contract/fail/message-returns-non-codec.stderr +++ b/crates/ink/tests/ui/contract/fail/message-returns-non-codec.stderr @@ -34,7 +34,7 @@ error[E0277]: the trait bound `Result: Encode` is not s note: required by a bound in `return_value` --> $WORKSPACE/crates/env/src/api.rs | - | pub fn return_value(return_flags: ReturnFlags, return_value: &R) -> ! + | pub fn return_value(return_flags: ReturnFlags, return_value: &R) | ------------ required by a bound in this function | where | R: scale::Encode, From 9c74b0871a14f8cbf0a688f03c0b6e09f070bbcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Tue, 31 Oct 2023 05:24:42 -0300 Subject: [PATCH 18/44] Fixed some dependencies for doc tests. --- crates/primitives/Cargo.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 190caaed1f..9c358277f1 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -25,9 +25,15 @@ xxhash-rust = { workspace = true, features = ["const_xxh32"] } cfg-if = { workspace = true } num-traits = { workspace = true, features = ["i128"] } +[dev-dependencies] +ink = { workspace = true, default-features = false } +ink_env = { workspace = true, default-features = false } + [features] default = ["std"] std = [ + "ink/std", + "ink_env/std", "ink_prelude/std", "scale/std", "scale-decode", From ea15b624d239966a5f20764f83342663c94fb64e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Tue, 31 Oct 2023 17:26:29 -0300 Subject: [PATCH 19/44] Fixed rustfmt issues. --- crates/ink/codegen/src/generator/trait_def/trait_registry.rs | 2 +- crates/ink/ir/src/ir/attrs.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ink/codegen/src/generator/trait_def/trait_registry.rs b/crates/ink/codegen/src/generator/trait_def/trait_registry.rs index 63017a0202..012bcfd759 100644 --- a/crates/ink/codegen/src/generator/trait_def/trait_registry.rs +++ b/crates/ink/codegen/src/generator/trait_def/trait_registry.rs @@ -21,7 +21,7 @@ use super::TraitDefinition; use crate::{ - generator::self, + generator, traits::GenerateCode, EnforcedErrors, }; diff --git a/crates/ink/ir/src/ir/attrs.rs b/crates/ink/ir/src/ir/attrs.rs index 4fd16ef7b0..a7f8ff2c95 100644 --- a/crates/ink/ir/src/ir/attrs.rs +++ b/crates/ink/ir/src/ir/attrs.rs @@ -32,7 +32,7 @@ use syn::{ }; use crate::{ - ast::self, + ast, error::ExtError as _, ir, ir::{ From 4e8fdc9c640303aecb535ebbf1de7fb4fd0f106f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Tue, 7 Nov 2023 05:50:00 -0300 Subject: [PATCH 20/44] Implemented code_hash() and set_code_hash(). --- crates/engine/src/database.rs | 21 +++++++++++++++++++++ crates/env/src/engine/off_chain/impls.rs | 16 ++++++++++++---- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/crates/engine/src/database.rs b/crates/engine/src/database.rs index 310225be28..268c75b203 100644 --- a/crates/engine/src/database.rs +++ b/crates/engine/src/database.rs @@ -18,6 +18,7 @@ use std::collections::HashMap; const BALANCE_OF: &[u8] = b"balance:"; const STORAGE_OF: &[u8] = b"contract-storage:"; +const CODE_HASH_OF: &[u8] = b"code-hash:"; /// Returns the database key under which to find the balance for account `who`. pub fn balance_of_key(who: &[u8]) -> [u8; 32] { @@ -35,6 +36,13 @@ pub fn storage_of_contract_key(who: &[u8], key: &[u8]) -> [u8; 32] { hashed_key } +pub fn code_hash_of_key(key: &Vec) -> [u8; 32]{ + let keyed = key.to_keyed_vec(CODE_HASH_OF); + let mut hashed_key: [u8; 32] = [0; 32]; + super::hashing::blake2b_256(&keyed[..], &mut hashed_key); + hashed_key +} + /// The chain database. /// /// Everything is stored in here: accounts, balances, contract storage, etc.. @@ -128,6 +136,19 @@ impl Database { .and_modify(|v| *v = encoded_balance.clone()) .or_insert(encoded_balance); } + + pub fn set_code_hash(&mut self, account: &Vec, code_hash: &[u8]) { + let hashed_key = code_hash_of_key(&account); + self.hmap + .entry(hashed_key.to_vec()) + .and_modify(|x| *x = code_hash.to_vec()) + .or_insert(code_hash.to_vec()); + } + + pub fn get_code_hash(&self, account: &Vec) -> Option> { + let hashed_key = code_hash_of_key(&account); + self.get(&hashed_key).cloned() + } } #[cfg(test)] diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index cda57bde43..6c7c068e74 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -396,8 +396,9 @@ impl EnvBackend for EnvInstance { Ok(decoded) } - fn set_code_hash(&mut self, _code_hash: &[u8]) -> Result<()> { - unimplemented!("off-chain environment does not support `set_code_hash`") + fn set_code_hash(&mut self, code_hash: &[u8]) -> Result<()> { + self.engine.database.set_code_hash(&self.engine.get_callee(), code_hash); + Ok(()) } } @@ -585,11 +586,18 @@ impl TypedEnvBackend for EnvInstance { unimplemented!("off-chain environment does not support cross-contract calls") } - fn code_hash(&mut self, _account: &E::AccountId) -> Result + fn code_hash(&mut self, account: &E::AccountId) -> Result where E: Environment, { - unimplemented!("off-chain environment does not support `code_hash`") + let code_hash = self.engine.database.get_code_hash(&scale::Encode::encode(&account)); + if let Some(code_hash) = code_hash{ + let code_hash = ::Hash::decode(&mut &code_hash[..]).unwrap(); + Ok(code_hash) + }else{ + Err(Error::KeyNotFound) + } + } fn own_code_hash(&mut self) -> Result From 9981c7f945e3d6e4cd35bd6f0f2e433168090a73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Tue, 7 Nov 2023 06:10:44 -0300 Subject: [PATCH 21/44] Minor behavior correction for instantiate_contract(). --- crates/engine/src/lib.rs | 2 +- crates/env/src/api.rs | 8 +++++ crates/env/src/backend.rs | 4 +++ crates/env/src/engine/off_chain/impls.rs | 44 ++++++++++++++++++++---- 4 files changed, 50 insertions(+), 8 deletions(-) diff --git a/crates/engine/src/lib.rs b/crates/engine/src/lib.rs index ded35d62c8..18fcf02ae5 100644 --- a/crates/engine/src/lib.rs +++ b/crates/engine/src/lib.rs @@ -23,7 +23,7 @@ pub mod test_api; mod chain_extension; mod database; mod exec_context; -mod hashing; +pub mod hashing; mod types; #[cfg(test)] diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index 8aa235d322..7642fe0c6b 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -477,6 +477,14 @@ where }) } +/// Retrieves the value stored by return_value(). +#[cfg(feature = "test_instantiate")] +pub fn get_return_value() -> Vec { + ::on_instance(|instance| { + EnvBackend::get_return_value(instance) + }) +} + /// Appends the given message to the debug message buffer. pub fn debug_message(message: &str) { ::on_instance(|instance| { diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index 7756e79fbc..f648928ff7 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -266,6 +266,10 @@ pub trait EnvBackend { where R: scale::Encode; + /// Retrieves the value stored by return_value(). + #[cfg(feature = "test_instantiate")] + fn get_return_value(&mut self) -> Vec; + /// Emit a custom debug message. /// /// The message is appended to the debug buffer which is then supplied to the calling diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index cda57bde43..403a7f5c2e 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -266,7 +266,12 @@ impl EnvBackend for EnvInstance { { let mut v = vec![]; return_value.encode_to(&mut v); - self.engine.set_storage(&[0, 0, 0, 0], &v[..]); + self.engine.set_storage(&[255_u8; 32], &v[..]); + } + + #[cfg(feature = "test_instantiate")] + fn get_return_value(&mut self) -> Vec { + self.engine.get_storage(&[255_u8; 32]).unwrap().to_vec() } fn debug_message(&mut self, message: &str) { @@ -516,13 +521,36 @@ impl TypedEnvBackend for EnvInstance { Salt: AsRef<[u8]>, R: ConstructorReturnType, { - let _code_hash = params.code_hash(); let _gas_limit = params.gas_limit(); let _endowment = params.endowment(); - let _salt_bytes = params.salt_bytes(); + + let salt_bytes = params.salt_bytes(); + + let code_hash = params.code_hash(); + let code_hash = scale::Encode::encode(code_hash); let input = params.exec_input(); - let input = ::scale::Encode::encode(input); + let input = scale::Encode::encode(input); + + //Compute account for instantiated contract. + let account_id_vec = { + let mut account_input = Vec::::new(); + account_input.extend(&b"contract_addr_v1".to_vec()); + if let Some(caller) = &self.engine.exec_context.caller{ + scale::Encode::encode_to(&caller.as_bytes(), &mut account_input); + } + account_input.extend(&input); + account_input.extend(salt_bytes.as_ref()); + let mut account_id = [0_u8; 32]; + ink_engine::hashing::blake2b_256(&account_input[..], &mut account_id); + account_id.to_vec() + }; + + let account_id = ::AccountId::decode(&mut &(account_id_vec[..])).unwrap(); + + let old_callee = self.engine.get_callee(); + self.engine.set_callee(account_id_vec); + let dispatch = < < < @@ -537,10 +565,12 @@ impl TypedEnvBackend for EnvInstance { crate::reflect::ExecuteDispatchable::execute_dispatchable(dispatch) .unwrap_or_else(|e| panic!("Constructor call failed: {:?}", e)); - let id = - ::AccountId::decode(&mut &(vec![0_u8; 32][..])).unwrap(); + self.set_code_hash(code_hash.as_slice())?; + + self.engine.set_callee(old_callee); + Ok(Ok(R::ok( - >::from_account_id(id), + >::from_account_id(account_id), ))) } From b6478d9b2bac279a08a5db522f8cf695e06d7ba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Tue, 7 Nov 2023 06:25:32 -0300 Subject: [PATCH 22/44] Tentative invoke_contract() implementation. --- crates/engine/src/database.rs | 52 +++++++++++++++++++ crates/env/src/api.rs | 14 ++++++ crates/env/src/backend.rs | 8 +++ crates/env/src/call/create_builder.rs | 4 ++ crates/env/src/engine/off_chain/impls.rs | 63 ++++++++++++++++++++++-- 5 files changed, 138 insertions(+), 3 deletions(-) diff --git a/crates/engine/src/database.rs b/crates/engine/src/database.rs index 268c75b203..b2b804f7e2 100644 --- a/crates/engine/src/database.rs +++ b/crates/engine/src/database.rs @@ -18,6 +18,8 @@ use std::collections::HashMap; const BALANCE_OF: &[u8] = b"balance:"; const STORAGE_OF: &[u8] = b"contract-storage:"; +const CONTRACT_PREFIX: &[u8] = b"contract:"; +const MSG_HANDLER_OF: &[u8] = b"message-handler:"; const CODE_HASH_OF: &[u8] = b"code-hash:"; /// Returns the database key under which to find the balance for account `who`. @@ -36,6 +38,26 @@ pub fn storage_of_contract_key(who: &[u8], key: &[u8]) -> [u8; 32] { hashed_key } +pub type MessageHandler = fn(Vec) -> Vec; + +pub fn contract_key(f: MessageHandler) -> [u8; 32]{ + let f = f as usize; + let f = f.to_le_bytes(); + let keyed = f + .to_vec().to_keyed_vec(CONTRACT_PREFIX); + let mut ret: [u8; 32] = [0; 32]; + super::hashing::blake2b_256(&keyed[..], &mut ret); + ret +} + +pub fn message_handler_of_contract_key(key: &[u8]) -> [u8; 32]{ + let keyed = key.to_vec() + .to_keyed_vec(MSG_HANDLER_OF); + let mut hashed_key: [u8; 32] = [0; 32]; + super::hashing::blake2b_256(&keyed[..], &mut hashed_key); + hashed_key +} + pub fn code_hash_of_key(key: &Vec) -> [u8; 32]{ let keyed = key.to_keyed_vec(CODE_HASH_OF); let mut hashed_key: [u8; 32] = [0; 32]; @@ -137,6 +159,36 @@ impl Database { .or_insert(encoded_balance); } + pub fn set_contract_message_handler(&mut self, handler: MessageHandler) -> [u8; 32]{ + let key = contract_key(handler); + let hashed_key = message_handler_of_contract_key(&key); + let handler = handler as usize; + let encoded_pointer = scale::Encode::encode(&handler.to_le_bytes()); + self.hmap + .entry(hashed_key.to_vec()) + .and_modify(|x| *x = encoded_pointer.clone()) + .or_insert(encoded_pointer); + key + } + + pub fn get_contract_message_handler(&mut self, key: &[u8]) -> MessageHandler { + let hashed_key = message_handler_of_contract_key(&key); + #[cfg(target_pointer_width = "32")] + const N: usize = 4; + #[cfg(target_pointer_width = "64")] + const N: usize = 8; + let pointer: Option<[u8; N]> = self.hmap + .get(&hashed_key.to_vec()) + .map(|encoded_pointer|{ + scale::Decode::decode(&mut &encoded_pointer[..]) + .expect("unable to retrieve message handler") + }); + let pointer = usize::from_le_bytes(pointer.unwrap()); + unsafe { + std::mem::transmute(pointer) + } + } + pub fn set_code_hash(&mut self, account: &Vec, code_hash: &[u8]) { let hashed_key = code_hash_of_key(&account); self.hmap diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index 7642fe0c6b..1fdd35c9f0 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -837,3 +837,17 @@ where TypedEnvBackend::call_runtime::(instance, call) }) } + +/// Gets a pseudo code hash for a contract ref. +#[cfg(feature = "test_instantiate")] +pub fn simulate_code_upload() -> ink_primitives::types::Hash +where + E: Environment, + ContractRef: crate::ContractReverseReference, + ::Type: + crate::reflect::ContractMessageDecoder, +{ + ::on_instance(|instance| { + EnvBackend::simulate_code_upload::(instance) + }) +} diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index f648928ff7..ed90c32ce2 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -366,6 +366,14 @@ pub trait EnvBackend { /// /// - If the supplied `code_hash` cannot be found on-chain. fn set_code_hash(&mut self, code_hash: &[u8]) -> Result<()>; + + #[cfg(feature = "test_instantiate")] + fn simulate_code_upload(&mut self) -> ink_primitives::types::Hash + where + E: Environment, + ContractRef: crate::ContractReverseReference, + ::Type: + crate::reflect::ContractMessageDecoder; } /// Environmental contract functionality. diff --git a/crates/env/src/call/create_builder.rs b/crates/env/src/call/create_builder.rs index aefad28d65..d3d1676420 100644 --- a/crates/env/src/call/create_builder.rs +++ b/crates/env/src/call/create_builder.rs @@ -243,6 +243,8 @@ where ContractRef: FromAccountId + crate::ContractReverseReference, ::Type: crate::reflect::ContractConstructorDecoder, + ::Type: + crate::reflect::ContractMessageDecoder, Args: scale::Encode, Salt: AsRef<[u8]>, R: ConstructorReturnType, @@ -726,6 +728,8 @@ where ContractRef: FromAccountId + crate::ContractReverseReference, ::Type: crate::reflect::ContractConstructorDecoder, + ::Type: + crate::reflect::ContractMessageDecoder, GasLimit: Unwrap, Args: scale::Encode, Salt: AsRef<[u8]>, diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index 9f1293a0c1..53aff14712 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -60,6 +60,33 @@ use schnorrkel::{ /// to be as close to the on-chain behavior as possible. const BUFFER_SIZE: usize = crate::BUFFER_SIZE; +/// Fill me. +#[cfg(feature = "test_instantiate")] +fn execute_contract_call(input: Vec) -> Vec +where + E: Environment, + ContractRef: crate::ContractReverseReference, + ::Type: + crate::reflect::ContractMessageDecoder, +{ + let dispatch = < + < + < + ContractRef + as crate::ContractReverseReference + >::Type + as crate::reflect::ContractMessageDecoder + >::Type + as scale::Decode + >::decode(&mut &input[..]) + .unwrap_or_else(|e| panic!("Failed to decode constructor call: {:?}", e)); + + crate::reflect::ExecuteDispatchable::execute_dispatchable(dispatch) + .unwrap_or_else(|e| panic!("Message call failed: {:?}", e)); + + crate::api::get_return_value() +} + impl CryptoHash for Blake2x128 { fn hash(input: &[u8], output: &mut ::Type) { type OutputType = [u8; 16]; @@ -405,6 +432,17 @@ impl EnvBackend for EnvInstance { self.engine.database.set_code_hash(&self.engine.get_callee(), code_hash); Ok(()) } + + #[cfg(feature = "test_instantiate")] + fn simulate_code_upload(&mut self) -> ink_primitives::types::Hash + where + E: Environment, + ContractRef: crate::ContractReverseReference, + ::Type: + crate::reflect::ContractMessageDecoder, + { + ink_primitives::types::Hash::from(self.engine.database.set_contract_message_handler(execute_contract_call::)) + } } impl TypedEnvBackend for EnvInstance { @@ -483,11 +521,30 @@ impl TypedEnvBackend for EnvInstance { R: scale::Decode, { let _gas_limit = params.gas_limit(); - let _callee = params.callee(); let _call_flags = params.call_flags().into_u32(); let _transferred_value = params.transferred_value(); - let _input = params.exec_input(); - unimplemented!("off-chain environment does not support contract invocation") + let input = params.exec_input(); + + let callee = params.callee(); + let callee = scale::Encode::encode(callee); + + let input = scale::Encode::encode(input); + + let callee_account = ::AccountId::decode(&mut &callee[..]).unwrap(); + let mut callee_code_hash = self.code_hash::(&callee_account)?; + + let handler = self.engine.database.get_contract_message_handler(&callee_code_hash.as_mut().to_vec()); + let old_callee = self.engine.get_callee(); + self.engine.set_callee(callee); + + let result = handler(input); + + self.engine.set_callee(old_callee); + + let result = as scale::Decode>::decode(&mut &result[..]) + .expect("failed to decode return value"); + + Ok(result) } fn invoke_contract_delegate( From 4c04eba03d4fff84b29cedd53e9a71ff5147d55b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Tue, 7 Nov 2023 07:45:56 -0300 Subject: [PATCH 23/44] Added invoke_contract_delegate() skeleton. --- crates/env/src/engine/off_chain/impls.rs | 95 +++++++++++++++++------- 1 file changed, 68 insertions(+), 27 deletions(-) diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index 53aff14712..ad3981bb49 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -20,7 +20,7 @@ use crate::{ ConstructorReturnType, CreateParams, DelegateCall, - FromAccountId, + FromAccountId, self, }, event::{ Event, @@ -60,7 +60,7 @@ use schnorrkel::{ /// to be as close to the on-chain behavior as possible. const BUFFER_SIZE: usize = crate::BUFFER_SIZE; -/// Fill me. +/// Proxy function used to simulate code hash and to invoke contract methods. #[cfg(feature = "test_instantiate")] fn execute_contract_call(input: Vec) -> Vec where @@ -87,6 +87,46 @@ where crate::api::get_return_value() } +fn invoke_contract_impl( + env: &mut EnvInstance, + _gas_limit: Option, + _call_flags: u32, + _transferred_value: Option<&::Balance>, + callee_account: Option<&::AccountId>, + code_hash: Option<&::Hash>, + input: Vec, +) -> Result> +where + E: Environment, + Args: scale::Encode, + R: scale::Decode, +{ + let mut callee_code_hash = match callee_account{ + Some(ca) => env.code_hash::(&ca)?, + None => code_hash.unwrap().clone(), + }; + + let handler = env.engine.database.get_contract_message_handler(&callee_code_hash.as_mut().to_vec()); + let old_callee = env.engine.get_callee(); + let mut restore_callee = false; + if let Some(callee_account) = callee_account { + let encoded_callee = scale::Encode::encode(callee_account); + env.engine.set_callee(encoded_callee); + restore_callee = true; + } + + let result = handler(input); + + if restore_callee { + env.engine.set_callee(old_callee); + } + + let result = as scale::Decode>::decode(&mut &result[..]) + .expect("failed to decode return value"); + + Ok(result) +} + impl CryptoHash for Blake2x128 { fn hash(input: &[u8], output: &mut ::Type) { type OutputType = [u8; 16]; @@ -520,31 +560,22 @@ impl TypedEnvBackend for EnvInstance { Args: scale::Encode, R: scale::Decode, { - let _gas_limit = params.gas_limit(); - let _call_flags = params.call_flags().into_u32(); - let _transferred_value = params.transferred_value(); + let gas_limit = params.gas_limit(); + let call_flags = params.call_flags().into_u32(); + let transferred_value = params.transferred_value(); let input = params.exec_input(); - - let callee = params.callee(); - let callee = scale::Encode::encode(callee); - + let callee_account = params.callee(); let input = scale::Encode::encode(input); - let callee_account = ::AccountId::decode(&mut &callee[..]).unwrap(); - let mut callee_code_hash = self.code_hash::(&callee_account)?; - - let handler = self.engine.database.get_contract_message_handler(&callee_code_hash.as_mut().to_vec()); - let old_callee = self.engine.get_callee(); - self.engine.set_callee(callee); - - let result = handler(input); - - self.engine.set_callee(old_callee); - - let result = as scale::Decode>::decode(&mut &result[..]) - .expect("failed to decode return value"); - - Ok(result) + invoke_contract_impl::( + self, + Some(gas_limit), + call_flags, + Some(transferred_value), + Some(callee_account), + None, + input, + ) } fn invoke_contract_delegate( @@ -556,9 +587,19 @@ impl TypedEnvBackend for EnvInstance { Args: scale::Encode, R: scale::Decode, { - let _code_hash = params.code_hash(); - unimplemented!( - "off-chain environment does not support delegated contract invocation" + let call_flags = params.call_flags().into_u32(); + let input = params.exec_input(); + let code_hash = params.code_hash(); + let input = scale::Encode::encode(input); + + invoke_contract_impl::( + self, + None, + call_flags, + None, + None, + Some(code_hash), + input, ) } From 7d4f2652f7ae2a0f410836edc41b79b8d108da49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Tue, 7 Nov 2023 07:55:26 -0300 Subject: [PATCH 24/44] Obviated unsafe block. --- crates/engine/src/database.rs | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/crates/engine/src/database.rs b/crates/engine/src/database.rs index b2b804f7e2..ebbe200a9e 100644 --- a/crates/engine/src/database.rs +++ b/crates/engine/src/database.rs @@ -72,6 +72,7 @@ pub fn code_hash_of_key(key: &Vec) -> [u8; 32]{ #[derive(Default)] pub struct Database { hmap: HashMap, Vec>, + fmap: HashMap, MessageHandler>, } impl Database { @@ -79,6 +80,7 @@ impl Database { pub fn new() -> Self { Database { hmap: HashMap::new(), + fmap: HashMap::new(), } } @@ -162,31 +164,19 @@ impl Database { pub fn set_contract_message_handler(&mut self, handler: MessageHandler) -> [u8; 32]{ let key = contract_key(handler); let hashed_key = message_handler_of_contract_key(&key); - let handler = handler as usize; - let encoded_pointer = scale::Encode::encode(&handler.to_le_bytes()); - self.hmap + self.fmap .entry(hashed_key.to_vec()) - .and_modify(|x| *x = encoded_pointer.clone()) - .or_insert(encoded_pointer); + .and_modify(|x| *x = handler.clone()) + .or_insert(handler); key } pub fn get_contract_message_handler(&mut self, key: &[u8]) -> MessageHandler { let hashed_key = message_handler_of_contract_key(&key); - #[cfg(target_pointer_width = "32")] - const N: usize = 4; - #[cfg(target_pointer_width = "64")] - const N: usize = 8; - let pointer: Option<[u8; N]> = self.hmap + self.fmap .get(&hashed_key.to_vec()) - .map(|encoded_pointer|{ - scale::Decode::decode(&mut &encoded_pointer[..]) - .expect("unable to retrieve message handler") - }); - let pointer = usize::from_le_bytes(pointer.unwrap()); - unsafe { - std::mem::transmute(pointer) - } + .unwrap() + .clone() } pub fn set_code_hash(&mut self, account: &Vec, code_hash: &[u8]) { From 94f3484a3661eaa590a13190f4a7565ebc58e5e8 Mon Sep 17 00:00:00 2001 From: Brian Ramirez Date: Wed, 8 Nov 2023 12:05:25 -0300 Subject: [PATCH 25/44] own_code_hash implementation --- crates/engine/src/database.rs | 6 +++--- crates/env/src/engine/off_chain/impls.rs | 27 ++++++++++++++++++------ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/crates/engine/src/database.rs b/crates/engine/src/database.rs index 268c75b203..24162668b6 100644 --- a/crates/engine/src/database.rs +++ b/crates/engine/src/database.rs @@ -36,7 +36,7 @@ pub fn storage_of_contract_key(who: &[u8], key: &[u8]) -> [u8; 32] { hashed_key } -pub fn code_hash_of_key(key: &Vec) -> [u8; 32]{ +pub fn code_hash_of_key(key: &Vec) -> [u8; 32] { let keyed = key.to_keyed_vec(CODE_HASH_OF); let mut hashed_key: [u8; 32] = [0; 32]; super::hashing::blake2b_256(&keyed[..], &mut hashed_key); @@ -138,7 +138,7 @@ impl Database { } pub fn set_code_hash(&mut self, account: &Vec, code_hash: &[u8]) { - let hashed_key = code_hash_of_key(&account); + let hashed_key = code_hash_of_key(account); self.hmap .entry(hashed_key.to_vec()) .and_modify(|x| *x = code_hash.to_vec()) @@ -146,7 +146,7 @@ impl Database { } pub fn get_code_hash(&self, account: &Vec) -> Option> { - let hashed_key = code_hash_of_key(&account); + let hashed_key = code_hash_of_key(account); self.get(&hashed_key).cloned() } } diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index 6c7c068e74..ecf18d51d6 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -397,7 +397,9 @@ impl EnvBackend for EnvInstance { } fn set_code_hash(&mut self, code_hash: &[u8]) -> Result<()> { - self.engine.database.set_code_hash(&self.engine.get_callee(), code_hash); + self.engine + .database + .set_code_hash(&self.engine.get_callee(), code_hash); Ok(()) } } @@ -590,21 +592,32 @@ impl TypedEnvBackend for EnvInstance { where E: Environment, { - let code_hash = self.engine.database.get_code_hash(&scale::Encode::encode(&account)); - if let Some(code_hash) = code_hash{ - let code_hash = ::Hash::decode(&mut &code_hash[..]).unwrap(); + let code_hash = self + .engine + .database + .get_code_hash(&scale::Encode::encode(&account)); + if let Some(code_hash) = code_hash { + let code_hash = + ::Hash::decode(&mut &code_hash[..]).unwrap(); Ok(code_hash) - }else{ + } else { Err(Error::KeyNotFound) } - } fn own_code_hash(&mut self) -> Result where E: Environment, { - unimplemented!("off-chain environment does not support `own_code_hash`") + let callee = &self.engine.get_callee(); + let code_hash = self.engine.database.get_code_hash(callee); + if let Some(code_hash) = code_hash { + let code_hash = + ::Hash::decode(&mut &code_hash[..]).unwrap(); + Ok(code_hash) + } else { + Err(Error::KeyNotFound) + } } fn call_runtime(&mut self, _call: &Call) -> Result<()> From 4de3aa00c190dfc60de57900814dbea236215b19 Mon Sep 17 00:00:00 2001 From: Brian Ramirez Date: Wed, 8 Nov 2023 12:05:42 -0300 Subject: [PATCH 26/44] Add own-code-hash integration test --- integration-tests/own-code-hash/.gitignore | 9 +++ integration-tests/own-code-hash/Cargo.toml | 27 +++++++ integration-tests/own-code-hash/lib.rs | 91 ++++++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 integration-tests/own-code-hash/.gitignore create mode 100644 integration-tests/own-code-hash/Cargo.toml create mode 100644 integration-tests/own-code-hash/lib.rs diff --git a/integration-tests/own-code-hash/.gitignore b/integration-tests/own-code-hash/.gitignore new file mode 100644 index 0000000000..bf910de10a --- /dev/null +++ b/integration-tests/own-code-hash/.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 \ No newline at end of file diff --git a/integration-tests/own-code-hash/Cargo.toml b/integration-tests/own-code-hash/Cargo.toml new file mode 100644 index 0000000000..c0945fa1fe --- /dev/null +++ b/integration-tests/own-code-hash/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "own-code-hash" +version = "4.3.0" +authors = ["Parity Technologies "] +edition = "2021" +publish = false + +[dependencies] +ink = { path = "../../crates/ink", default-features = false } +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2.5", default-features = false, features = ["derive"], optional = true } + +[dev-dependencies] +ink_e2e = { path = "../../crates/e2e" } + +[lib] +path = "lib.rs" + +[features] +default = ["std"] +std = [ + "ink/std", + "scale/std", + "scale-info/std" +] +ink-as-dependency = [] +e2e-tests = [] \ No newline at end of file diff --git a/integration-tests/own-code-hash/lib.rs b/integration-tests/own-code-hash/lib.rs new file mode 100644 index 0000000000..461c17bd79 --- /dev/null +++ b/integration-tests/own-code-hash/lib.rs @@ -0,0 +1,91 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + +#[ink::contract] +mod own_code_hash { + + #[ink(storage)] + pub struct OwnCodeHash {} + + impl OwnCodeHash { + #[ink(constructor)] + pub fn new() -> Self { + Self {} + } + + /// Returns the code hash of the contract + #[ink(message)] + pub fn own_code_hash(&self) -> Hash { + self.env().own_code_hash().unwrap() + } + + /// Returns the code hash of the contract by providing it's `account_id` + #[ink(message)] + pub fn get_code(&self) -> Hash { + self.env() + .code_hash(&self.env().account_id()) + .expect("Failed to get code hash") + } + } + + impl Default for OwnCodeHash { + fn default() -> Self { + Self::new() + } + } + + #[cfg(test)] + mod tests { + use super::*; + + #[ink::test] + fn get_own_code_hash() { + let own_code_hash = OwnCodeHash::new(); + + let code_hash_via_own: Hash = own_code_hash.own_code_hash(); + + // Ideally we should compare it the code obtained via code_hash (but it is also unimplemented) + assert_eq!(code_hash_via_own, Hash::from([0x0; 32])); + } + } + + #[cfg(all(test, feature = "e2e-tests"))] + mod e2e_tests { + use ink_e2e::build_message; + + use super::*; + + type E2EResult = std::result::Result>; + + #[ink_e2e::test] + async fn get_own_code_hash(mut client: ink_e2e::Client) -> E2EResult<()> { + let constructor = OwnCodeHashRef::new(); + let contract_acc_id = client + .instantiate("own_code_hash", &ink_e2e::bob(), constructor, 0, None) + .await + .expect("instantiate failed") + .account_id; + + let own_code_hash = build_message::(contract_acc_id) + .call(|contract| contract.own_code_hash()); + let own_code_hash_res = client + .call(&ink_e2e::bob(), own_code_hash, 0, None) + .await + .expect("own_code_hash failed"); + + // Compare codes obtained differently with own_code_hash and code_hash + let get_code = build_message::(contract_acc_id) + .call(|contract| contract.get_code()); + let get_code_res = client + .call(&ink_e2e::alice(), get_code, 0, None) + .await + .expect("get_code failed"); + + let code_hash_via_own = own_code_hash_res.return_value(); + let code_hash_via_get = get_code_res.return_value(); + + assert_eq!(code_hash_via_own, code_hash_via_get); + + Ok(()) + } + } +} \ No newline at end of file From 439e90cf7fdd6bdfb786487d59a2af9849ec5c3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Wed, 8 Nov 2023 17:13:02 -0300 Subject: [PATCH 27/44] Remove unused use. --- crates/env/src/engine/off_chain/impls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index ad3981bb49..b05c9558c3 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -20,7 +20,7 @@ use crate::{ ConstructorReturnType, CreateParams, DelegateCall, - FromAccountId, self, + FromAccountId, }, event::{ Event, From 057e98ce9ef2138e62fe3a1c48ef52e5c790273a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Wed, 8 Nov 2023 19:48:42 -0300 Subject: [PATCH 28/44] Added some missing semantics. --- crates/env/src/engine/off_chain/impls.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index 03e300b456..b573267862 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -123,7 +123,7 @@ where let result = as scale::Decode>::decode(&mut &result[..]) .expect("failed to decode return value"); - + Ok(result) } @@ -623,7 +623,10 @@ impl TypedEnvBackend for EnvInstance { R: ConstructorReturnType, { let _gas_limit = params.gas_limit(); - let _endowment = params.endowment(); + + let endowment = params.endowment(); + let endowment = scale::Encode::encode(endowment); + let endowment: u128 = scale::Decode::decode(&mut &endowment[..])?; let salt_bytes = params.salt_bytes(); @@ -647,10 +650,10 @@ impl TypedEnvBackend for EnvInstance { account_id.to_vec() }; - let account_id = ::AccountId::decode(&mut &(account_id_vec[..])).unwrap(); + let mut account_id = ::AccountId::decode(&mut &account_id_vec[..]).unwrap(); let old_callee = self.engine.get_callee(); - self.engine.set_callee(account_id_vec); + self.engine.set_callee(account_id_vec.clone()); let dispatch = < < @@ -667,6 +670,10 @@ impl TypedEnvBackend for EnvInstance { .unwrap_or_else(|e| panic!("Constructor call failed: {:?}", e)); self.set_code_hash(code_hash.as_slice())?; + self.engine.set_contract(account_id_vec.clone()); + self.engine + .database + .set_balance(account_id.as_mut(), endowment); self.engine.set_callee(old_callee); From b684b740567befba65bc52d43e9e5e22e5289b01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Thu, 9 Nov 2023 09:04:17 -0300 Subject: [PATCH 29/44] Passed through rustfmt. --- crates/engine/src/database.rs | 17 ++++++---------- crates/env/src/engine/off_chain/impls.rs | 25 ++++++++++++++++-------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/crates/engine/src/database.rs b/crates/engine/src/database.rs index 76b8466e6a..127016f096 100644 --- a/crates/engine/src/database.rs +++ b/crates/engine/src/database.rs @@ -40,19 +40,17 @@ pub fn storage_of_contract_key(who: &[u8], key: &[u8]) -> [u8; 32] { pub type MessageHandler = fn(Vec) -> Vec; -pub fn contract_key(f: MessageHandler) -> [u8; 32]{ +pub fn contract_key(f: MessageHandler) -> [u8; 32] { let f = f as usize; let f = f.to_le_bytes(); - let keyed = f - .to_vec().to_keyed_vec(CONTRACT_PREFIX); + let keyed = f.to_vec().to_keyed_vec(CONTRACT_PREFIX); let mut ret: [u8; 32] = [0; 32]; super::hashing::blake2b_256(&keyed[..], &mut ret); ret } -pub fn message_handler_of_contract_key(key: &[u8]) -> [u8; 32]{ - let keyed = key.to_vec() - .to_keyed_vec(MSG_HANDLER_OF); +pub fn message_handler_of_contract_key(key: &[u8]) -> [u8; 32] { + let keyed = key.to_vec().to_keyed_vec(MSG_HANDLER_OF); let mut hashed_key: [u8; 32] = [0; 32]; super::hashing::blake2b_256(&keyed[..], &mut hashed_key); hashed_key @@ -161,7 +159,7 @@ impl Database { .or_insert(encoded_balance); } - pub fn set_contract_message_handler(&mut self, handler: MessageHandler) -> [u8; 32]{ + pub fn set_contract_message_handler(&mut self, handler: MessageHandler) -> [u8; 32] { let key = contract_key(handler); let hashed_key = message_handler_of_contract_key(&key); self.fmap @@ -173,10 +171,7 @@ impl Database { pub fn get_contract_message_handler(&mut self, key: &[u8]) -> MessageHandler { let hashed_key = message_handler_of_contract_key(&key); - self.fmap - .get(&hashed_key.to_vec()) - .unwrap() - .clone() + self.fmap.get(&hashed_key.to_vec()).unwrap().clone() } pub fn set_code_hash(&mut self, account: &Vec, code_hash: &[u8]) { diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index b573267862..0d61e518e2 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -101,12 +101,15 @@ where Args: scale::Encode, R: scale::Decode, { - let mut callee_code_hash = match callee_account{ + let mut callee_code_hash = match callee_account { Some(ca) => env.code_hash::(&ca)?, None => code_hash.unwrap().clone(), }; - let handler = env.engine.database.get_contract_message_handler(&callee_code_hash.as_mut().to_vec()); + let handler = env + .engine + .database + .get_contract_message_handler(&callee_code_hash.as_mut().to_vec()); let old_callee = env.engine.get_callee(); let mut restore_callee = false; if let Some(callee_account) = callee_account { @@ -121,8 +124,9 @@ where env.engine.set_callee(old_callee); } - let result = as scale::Decode>::decode(&mut &result[..]) - .expect("failed to decode return value"); + let result = + as scale::Decode>::decode(&mut &result[..]) + .expect("failed to decode return value"); Ok(result) } @@ -483,7 +487,11 @@ impl EnvBackend for EnvInstance { ::Type: crate::reflect::ContractMessageDecoder, { - ink_primitives::types::Hash::from(self.engine.database.set_contract_message_handler(execute_contract_call::)) + ink_primitives::types::Hash::from( + self.engine + .database + .set_contract_message_handler(execute_contract_call::), + ) } } @@ -636,11 +644,11 @@ impl TypedEnvBackend for EnvInstance { let input = params.exec_input(); let input = scale::Encode::encode(input); - //Compute account for instantiated contract. + // Compute account for instantiated contract. let account_id_vec = { let mut account_input = Vec::::new(); account_input.extend(&b"contract_addr_v1".to_vec()); - if let Some(caller) = &self.engine.exec_context.caller{ + if let Some(caller) = &self.engine.exec_context.caller { scale::Encode::encode_to(&caller.as_bytes(), &mut account_input); } account_input.extend(&input); @@ -650,7 +658,8 @@ impl TypedEnvBackend for EnvInstance { account_id.to_vec() }; - let mut account_id = ::AccountId::decode(&mut &account_id_vec[..]).unwrap(); + let mut account_id = + ::AccountId::decode(&mut &account_id_vec[..]).unwrap(); let old_callee = self.engine.get_callee(); self.engine.set_callee(account_id_vec.clone()); From cd6e687c79c05ba21fea13522de8c294af9ab071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Thu, 9 Nov 2023 09:11:41 -0300 Subject: [PATCH 30/44] Passed through clippy. --- crates/engine/src/database.rs | 6 +++--- crates/env/src/engine/off_chain/impls.rs | 18 ++++++++---------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/crates/engine/src/database.rs b/crates/engine/src/database.rs index 127016f096..2c7ea2b925 100644 --- a/crates/engine/src/database.rs +++ b/crates/engine/src/database.rs @@ -164,14 +164,14 @@ impl Database { let hashed_key = message_handler_of_contract_key(&key); self.fmap .entry(hashed_key.to_vec()) - .and_modify(|x| *x = handler.clone()) + .and_modify(|x| *x = handler) .or_insert(handler); key } pub fn get_contract_message_handler(&mut self, key: &[u8]) -> MessageHandler { - let hashed_key = message_handler_of_contract_key(&key); - self.fmap.get(&hashed_key.to_vec()).unwrap().clone() + let hashed_key = message_handler_of_contract_key(key); + *self.fmap.get(&hashed_key.to_vec()).unwrap() } pub fn set_code_hash(&mut self, account: &Vec, code_hash: &[u8]) { diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index 0d61e518e2..6d09e87a78 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -62,9 +62,8 @@ const BUFFER_SIZE: usize = crate::BUFFER_SIZE; /// Proxy function used to simulate code hash and to invoke contract methods. #[cfg(feature = "test_instantiate")] -fn execute_contract_call(input: Vec) -> Vec +fn execute_contract_call(input: Vec) -> Vec where - E: Environment, ContractRef: crate::ContractReverseReference, ::Type: crate::reflect::ContractMessageDecoder, @@ -87,7 +86,7 @@ where crate::api::get_return_value() } -fn invoke_contract_impl( +fn invoke_contract_impl( env: &mut EnvInstance, _gas_limit: Option, _call_flags: u32, @@ -98,18 +97,17 @@ fn invoke_contract_impl( ) -> Result> where E: Environment, - Args: scale::Encode, R: scale::Decode, { let mut callee_code_hash = match callee_account { - Some(ca) => env.code_hash::(&ca)?, - None => code_hash.unwrap().clone(), + Some(ca) => env.code_hash::(ca)?, + None => *code_hash.unwrap(), }; let handler = env .engine .database - .get_contract_message_handler(&callee_code_hash.as_mut().to_vec()); + .get_contract_message_handler(callee_code_hash.as_mut()); let old_callee = env.engine.get_callee(); let mut restore_callee = false; if let Some(callee_account) = callee_account { @@ -490,7 +488,7 @@ impl EnvBackend for EnvInstance { ink_primitives::types::Hash::from( self.engine .database - .set_contract_message_handler(execute_contract_call::), + .set_contract_message_handler(execute_contract_call::), ) } } @@ -577,7 +575,7 @@ impl TypedEnvBackend for EnvInstance { let callee_account = params.callee(); let input = scale::Encode::encode(input); - invoke_contract_impl::( + invoke_contract_impl::( self, Some(gas_limit), call_flags, @@ -602,7 +600,7 @@ impl TypedEnvBackend for EnvInstance { let code_hash = params.code_hash(); let input = scale::Encode::encode(input); - invoke_contract_impl::( + invoke_contract_impl::( self, None, call_flags, From c9c7d85e2afe3f4628b298445d1a15244e1d859b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Thu, 9 Nov 2023 17:06:34 -0300 Subject: [PATCH 31/44] Fixed own_code_hash test. --- integration-tests/own-code-hash/Cargo.toml | 7 +++-- integration-tests/own-code-hash/lib.rs | 34 +++++++++++++++++++--- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/integration-tests/own-code-hash/Cargo.toml b/integration-tests/own-code-hash/Cargo.toml index c0945fa1fe..98b1134dbf 100644 --- a/integration-tests/own-code-hash/Cargo.toml +++ b/integration-tests/own-code-hash/Cargo.toml @@ -17,11 +17,14 @@ ink_e2e = { path = "../../crates/e2e" } path = "lib.rs" [features] -default = ["std"] +default = ["std", "test_instantiate"] std = [ "ink/std", "scale/std", "scale-info/std" ] ink-as-dependency = [] -e2e-tests = [] \ No newline at end of file +e2e-tests = [] +test_instantiate = [ + "ink/test_instantiate", +] diff --git a/integration-tests/own-code-hash/lib.rs b/integration-tests/own-code-hash/lib.rs index 461c17bd79..d0b4f1559f 100644 --- a/integration-tests/own-code-hash/lib.rs +++ b/integration-tests/own-code-hash/lib.rs @@ -33,18 +33,44 @@ mod own_code_hash { } } - #[cfg(test)] + #[cfg(all(test, feature = "test_instantiate"))] mod tests { use super::*; #[ink::test] fn get_own_code_hash() { - let own_code_hash = OwnCodeHash::new(); + let code_hash = ink::env::simulate_code_upload::(); + let address = + { + let create_params = ink::env::call::build_create::() + .code_hash(code_hash) + .gas_limit(0) + .endowment(0) + .exec_input(ink::env::call::ExecutionInput::new( + ink::env::call::Selector::new(ink::selector_bytes!("new")), + )) + .salt_bytes(&[0_u8; 4]) + .returns::() + .params(); + + let cr = ink::env::instantiate_contract(&create_params) + .unwrap_or_else(|error| { + panic!( + "Received an error from the Contracts pallet while instantiating: {:?}", + error + ) + }) + .unwrap_or_else(|error| { + panic!("Received a `LangError` while instatiating: {:?}", error) + }); + ink::ToAccountId::::to_account_id(&cr) + }; + let own_code_hash = OwnCodeHash::new(); + ink::env::test::set_callee::(address); let code_hash_via_own: Hash = own_code_hash.own_code_hash(); - // Ideally we should compare it the code obtained via code_hash (but it is also unimplemented) - assert_eq!(code_hash_via_own, Hash::from([0x0; 32])); + assert_eq!(code_hash_via_own, code_hash); } } From 7a8f98d45071ff017a0b76e646288c62187ad507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Thu, 9 Nov 2023 17:44:13 -0300 Subject: [PATCH 32/44] Tightening up code. --- crates/env/src/api.rs | 43 -------------------- crates/env/src/backend.rs | 12 ------ crates/env/src/engine/off_chain/impls.rs | 41 +++++++++---------- crates/env/src/engine/off_chain/test_api.rs | 20 +++++++++ crates/ink/codegen/src/generator/dispatch.rs | 5 --- 5 files changed, 39 insertions(+), 82 deletions(-) diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index 1fdd35c9f0..b90213068a 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -204,27 +204,6 @@ where }) } -/// Same as set_contract_storage(), but gets the key from a function pointer. -/// This is necessary for integration tests, because we can't get the key from -/// the type declaration. -#[cfg(feature = "test_instantiate")] -pub fn set_contract_storage_test(value: &V) -> Option -where - V: Storable, - Ref: ink_storage_traits::StorageLayout, -{ - let x = Ref::layout as usize; - let x = ((x | (x >> 32)) & 0xFFFFFFFF) as u32; - set_contract_storage(&x, value) -} - -/// Dummy set_contract_storage_test() for non-test environments. The compiler -/// should optimize this away. -#[cfg(not(feature = "test_instantiate"))] -pub fn set_contract_storage_test(_value: &V) -> Option { - None -} - /// Returns the value stored under the given storage key in the contract's storage if any. /// /// # Errors @@ -477,14 +456,6 @@ where }) } -/// Retrieves the value stored by return_value(). -#[cfg(feature = "test_instantiate")] -pub fn get_return_value() -> Vec { - ::on_instance(|instance| { - EnvBackend::get_return_value(instance) - }) -} - /// Appends the given message to the debug message buffer. pub fn debug_message(message: &str) { ::on_instance(|instance| { @@ -837,17 +808,3 @@ where TypedEnvBackend::call_runtime::(instance, call) }) } - -/// Gets a pseudo code hash for a contract ref. -#[cfg(feature = "test_instantiate")] -pub fn simulate_code_upload() -> ink_primitives::types::Hash -where - E: Environment, - ContractRef: crate::ContractReverseReference, - ::Type: - crate::reflect::ContractMessageDecoder, -{ - ::on_instance(|instance| { - EnvBackend::simulate_code_upload::(instance) - }) -} diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index ed90c32ce2..7756e79fbc 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -266,10 +266,6 @@ pub trait EnvBackend { where R: scale::Encode; - /// Retrieves the value stored by return_value(). - #[cfg(feature = "test_instantiate")] - fn get_return_value(&mut self) -> Vec; - /// Emit a custom debug message. /// /// The message is appended to the debug buffer which is then supplied to the calling @@ -366,14 +362,6 @@ pub trait EnvBackend { /// /// - If the supplied `code_hash` cannot be found on-chain. fn set_code_hash(&mut self, code_hash: &[u8]) -> Result<()>; - - #[cfg(feature = "test_instantiate")] - fn simulate_code_upload(&mut self) -> ink_primitives::types::Hash - where - E: Environment, - ContractRef: crate::ContractReverseReference, - ::Type: - crate::reflect::ContractMessageDecoder; } /// Environmental contract functionality. diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index 6d09e87a78..3ace2036dd 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -61,7 +61,6 @@ use schnorrkel::{ const BUFFER_SIZE: usize = crate::BUFFER_SIZE; /// Proxy function used to simulate code hash and to invoke contract methods. -#[cfg(feature = "test_instantiate")] fn execute_contract_call(input: Vec) -> Vec where ContractRef: crate::ContractReverseReference, @@ -83,7 +82,7 @@ where crate::reflect::ExecuteDispatchable::execute_dispatchable(dispatch) .unwrap_or_else(|e| panic!("Message call failed: {:?}", e)); - crate::api::get_return_value() + crate::test::get_return_value() } fn invoke_contract_impl( @@ -256,6 +255,24 @@ impl EnvInstance { ext_fn(&self.engine, full_scope); scale::Decode::decode(&mut &full_scope[..]).map_err(Into::into) } + + pub fn get_return_value(&mut self) -> Vec { + self.engine.get_storage(&[255_u8; 32]).unwrap().to_vec() + } + + pub fn upload_code(&mut self) -> ink_primitives::types::Hash + where + E: Environment, + ContractRef: crate::ContractReverseReference, + ::Type: + crate::reflect::ContractMessageDecoder, + { + ink_primitives::types::Hash::from( + self.engine + .database + .set_contract_message_handler(execute_contract_call::), + ) + } } impl EnvBackend for EnvInstance { @@ -338,11 +355,6 @@ impl EnvBackend for EnvInstance { self.engine.set_storage(&[255_u8; 32], &v[..]); } - #[cfg(feature = "test_instantiate")] - fn get_return_value(&mut self) -> Vec { - self.engine.get_storage(&[255_u8; 32]).unwrap().to_vec() - } - fn debug_message(&mut self, message: &str) { self.engine.debug_message(message) } @@ -476,21 +488,6 @@ impl EnvBackend for EnvInstance { .set_code_hash(&self.engine.get_callee(), code_hash); Ok(()) } - - #[cfg(feature = "test_instantiate")] - fn simulate_code_upload(&mut self) -> ink_primitives::types::Hash - where - E: Environment, - ContractRef: crate::ContractReverseReference, - ::Type: - crate::reflect::ContractMessageDecoder, - { - ink_primitives::types::Hash::from( - self.engine - .database - .set_contract_message_handler(execute_contract_call::), - ) - } } impl TypedEnvBackend for EnvInstance { diff --git a/crates/env/src/engine/off_chain/test_api.rs b/crates/env/src/engine/off_chain/test_api.rs index 7e00c335b8..868f04d370 100644 --- a/crates/env/src/engine/off_chain/test_api.rs +++ b/crates/env/src/engine/off_chain/test_api.rs @@ -430,3 +430,23 @@ macro_rules! pay_with_call { $contract.$message($ ($params) ,*) }} } + +/// Retrieves the value stored by return_value(). +pub fn get_return_value() -> Vec { + ::on_instance(|instance| { + instance.get_return_value() + }) +} + +/// Gets a pseudo code hash for a contract ref. +pub fn upload_code() -> ink_primitives::types::Hash +where + E: Environment, + ContractRef: crate::ContractReverseReference, + ::Type: + crate::reflect::ContractMessageDecoder, +{ + ::on_instance(|instance| { + instance.upload_code::() + }) +} diff --git a/crates/ink/codegen/src/generator/dispatch.rs b/crates/ink/codegen/src/generator/dispatch.rs index a5721996e4..d374a2597a 100644 --- a/crates/ink/codegen/src/generator/dispatch.rs +++ b/crates/ink/codegen/src/generator/dispatch.rs @@ -476,8 +476,6 @@ impl Dispatch<'_> { let span = self.contract.module().storage().span(); let storage_ident = self.contract.module().storage().ident(); - let ref_ident = - quote::format_ident!("{}Ref", self.contract.module().storage().ident()); let constructors_variants = constructors.iter().enumerate().map(|(index, item)| { let constructor_span = item.constructor.span(); @@ -588,9 +586,6 @@ impl Dispatch<'_> { &<#storage_ident as ::ink::storage::traits::StorageKey>::KEY, contract, ); - ::ink::env::set_contract_storage_test::<#storage_ident, #ref_ident>( - contract, - ); } ::ink::env::return_value::< From 37a00d999e935833cbca37645239c5f25100b94f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Thu, 9 Nov 2023 20:57:57 -0300 Subject: [PATCH 33/44] Improved contract invokation tests. Fixed some things. --- crates/env/src/engine/off_chain/impls.rs | 1 + .../instantiate-contract/Cargo.toml | 11 +- .../{other_contract => contract1}/Cargo.toml | 2 +- .../{other_contract => contract1}/lib.rs | 10 +- .../instantiate-contract/contract2/Cargo.toml | 35 +++ .../instantiate-contract/contract2/lib.rs | 42 ++++ integration-tests/instantiate-contract/lib.rs | 222 ++++++++++++++++-- 7 files changed, 298 insertions(+), 25 deletions(-) rename integration-tests/instantiate-contract/{other_contract => contract1}/Cargo.toml (96%) rename integration-tests/instantiate-contract/{other_contract => contract1}/lib.rs (82%) create mode 100644 integration-tests/instantiate-contract/contract2/Cargo.toml create mode 100644 integration-tests/instantiate-contract/contract2/lib.rs diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index 3ace2036dd..1308e0129e 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -646,6 +646,7 @@ impl TypedEnvBackend for EnvInstance { if let Some(caller) = &self.engine.exec_context.caller { scale::Encode::encode_to(&caller.as_bytes(), &mut account_input); } + account_input.extend(&code_hash); account_input.extend(&input); account_input.extend(salt_bytes.as_ref()); let mut account_id = [0_u8; 32]; diff --git a/integration-tests/instantiate-contract/Cargo.toml b/integration-tests/instantiate-contract/Cargo.toml index 6a834c0eca..49dfcabb90 100644 --- a/integration-tests/instantiate-contract/Cargo.toml +++ b/integration-tests/instantiate-contract/Cargo.toml @@ -13,13 +13,15 @@ std = [ "ink/std", "scale/std", "scale-info/std", - "other_contract/std" + "contract1/std", + "contract2/std", ] ink-as-dependency = [] e2e-tests = [] test_instantiate = [ "ink/test_instantiate", - "other_contract/test_instantiate" + "contract1/test_instantiate", + "contract2/test_instantiate", ] [dependencies] @@ -30,7 +32,10 @@ scale = { package = "parity-scale-codec", version = "=3.6.5", default-features = scale-info = { version = "2.6", default-features = false, features = [ "derive", ], optional = true } -other_contract = { path = "./other_contract", default-features = false, features = [ +contract1 = { path = "./contract1", default-features = false, features = [ + "ink-as-dependency", +] } +contract2 = { path = "./contract2", default-features = false, features = [ "ink-as-dependency", ] } diff --git a/integration-tests/instantiate-contract/other_contract/Cargo.toml b/integration-tests/instantiate-contract/contract1/Cargo.toml similarity index 96% rename from integration-tests/instantiate-contract/other_contract/Cargo.toml rename to integration-tests/instantiate-contract/contract1/Cargo.toml index 94f4c9c0f7..2a7ff46715 100644 --- a/integration-tests/instantiate-contract/other_contract/Cargo.toml +++ b/integration-tests/instantiate-contract/contract1/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "other_contract" +name = "contract1" version = "0.1.0" edition = "2021" authors = ["Víctor M. González "] diff --git a/integration-tests/instantiate-contract/other_contract/lib.rs b/integration-tests/instantiate-contract/contract1/lib.rs similarity index 82% rename from integration-tests/instantiate-contract/other_contract/lib.rs rename to integration-tests/instantiate-contract/contract1/lib.rs index ab96aea2e7..2f1053ac60 100644 --- a/integration-tests/instantiate-contract/other_contract/lib.rs +++ b/integration-tests/instantiate-contract/contract1/lib.rs @@ -1,16 +1,16 @@ #![cfg_attr(not(feature = "std"), no_std, no_main)] -pub use self::other_contract::OtherContractRef; +pub use self::contract1::Contract1Ref; #[ink::contract()] -mod other_contract { +mod contract1 { #[ink(storage)] - pub struct OtherContract { + pub struct Contract1 { x: u32, } - impl OtherContract { + impl Contract1 { /// Creates a new Template contract. #[ink(constructor)] pub fn new() -> Self { @@ -34,7 +34,7 @@ mod other_contract { } } - impl Default for OtherContract { + impl Default for Contract1 { fn default() -> Self { Self::new() } diff --git a/integration-tests/instantiate-contract/contract2/Cargo.toml b/integration-tests/instantiate-contract/contract2/Cargo.toml new file mode 100644 index 0000000000..76e239a51d --- /dev/null +++ b/integration-tests/instantiate-contract/contract2/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "contract2" +version = "0.1.0" +edition = "2021" +authors = ["Víctor M. González "] + +[lib] +path = "lib.rs" + +[features] +default = ["std", "test_instantiate"] +std = ["ink/std", "scale/std", "scale-info/std"] +ink-as-dependency = [] +e2e-tests = [] +test_instantiate = [ + "ink/test_instantiate" +] + +[dependencies] +ink = { path = "../../../crates/ink", default-features = false } +scale = { package = "parity-scale-codec", version = "=3.6.5", default-features = false, features = [ + "derive", +] } +scale-info = { version = "2.6", default-features = false, features = [ + "derive", +], optional = true } + +[dev-dependencies] +ink_e2e = { path = "../../../crates/e2e" } + +[profile.dev] +overflow-checks = false + +[profile.release] +overflow-checks = false diff --git a/integration-tests/instantiate-contract/contract2/lib.rs b/integration-tests/instantiate-contract/contract2/lib.rs new file mode 100644 index 0000000000..01172827d3 --- /dev/null +++ b/integration-tests/instantiate-contract/contract2/lib.rs @@ -0,0 +1,42 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + +pub use self::contract2::Contract2Ref; + +#[ink::contract()] +mod contract2 { + + #[ink(storage)] + pub struct Contract2 { + x: u64, + } + + impl Contract2 { + /// Creates a new Template contract. + #[ink(constructor)] + pub fn new() -> Self { + Self { x: 0 } + } + + #[ink(message)] + pub fn get_x(&self) -> u32 { + 123456 + } + + #[ink(message)] + pub fn set_x(&mut self, x: u64) { + self.x = x; + } + + /// Returns the hash code of the contract through the function 'own_code_hash'. + #[ink(message)] + pub fn own_code_hash(&self) -> Hash { + self.env().own_code_hash().unwrap() + } + } + + impl Default for Contract2 { + fn default() -> Self { + Self::new() + } + } +} diff --git a/integration-tests/instantiate-contract/lib.rs b/integration-tests/instantiate-contract/lib.rs index b628dd9df1..6ee8336920 100644 --- a/integration-tests/instantiate-contract/lib.rs +++ b/integration-tests/instantiate-contract/lib.rs @@ -2,28 +2,37 @@ #[ink::contract] mod instantiate_contract { - use other_contract::OtherContractRef; + use contract1::Contract1Ref; + use contract2::Contract2Ref; + use ink::env::{ + call::{ + build_create, + build_call, + ExecutionInput, + Selector, + }, + }; #[ink(storage)] - pub struct InstantiateContract {} + pub struct ContractTester {} - impl InstantiateContract { + impl ContractTester { #[ink(constructor)] pub fn new() -> Self { - Self {} + Self{ } } #[ink(message)] - pub fn instantiate_other_contract(&self, code_hash: Hash) -> OtherContractRef { - let create_params = ink::env::call::build_create::() + pub fn instantiate_contract1(&self, code_hash: Hash) -> Contract1Ref { + let create_params = build_create::() .code_hash(code_hash) .gas_limit(0) .endowment(0) - .exec_input(ink::env::call::ExecutionInput::new( - ink::env::call::Selector::new(ink::selector_bytes!("new")), + .exec_input(ExecutionInput::new( + Selector::new(ink::selector_bytes!("new")), )) .salt_bytes(&[0x0; 4]) - .returns::() + .returns::() .params(); self.env() @@ -38,9 +47,117 @@ mod instantiate_contract { panic!("Received a `LangError` while instatiating: {:?}", error) }) } + + #[ink(message)] + pub fn instantiate_contract2(&self, code_hash: Hash) -> Contract2Ref { + let create_params = build_create::() + .code_hash(code_hash) + .gas_limit(0) + .endowment(0) + .exec_input(ExecutionInput::new( + Selector::new(ink::selector_bytes!("new")), + )) + .salt_bytes(&[0x0; 4]) + .returns::() + .params(); + + self.env() + .instantiate_contract(&create_params) + .unwrap_or_else(|error| { + panic!( + "Received an error from the Contracts pallet while instantiating: {:?}", + error + ) + }) + .unwrap_or_else(|error| { + panic!("Received a `LangError` while instatiating: {:?}", error) + }) + } + + #[ink(message)] + pub fn contract1_get_x(&self, contract1_address: [u8; 32]) -> u32 { + let call = build_call() + .call(AccountId::from(contract1_address)) + .gas_limit(0) + .transferred_value(0) + .exec_input( + ExecutionInput::new(Selector::new(ink::selector_bytes!("get_x"))) + ) + .returns::() + .params(); + + self.env() + .invoke_contract(&call) + .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)) + } + + #[ink(message)] + pub fn contract2_get_x(&self, contract2_address: [u8; 32]) -> u32 { + let call = build_call() + .call(AccountId::from(contract2_address)) + .gas_limit(0) + .transferred_value(0) + .exec_input( + ExecutionInput::new(Selector::new(ink::selector_bytes!("get_x"))) + ) + .returns::() + .params(); + + self.env() + .invoke_contract(&call) + .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)) + } + + #[ink(message)] + pub fn contract1_set_x(&self, contract1_address: [u8; 32], new_x: u32) { + let call = ink::env::call::build_call() + .call(AccountId::from(contract1_address)) + .gas_limit(0) + .transferred_value(0) + .exec_input( + ExecutionInput::new(Selector::new(ink::selector_bytes!("set_x"))) + .push_arg(new_x) + ) + .returns::<()>() + .params(); + + self.env() + .invoke_contract(&call) + .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)) + } + + #[ink(message)] + pub fn contract2_set_x(&self, contract2_address: [u8; 32], new_x: u64) { + let call = ink::env::call::build_call() + .call(AccountId::from(contract2_address)) + .gas_limit(0) + .transferred_value(0) + .exec_input( + ExecutionInput::new(Selector::new(ink::selector_bytes!("set_x"))) + .push_arg(new_x) + ) + .returns::<()>() + .params(); + + self.env() + .invoke_contract(&call) + .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)) + } } - impl Default for InstantiateContract { + impl Default for ContractTester { fn default() -> Self { Self::new() } @@ -49,12 +166,85 @@ mod instantiate_contract { #[cfg(all(test, feature = "test_instantiate"))] mod tests { use super::*; + use ink::{ + env::{ + DefaultEnvironment, + }, + primitives::AccountId, + }; + + fn instantiate_contract1(contract: &ContractTester, code_hash: Hash) -> AccountId{ + let cr = contract.instantiate_contract1(code_hash); + ink::ToAccountId::::to_account_id(&cr) + } + + fn instantiate_contract2(contract: &ContractTester, code_hash: Hash) -> AccountId{ + let cr = contract.instantiate_contract2(code_hash); + ink::ToAccountId::::to_account_id(&cr) + } + + fn to_array(address: &mut AccountId) -> [u8; 32]{ + let temp: &[u8; 32] = address.as_mut(); + temp.clone() + } #[ink::test] - fn instantiate_other_contract() { - let contract = InstantiateContract::new(); - let code_hash = Hash::from([0x42; 32]); - let _ = contract.instantiate_other_contract(code_hash); + fn test_contract1() { + let contract = ContractTester::new(); + let code_hash1 = ink::env::test::upload_code::(); + let code_hash2 = ink::env::test::upload_code::(); + + // Set different caller AccountIds, so that instantiate_contract will generate different account ids. + ink::env::test::set_caller::([1_u8; 32].into()); + let mut contract1_address1_account = instantiate_contract1(&contract, code_hash1); + let mut contract2_address1_account = instantiate_contract2(&contract, code_hash2); + ink::env::test::set_caller::([2_u8; 32].into()); + let mut contract1_address2_account = instantiate_contract1(&contract, code_hash1); + let mut contract2_address2_account = instantiate_contract2(&contract, code_hash2); + + let contract1_address1 = to_array(&mut contract1_address1_account); + let contract1_address2 = to_array(&mut contract1_address2_account); + let contract2_address1 = to_array(&mut contract2_address1_account); + let contract2_address2 = to_array(&mut contract2_address2_account); + + let check_hashes = |a, b, c|{ + let x = ink::env::code_hash::(a) + .expect("failed to get code hash"); + let y = ink::env::code_hash::(b) + .expect("failed to get code hash"); + + assert_eq!(x, c); + assert_eq!(y, c); + }; + check_hashes(&contract1_address1_account, &contract1_address2_account, code_hash1.clone()); + check_hashes(&contract2_address1_account, &contract2_address2_account, code_hash2.clone()); + + let check_values1 = |a, b| { + let x = contract.contract1_get_x(contract1_address1.clone()); + let y = contract.contract1_get_x(contract1_address2.clone()); + assert_eq!(x, a); + assert_eq!(y, b); + }; + let check_values2 = |a, b| { + let x = contract.contract2_get_x(contract2_address1.clone()); + let y = contract.contract2_get_x(contract2_address2.clone()); + assert_eq!(x, a); + assert_eq!(y, b); + }; + + check_values1(42, 42); + check_values2(123456, 123456); + contract.contract2_set_x(contract2_address1.clone(), 78); + check_values1(42, 42); + check_values2(123456, 123456); + contract.contract1_set_x(contract1_address1.clone(), 123); + contract.contract2_set_x(contract2_address2.clone(), 87); + check_values1(123, 42); + check_values2(123456, 123456); + contract.contract1_set_x(contract1_address2.clone(), 321); + check_values1(123, 321); + check_values2(123456, 123456); + } } @@ -70,7 +260,7 @@ mod instantiate_contract { async fn instantiate_other_contract( mut client: ink_e2e::Client, ) -> E2EResult<()> { - let constructor = InstantiateContractRef::new(); + let constructor = ContractTesterRef::new(); let contract_acc_id = client .instantiate( @@ -90,7 +280,7 @@ mod instantiate_contract { .expect("instantiate failed") .code_hash; - let instantiate_other_contract = build_message::( + let instantiate_other_contract = build_message::( contract_acc_id.clone(), ) .call(|contract| { From 1fe7be94380b6861c1bf7afc6897451a547d3a21 Mon Sep 17 00:00:00 2001 From: Brian Ramirez Date: Fri, 10 Nov 2023 11:58:27 -0300 Subject: [PATCH 34/44] caller-is-origin implementation --- crates/engine/src/exec_context.rs | 2 ++ crates/engine/src/ext.rs | 4 ++++ crates/env/src/engine/off_chain/impls.rs | 6 +++++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/crates/engine/src/exec_context.rs b/crates/engine/src/exec_context.rs index 05bcf699b0..66003836a2 100644 --- a/crates/engine/src/exec_context.rs +++ b/crates/engine/src/exec_context.rs @@ -45,6 +45,8 @@ pub struct ExecContext { pub block_timestamp: BlockTimestamp, /// Known contract accounts pub contracts: Vec>, + + pub depth: u8 } impl ExecContext { diff --git a/crates/engine/src/ext.rs b/crates/engine/src/ext.rs index 387eb57127..d1a7245f55 100644 --- a/crates/engine/src/ext.rs +++ b/crates/engine/src/ext.rs @@ -505,6 +505,10 @@ impl Engine { Err(_) => Err(Error::EcdsaRecoveryFailed), } } + + pub fn caller_is_origin(&self) -> bool { + self.exec_context.depth == 0 + } } /// Copies the `slice` into `output`. diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index 1308e0129e..1468b0f276 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -113,12 +113,14 @@ where let encoded_callee = scale::Encode::encode(callee_account); env.engine.set_callee(encoded_callee); restore_callee = true; + env.engine.exec_context.depth += 1; } let result = handler(input); if restore_callee { env.engine.set_callee(old_callee); + env.engine.exec_context.depth -= 1; } let result = @@ -658,6 +660,7 @@ impl TypedEnvBackend for EnvInstance { ::AccountId::decode(&mut &account_id_vec[..]).unwrap(); let old_callee = self.engine.get_callee(); + self.engine.exec_context.depth+=1; self.engine.set_callee(account_id_vec.clone()); let dispatch = < @@ -681,6 +684,7 @@ impl TypedEnvBackend for EnvInstance { .set_balance(account_id.as_mut(), endowment); self.engine.set_callee(old_callee); + self.engine.exec_context.depth-=1; Ok(Ok(R::ok( >::from_account_id(account_id), @@ -725,7 +729,7 @@ impl TypedEnvBackend for EnvInstance { where E: Environment, { - unimplemented!("off-chain environment does not support cross-contract calls") + self.engine.caller_is_origin() } fn code_hash(&mut self, account: &E::AccountId) -> Result From 648c65c7fedbfb6784f27804ff96a17c1e296fb4 Mon Sep 17 00:00:00 2001 From: Brian Ramirez Date: Fri, 10 Nov 2023 14:42:36 -0300 Subject: [PATCH 35/44] Fix integration tests --- integration-tests/caller-is-origin/Cargo.toml | 29 +++ .../contract_to_call/Cargo.toml | 28 +++ .../caller-is-origin/contract_to_call/lib.rs | 29 +++ integration-tests/caller-is-origin/lib.rs | 166 ++++++++++++++++++ 4 files changed, 252 insertions(+) create mode 100644 integration-tests/caller-is-origin/Cargo.toml create mode 100644 integration-tests/caller-is-origin/contract_to_call/Cargo.toml create mode 100644 integration-tests/caller-is-origin/contract_to_call/lib.rs create mode 100644 integration-tests/caller-is-origin/lib.rs diff --git a/integration-tests/caller-is-origin/Cargo.toml b/integration-tests/caller-is-origin/Cargo.toml new file mode 100644 index 0000000000..73828e3035 --- /dev/null +++ b/integration-tests/caller-is-origin/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "invoke_contract" +version = "4.3.0" +authors = ["Parity Technologies "] +edition = "2021" +publish = false + +[dependencies] +ink = { path = "../../crates/ink", default-features = false } +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2.5", default-features = false, features = ["derive"], optional = true } +contract_to_call = { path = "./contract_to_call", default-features = false, features = ["ink-as-dependency"] } + +[dev-dependencies] +ink_e2e = { path = "../../crates/e2e" } + +[lib] +path = "lib.rs" + +[features] +default = ["std", "test_instantiate"] +std = [ + "ink/std", + "scale/std", + "scale-info/std" +] +test_instantiate = ["ink/test_instantiate", "contract_to_call/test_instantiate"] +ink-as-dependency = [] +e2e-tests = [] \ No newline at end of file diff --git a/integration-tests/caller-is-origin/contract_to_call/Cargo.toml b/integration-tests/caller-is-origin/contract_to_call/Cargo.toml new file mode 100644 index 0000000000..26d64d11b7 --- /dev/null +++ b/integration-tests/caller-is-origin/contract_to_call/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "contract_to_call" +version = "4.3.0" +authors = ["Parity Technologies "] +edition = "2021" +publish = false + +[dependencies] +ink = { path = "../../../crates/ink", default-features = false } +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2.5", default-features = false, features = ["derive"], optional = true } + +[dev-dependencies] +ink_e2e = { path = "../../../crates/e2e" } + +[lib] +path = "lib.rs" + +[features] +default = ["std"] +std = [ + "ink/std", + "scale/std", + "scale-info/std" +] +test_instantiate = ["ink/test_instantiate"] +ink-as-dependency = [] +e2e-tests = [] \ No newline at end of file diff --git a/integration-tests/caller-is-origin/contract_to_call/lib.rs b/integration-tests/caller-is-origin/contract_to_call/lib.rs new file mode 100644 index 0000000000..4760fe5bf9 --- /dev/null +++ b/integration-tests/caller-is-origin/contract_to_call/lib.rs @@ -0,0 +1,29 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + +pub use self::contract_to_call::{ContractToCall, ContractToCallRef}; + +#[ink::contract] +mod contract_to_call { + #[ink(storage)] + pub struct ContractToCall {} + + impl ContractToCall { + /// Creates a new Template contract. + #[ink(constructor)] + pub fn new() -> Self { + Self {} + } + + /// Returns true if this contract has been called as the origin. + #[ink(message)] + pub fn im_the_origin(&self) -> bool { + self.env().caller_is_origin() + } + } + + impl Default for ContractToCall { + fn default() -> Self { + Self::new() + } + } +} \ No newline at end of file diff --git a/integration-tests/caller-is-origin/lib.rs b/integration-tests/caller-is-origin/lib.rs new file mode 100644 index 0000000000..28845e3d1e --- /dev/null +++ b/integration-tests/caller-is-origin/lib.rs @@ -0,0 +1,166 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + +#[ink::contract] +mod invoke_contract { + use ink::env::{ call::{ build_call, ExecutionInput, Selector }, DefaultEnvironment }; + + #[ink(storage)] + pub struct InvokeContract {} + + impl InvokeContract { + #[ink(constructor)] + pub fn new() -> Self { + Self {} + } + + /// Try to call the `split_profit` function of the contract sent by parameter. + /// If the account id of the sent contract is not valid it will fail. + #[ink(message)] + pub fn invoke_call(&self, contract_to_call: [u8; 32]) -> bool { + let call = build_call::() + .call(AccountId::from(contract_to_call)) + .gas_limit(0) + .transferred_value(0) + .exec_input( + ExecutionInput::new(Selector::new(ink::selector_bytes!("im_the_origin"))) + ) + .returns::() + .params(); + + self.env() + .invoke_contract(&call) + .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)) + } + } + + impl Default for InvokeContract { + fn default() -> Self { + Self::new() + } + } + + #[cfg(test)] + mod tests { + use super::*; + use contract_to_call::ContractToCall; + use contract_to_call::ContractToCallRef; + + #[ink::test] + fn call_contract_directly() { + let contract = ContractToCall::new(); + let is_the_origin = contract.im_the_origin(); + assert_eq!(is_the_origin, true); + } + + #[ink::test] + fn call_contract_indirectly() { + let contract = InvokeContract::new(); + let code_hash = ink::env::test::upload_code::< + ink::env::DefaultEnvironment, + ContractToCallRef + >(); + let create_params = ink::env::call + ::build_create::() + .code_hash(code_hash) + .gas_limit(0) + .endowment(0) + .exec_input(ExecutionInput::new(Selector::new(ink::selector_bytes!("new")))) + .salt_bytes(&[0_u8; 4]) + .returns::() + .params(); + + let cr = ink::env + ::instantiate_contract(&create_params) + .unwrap_or_else(|error| { + panic!( + "Received an error from the Contracts pallet while instantiating: {:?}", + error + ) + }) + .unwrap_or_else(|error| { + panic!("Received a `LangError` while instatiating: {:?}", error) + }); + + let mut account_id = ink::ToAccountId::::to_account_id(&cr); + let account_id: &[u8; 32] = account_id.as_mut(); + let is_the_origin = contract.invoke_call(*account_id); + assert_eq!(is_the_origin, false); + } + } + + #[cfg(all(test, feature = "e2e-tests"))] + mod e2e_tests { + use contract_to_call::ContractToCallRef; + use ink_e2e::build_message; + + use super::*; + + type E2EResult = std::result::Result>; + + #[ink_e2e::test(additional_contracts = "./contract_to_call/Cargo.toml")] + async fn call_contract_directly(mut client: ink_e2e::Client) -> E2EResult<()> { + let contract_to_call_constructor = ContractToCallRef::new(); + + let contract_to_call_acc_id = client + .instantiate( + "contract_to_call", + &ink_e2e::alice(), + contract_to_call_constructor, + 0, + None + ).await + .expect("instantiate failed").account_id; + + let origin_call = build_message::( + contract_to_call_acc_id.clone() + ).call(|contract| contract.im_the_origin()); + let is_the_origin_res = client.call(&ink_e2e::alice(), origin_call, 0, None).await; + + assert_eq!( + is_the_origin_res.expect("This call always returns a value").return_value(), + true + ); + Ok(()) + } + + #[ink_e2e::test(additional_contracts = "./contract_to_call/Cargo.toml")] + async fn call_contract_indirectly(mut client: ink_e2e::Client) -> E2EResult<()> { + let original_contract_contructor = InvokeContractRef::new(); + let contract_to_call_constructor = ContractToCallRef::new(); + + let original_contract_acc_id = client + .instantiate( + "invoke_contract", + &ink_e2e::alice(), + original_contract_contructor, + 0, + None + ).await + .expect("instantiate failed").account_id; + + let contract_to_call_acc_id = client + .instantiate( + "contract_to_call", + &ink_e2e::alice(), + contract_to_call_constructor, + 0, + None + ).await + .expect("instantiate failed").account_id; + + let invoke_call = build_message::( + original_contract_acc_id.clone() + ).call(|contract| contract.invoke_call(*contract_to_call_acc_id.as_ref())); + let is_the_origin_res = client.call(&ink_e2e::alice(), invoke_call, 0, None).await; + + assert_eq!( + is_the_origin_res.expect("This call always returns a value").return_value(), + false + ); + Ok(()) + } + } +} From 3c1d66fd5f34a97c4a2ddb26844d56ba7f2b4b96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Fri, 10 Nov 2023 19:09:40 -0300 Subject: [PATCH 36/44] Added tests. --- crates/env/src/engine/off_chain/test_api.rs | 4 +- .../Cargo.toml | 15 ++ .../README.md | 0 .../contract1/Cargo.toml | 0 .../contract1/lib.rs | 0 .../contract2/Cargo.toml | 0 .../contract2/lib.rs | 0 .../lib.rs | 134 ++++++++++-------- .../virtual_contract/Cargo.toml | 35 +++++ .../virtual_contract/lib.rs | 87 ++++++++++++ .../virtual_contract_ver1/Cargo.toml | 35 +++++ .../virtual_contract_ver1/lib.rs | 40 ++++++ .../virtual_contract_ver2/Cargo.toml | 35 +++++ .../virtual_contract_ver2/lib.rs | 40 ++++++ 14 files changed, 361 insertions(+), 64 deletions(-) rename integration-tests/{instantiate-contract => contract-invocation}/Cargo.toml (65%) rename integration-tests/{instantiate-contract => contract-invocation}/README.md (100%) rename integration-tests/{instantiate-contract => contract-invocation}/contract1/Cargo.toml (100%) rename integration-tests/{instantiate-contract => contract-invocation}/contract1/lib.rs (100%) rename integration-tests/{instantiate-contract => contract-invocation}/contract2/Cargo.toml (100%) rename integration-tests/{instantiate-contract => contract-invocation}/contract2/lib.rs (100%) rename integration-tests/{instantiate-contract => contract-invocation}/lib.rs (72%) create mode 100644 integration-tests/contract-invocation/virtual_contract/Cargo.toml create mode 100644 integration-tests/contract-invocation/virtual_contract/lib.rs create mode 100644 integration-tests/contract-invocation/virtual_contract_ver1/Cargo.toml create mode 100644 integration-tests/contract-invocation/virtual_contract_ver1/lib.rs create mode 100644 integration-tests/contract-invocation/virtual_contract_ver2/Cargo.toml create mode 100644 integration-tests/contract-invocation/virtual_contract_ver2/lib.rs diff --git a/crates/env/src/engine/off_chain/test_api.rs b/crates/env/src/engine/off_chain/test_api.rs index 868f04d370..c587d50533 100644 --- a/crates/env/src/engine/off_chain/test_api.rs +++ b/crates/env/src/engine/off_chain/test_api.rs @@ -433,9 +433,7 @@ macro_rules! pay_with_call { /// Retrieves the value stored by return_value(). pub fn get_return_value() -> Vec { - ::on_instance(|instance| { - instance.get_return_value() - }) + ::on_instance(|instance| instance.get_return_value()) } /// Gets a pseudo code hash for a contract ref. diff --git a/integration-tests/instantiate-contract/Cargo.toml b/integration-tests/contract-invocation/Cargo.toml similarity index 65% rename from integration-tests/instantiate-contract/Cargo.toml rename to integration-tests/contract-invocation/Cargo.toml index 49dfcabb90..8eb206ebe1 100644 --- a/integration-tests/instantiate-contract/Cargo.toml +++ b/integration-tests/contract-invocation/Cargo.toml @@ -15,6 +15,9 @@ std = [ "scale-info/std", "contract1/std", "contract2/std", + "virtual_contract/std", + "virtual_contract_ver1/std", + "virtual_contract_ver2/std", ] ink-as-dependency = [] e2e-tests = [] @@ -22,6 +25,9 @@ test_instantiate = [ "ink/test_instantiate", "contract1/test_instantiate", "contract2/test_instantiate", + "virtual_contract/test_instantiate", + "virtual_contract_ver1/test_instantiate", + "virtual_contract_ver2/test_instantiate", ] [dependencies] @@ -38,6 +44,15 @@ contract1 = { path = "./contract1", default-features = false, features = [ contract2 = { path = "./contract2", default-features = false, features = [ "ink-as-dependency", ] } +virtual_contract = { path = "./virtual_contract", default-features = false, features = [ + "ink-as-dependency", +] } +virtual_contract_ver1 = { path = "./virtual_contract_ver1", default-features = false, features = [ + "ink-as-dependency", +] } +virtual_contract_ver2 = { path = "./virtual_contract_ver2", default-features = false, features = [ + "ink-as-dependency", +] } [dev-dependencies] ink_e2e = { path = "../../crates/e2e" } diff --git a/integration-tests/instantiate-contract/README.md b/integration-tests/contract-invocation/README.md similarity index 100% rename from integration-tests/instantiate-contract/README.md rename to integration-tests/contract-invocation/README.md diff --git a/integration-tests/instantiate-contract/contract1/Cargo.toml b/integration-tests/contract-invocation/contract1/Cargo.toml similarity index 100% rename from integration-tests/instantiate-contract/contract1/Cargo.toml rename to integration-tests/contract-invocation/contract1/Cargo.toml diff --git a/integration-tests/instantiate-contract/contract1/lib.rs b/integration-tests/contract-invocation/contract1/lib.rs similarity index 100% rename from integration-tests/instantiate-contract/contract1/lib.rs rename to integration-tests/contract-invocation/contract1/lib.rs diff --git a/integration-tests/instantiate-contract/contract2/Cargo.toml b/integration-tests/contract-invocation/contract2/Cargo.toml similarity index 100% rename from integration-tests/instantiate-contract/contract2/Cargo.toml rename to integration-tests/contract-invocation/contract2/Cargo.toml diff --git a/integration-tests/instantiate-contract/contract2/lib.rs b/integration-tests/contract-invocation/contract2/lib.rs similarity index 100% rename from integration-tests/instantiate-contract/contract2/lib.rs rename to integration-tests/contract-invocation/contract2/lib.rs diff --git a/integration-tests/instantiate-contract/lib.rs b/integration-tests/contract-invocation/lib.rs similarity index 72% rename from integration-tests/instantiate-contract/lib.rs rename to integration-tests/contract-invocation/lib.rs index 6ee8336920..89aca51e46 100644 --- a/integration-tests/instantiate-contract/lib.rs +++ b/integration-tests/contract-invocation/lib.rs @@ -23,7 +23,8 @@ mod instantiate_contract { } #[ink(message)] - pub fn instantiate_contract1(&self, code_hash: Hash) -> Contract1Ref { + pub fn instantiate_contract1(&self, code_hash: Hash, salt: u32) -> Contract1Ref { + let salt = salt.to_le_bytes(); let create_params = build_create::() .code_hash(code_hash) .gas_limit(0) @@ -31,7 +32,7 @@ mod instantiate_contract { .exec_input(ExecutionInput::new( Selector::new(ink::selector_bytes!("new")), )) - .salt_bytes(&[0x0; 4]) + .salt_bytes(&salt) .returns::() .params(); @@ -49,7 +50,8 @@ mod instantiate_contract { } #[ink(message)] - pub fn instantiate_contract2(&self, code_hash: Hash) -> Contract2Ref { + pub fn instantiate_contract2(&self, code_hash: Hash, salt: u32) -> Contract2Ref { + let salt = salt.to_le_bytes(); let create_params = build_create::() .code_hash(code_hash) .gas_limit(0) @@ -57,7 +59,7 @@ mod instantiate_contract { .exec_input(ExecutionInput::new( Selector::new(ink::selector_bytes!("new")), )) - .salt_bytes(&[0x0; 4]) + .salt_bytes(&salt) .returns::() .params(); @@ -172,14 +174,17 @@ mod instantiate_contract { }, primitives::AccountId, }; + use virtual_contract::VirtualContractRef; + use virtual_contract_ver1::VirtualContractVer1Ref; + use virtual_contract_ver2::VirtualContractVer2Ref; - fn instantiate_contract1(contract: &ContractTester, code_hash: Hash) -> AccountId{ - let cr = contract.instantiate_contract1(code_hash); + fn instantiate_contract1(contract: &ContractTester, code_hash: Hash, salt: u32) -> AccountId{ + let cr = contract.instantiate_contract1(code_hash, salt); ink::ToAccountId::::to_account_id(&cr) } - fn instantiate_contract2(contract: &ContractTester, code_hash: Hash) -> AccountId{ - let cr = contract.instantiate_contract2(code_hash); + fn instantiate_contract2(contract: &ContractTester, code_hash: Hash, salt: u32) -> AccountId{ + let cr = contract.instantiate_contract2(code_hash, salt); ink::ToAccountId::::to_account_id(&cr) } @@ -189,18 +194,15 @@ mod instantiate_contract { } #[ink::test] - fn test_contract1() { + fn test_invoke() { let contract = ContractTester::new(); let code_hash1 = ink::env::test::upload_code::(); let code_hash2 = ink::env::test::upload_code::(); - // Set different caller AccountIds, so that instantiate_contract will generate different account ids. - ink::env::test::set_caller::([1_u8; 32].into()); - let mut contract1_address1_account = instantiate_contract1(&contract, code_hash1); - let mut contract2_address1_account = instantiate_contract2(&contract, code_hash2); - ink::env::test::set_caller::([2_u8; 32].into()); - let mut contract1_address2_account = instantiate_contract1(&contract, code_hash1); - let mut contract2_address2_account = instantiate_contract2(&contract, code_hash2); + let mut contract1_address1_account = instantiate_contract1(&contract, code_hash1, 1); + let mut contract1_address2_account = instantiate_contract1(&contract, code_hash1, 2); + let mut contract2_address1_account = instantiate_contract2(&contract, code_hash2, 3); + let mut contract2_address2_account = instantiate_contract2(&contract, code_hash2, 4); let contract1_address1 = to_array(&mut contract1_address1_account); let contract1_address2 = to_array(&mut contract1_address2_account); @@ -246,54 +248,64 @@ mod instantiate_contract { check_values2(123456, 123456); } - } - #[cfg(all(test, feature = "e2e-tests", not(feature = "test_instantiate")))] - mod e2e_tests { - use ink_e2e::build_message; + #[ink::test] + fn test_invoke_delegate() { + let code_hash1 = ink::env::test::upload_code::(); + let code_hash2 = ink::env::test::upload_code::(); + let code_hash3 = ink::env::test::upload_code::(); + + let ic = |hash, salt: u32, x|{ + let salt = salt.to_le_bytes(); + let create_params = build_create::() + .code_hash(code_hash1) + .gas_limit(0) + .endowment(0) + .exec_input( + ExecutionInput::new(Selector::new(ink::selector_bytes!("new"))) + .push_arg(hash) + .push_arg(x), + ) + .salt_bytes(&salt) + .returns::() + .params(); + + ink::env::instantiate_contract(&create_params) + .unwrap_or_else(|error| { + panic!( + "Received an error from the Contracts pallet while instantiating: {:?}", + error + ) + }) + .unwrap_or_else(|error| { + panic!("Received a `LangError` while instatiating: {:?}", error) + }) + }; + + let mut ref1 = ic(code_hash2, 1, 42); + let mut ref2 = ic(code_hash3, 2, 74); + + let check_values = |r1: &VirtualContractRef, r2: &VirtualContractRef, a, b, c, d|{ + let v1 = r1.real_get_x(); + let v2 = r2.real_get_x(); + let v3 = r1.get_x(); + let v4 = r2.get_x(); + assert_eq!(v1, a); + assert_eq!(v2, b); + assert_eq!(v3, c); + assert_eq!(v4, d); + }; - use super::*; + check_values(&ref1, &ref2, 42, 74, 43, 148); + ref1.set_x(15); + check_values(&ref1, &ref2, 42, 74, 43, 148); + ref1.real_set_x(15); + check_values(&ref1, &ref2, 15, 74, 16, 148); + ref2.set_x(39); + check_values(&ref1, &ref2, 15, 74, 16, 148); + ref2.real_set_x(39); + check_values(&ref1, &ref2, 15, 39, 16, 78); - type E2EResult = std::result::Result>; - - #[ink_e2e::test(additional_contracts = "other_contract/Cargo.toml")] - async fn instantiate_other_contract( - mut client: ink_e2e::Client, - ) -> E2EResult<()> { - let constructor = ContractTesterRef::new(); - - let contract_acc_id = client - .instantiate( - "instantiate_contract", - &ink_e2e::bob(), - constructor, - 0, - None, - ) - .await - .expect("instantiate failed") - .account_id; - - let other_contract_code_hash = client - .upload("other_contract", &ink_e2e::bob(), None) - .await - .expect("instantiate failed") - .code_hash; - - let instantiate_other_contract = build_message::( - contract_acc_id.clone(), - ) - .call(|contract| { - contract.instantiate_other_contract(other_contract_code_hash) - }); - - let instantiate_other_contract_res = client - .call_dry_run(&ink_e2e::bob(), &instantiate_other_contract, 0, None) - .await; - - assert!(instantiate_other_contract_res.exec_result.result.is_ok()); - - Ok(()) } } } diff --git a/integration-tests/contract-invocation/virtual_contract/Cargo.toml b/integration-tests/contract-invocation/virtual_contract/Cargo.toml new file mode 100644 index 0000000000..c9e6e99100 --- /dev/null +++ b/integration-tests/contract-invocation/virtual_contract/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "virtual_contract" +version = "0.1.0" +edition = "2021" +authors = ["Víctor M. González "] + +[lib] +path = "lib.rs" + +[features] +default = ["std", "test_instantiate"] +std = ["ink/std", "scale/std", "scale-info/std"] +ink-as-dependency = [] +e2e-tests = [] +test_instantiate = [ + "ink/test_instantiate" +] + +[dependencies] +ink = { path = "../../../crates/ink", default-features = false } +scale = { package = "parity-scale-codec", version = "=3.6.5", default-features = false, features = [ + "derive", +] } +scale-info = { version = "2.6", default-features = false, features = [ + "derive", +], optional = true } + +[dev-dependencies] +ink_e2e = { path = "../../../crates/e2e" } + +[profile.dev] +overflow-checks = false + +[profile.release] +overflow-checks = false diff --git a/integration-tests/contract-invocation/virtual_contract/lib.rs b/integration-tests/contract-invocation/virtual_contract/lib.rs new file mode 100644 index 0000000000..60011b7864 --- /dev/null +++ b/integration-tests/contract-invocation/virtual_contract/lib.rs @@ -0,0 +1,87 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + +pub use self::virtual_contract::VirtualContractRef; + +#[ink::contract()] +mod virtual_contract { + use ink::env::call::{ + build_call, + ExecutionInput, + Selector, + }; + + #[ink(storage)] + pub struct VirtualContract { + version: [u8; 32], + x: u32, + } + + impl VirtualContract { + /// Creates a new Template contract. + #[ink(constructor)] + pub fn new(version: [u8; 32], x: u32) -> Self { + Self { + version, + x, + } + } + + #[ink(message)] + pub fn set_version(&mut self, version: [u8; 32]) { + self.version = version; + } + + #[ink(message)] + pub fn real_set_x(&mut self, x: u32) { + self.x = x; + } + + #[ink(message)] + pub fn real_get_x(&self) -> u32 { + self.x + } + + #[ink(message)] + pub fn set_x(&mut self, x: u32) { + let call = build_call() + .delegate(Hash::from(self.version)) + .exec_input( + ExecutionInput::new(Selector::new(ink::selector_bytes!("set_x"))) + .push_arg(x) + ) + .returns::<()>() + .params(); + + self.env() + .invoke_contract_delegate(&call) + .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)); + } + + #[ink(message)] + pub fn get_x(&self) -> u32 { + let call = build_call() + .delegate(Hash::from(self.version)) + .exec_input( + ExecutionInput::new(Selector::new(ink::selector_bytes!("get_x"))) + ) + .returns::() + .params(); + + self.env() + .invoke_contract_delegate(&call) + .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)) + } + } + + impl Default for VirtualContract { + fn default() -> Self { + Self::new([0; 32], 0) + } + } +} diff --git a/integration-tests/contract-invocation/virtual_contract_ver1/Cargo.toml b/integration-tests/contract-invocation/virtual_contract_ver1/Cargo.toml new file mode 100644 index 0000000000..1247486986 --- /dev/null +++ b/integration-tests/contract-invocation/virtual_contract_ver1/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "virtual_contract_ver1" +version = "0.1.0" +edition = "2021" +authors = ["Víctor M. González "] + +[lib] +path = "lib.rs" + +[features] +default = ["std", "test_instantiate"] +std = ["ink/std", "scale/std", "scale-info/std"] +ink-as-dependency = [] +e2e-tests = [] +test_instantiate = [ + "ink/test_instantiate" +] + +[dependencies] +ink = { path = "../../../crates/ink", default-features = false } +scale = { package = "parity-scale-codec", version = "=3.6.5", default-features = false, features = [ + "derive", +] } +scale-info = { version = "2.6", default-features = false, features = [ + "derive", +], optional = true } + +[dev-dependencies] +ink_e2e = { path = "../../../crates/e2e" } + +[profile.dev] +overflow-checks = false + +[profile.release] +overflow-checks = false diff --git a/integration-tests/contract-invocation/virtual_contract_ver1/lib.rs b/integration-tests/contract-invocation/virtual_contract_ver1/lib.rs new file mode 100644 index 0000000000..940d3fa5d3 --- /dev/null +++ b/integration-tests/contract-invocation/virtual_contract_ver1/lib.rs @@ -0,0 +1,40 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + +pub use self::virtual_contract_ver1::VirtualContractVer1Ref; + +#[ink::contract()] +mod virtual_contract_ver1 { + + #[ink(storage)] + pub struct VirtualContractVer1 { + version: [u8; 32], + x: u32, + } + + impl VirtualContractVer1 { + /// Creates a new Template contract. + #[ink(constructor)] + pub fn new() -> Self { + Self { + version: [0; 32], + x: 42 + } + } + + #[ink(message)] + pub fn set_x(&mut self, x: u32) { + self.x = x / 2; + } + + #[ink(message)] + pub fn get_x(&self) -> u32 { + self.x + 1 + } + } + + impl Default for VirtualContractVer1 { + fn default() -> Self { + Self::new() + } + } +} diff --git a/integration-tests/contract-invocation/virtual_contract_ver2/Cargo.toml b/integration-tests/contract-invocation/virtual_contract_ver2/Cargo.toml new file mode 100644 index 0000000000..d8cd903186 --- /dev/null +++ b/integration-tests/contract-invocation/virtual_contract_ver2/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "virtual_contract_ver2" +version = "0.1.0" +edition = "2021" +authors = ["Víctor M. González "] + +[lib] +path = "lib.rs" + +[features] +default = ["std", "test_instantiate"] +std = ["ink/std", "scale/std", "scale-info/std"] +ink-as-dependency = [] +e2e-tests = [] +test_instantiate = [ + "ink/test_instantiate" +] + +[dependencies] +ink = { path = "../../../crates/ink", default-features = false } +scale = { package = "parity-scale-codec", version = "=3.6.5", default-features = false, features = [ + "derive", +] } +scale-info = { version = "2.6", default-features = false, features = [ + "derive", +], optional = true } + +[dev-dependencies] +ink_e2e = { path = "../../../crates/e2e" } + +[profile.dev] +overflow-checks = false + +[profile.release] +overflow-checks = false diff --git a/integration-tests/contract-invocation/virtual_contract_ver2/lib.rs b/integration-tests/contract-invocation/virtual_contract_ver2/lib.rs new file mode 100644 index 0000000000..7c37c838fa --- /dev/null +++ b/integration-tests/contract-invocation/virtual_contract_ver2/lib.rs @@ -0,0 +1,40 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + +pub use self::virtual_contract_ver2::VirtualContractVer2Ref; + +#[ink::contract()] +mod virtual_contract_ver2 { + + #[ink(storage)] + pub struct VirtualContractVer2 { + version: [u8; 32], + x: u32, + } + + impl VirtualContractVer2 { + /// Creates a new Template contract. + #[ink(constructor)] + pub fn new() -> Self { + Self { + version: [0; 32], + x: 42 + } + } + + #[ink(message)] + pub fn set_x(&mut self, x: u32) { + self.x = x - 1; + } + + #[ink(message)] + pub fn get_x(&self) -> u32 { + self.x * 2 + } + } + + impl Default for VirtualContractVer2 { + fn default() -> Self { + Self::new() + } + } +} From 6cc180ca5fcf0e2647e8ec2959c5f50ce9c40e1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Fri, 10 Nov 2023 19:18:12 -0300 Subject: [PATCH 37/44] Removed unused type parameter. --- crates/env/src/engine/off_chain/impls.rs | 3 +-- crates/env/src/engine/off_chain/test_api.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index 1308e0129e..18e6eb0d57 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -260,9 +260,8 @@ impl EnvInstance { self.engine.get_storage(&[255_u8; 32]).unwrap().to_vec() } - pub fn upload_code(&mut self) -> ink_primitives::types::Hash + pub fn upload_code(&mut self) -> ink_primitives::types::Hash where - E: Environment, ContractRef: crate::ContractReverseReference, ::Type: crate::reflect::ContractMessageDecoder, diff --git a/crates/env/src/engine/off_chain/test_api.rs b/crates/env/src/engine/off_chain/test_api.rs index c587d50533..9be60564e6 100644 --- a/crates/env/src/engine/off_chain/test_api.rs +++ b/crates/env/src/engine/off_chain/test_api.rs @@ -445,6 +445,6 @@ where crate::reflect::ContractMessageDecoder, { ::on_instance(|instance| { - instance.upload_code::() + instance.upload_code::() }) } From cc80e57710b775df7e85b0fd663c1fc9c75f334e Mon Sep 17 00:00:00 2001 From: Brian Ramirez Date: Mon, 13 Nov 2023 09:57:41 -0300 Subject: [PATCH 38/44] Fix e2e tests --- integration-tests/caller-is-origin/lib.rs | 79 ++++++++++++++--------- 1 file changed, 49 insertions(+), 30 deletions(-) diff --git a/integration-tests/caller-is-origin/lib.rs b/integration-tests/caller-is-origin/lib.rs index 28845e3d1e..475d5785b2 100644 --- a/integration-tests/caller-is-origin/lib.rs +++ b/integration-tests/caller-is-origin/lib.rs @@ -94,7 +94,8 @@ mod invoke_contract { #[cfg(all(test, feature = "e2e-tests"))] mod e2e_tests { use contract_to_call::ContractToCallRef; - use ink_e2e::build_message; + use ink_e2e::ContractsBackend; + use contract_to_call::ContractToCall; use super::*; @@ -102,64 +103,82 @@ mod invoke_contract { #[ink_e2e::test(additional_contracts = "./contract_to_call/Cargo.toml")] async fn call_contract_directly(mut client: ink_e2e::Client) -> E2EResult<()> { - let contract_to_call_constructor = ContractToCallRef::new(); + // given + let mut contract_to_call_constructor = ContractToCallRef::new(); - let contract_to_call_acc_id = client + let contract = client .instantiate( "contract_to_call", &ink_e2e::alice(), - contract_to_call_constructor, - 0, - None - ).await - .expect("instantiate failed").account_id; + &mut contract_to_call_constructor, + ).submit() + .await + .expect("instantiate failed"); + let call = contract.call::(); - let origin_call = build_message::( - contract_to_call_acc_id.clone() - ).call(|contract| contract.im_the_origin()); - let is_the_origin_res = client.call(&ink_e2e::alice(), origin_call, 0, None).await; + // when + let im_the_origin_call = call.im_the_origin(); + let result = client.call(&ink_e2e::alice(), &im_the_origin_call).submit().await; + + // then assert_eq!( - is_the_origin_res.expect("This call always returns a value").return_value(), + result.expect("This call always returns a value").return_value(), true ); + // assert_eq!( + // is_the_origin_res.expect("This call always returns a value").return_value(), + // true + // ); + Ok(()) } #[ink_e2e::test(additional_contracts = "./contract_to_call/Cargo.toml")] async fn call_contract_indirectly(mut client: ink_e2e::Client) -> E2EResult<()> { - let original_contract_contructor = InvokeContractRef::new(); - let contract_to_call_constructor = ContractToCallRef::new(); + // given + let mut original_contract_contructor = InvokeContractRef::new(); + let mut contract_to_call_constructor = ContractToCallRef::new(); - let original_contract_acc_id = client + let original_contract = client .instantiate( "invoke_contract", &ink_e2e::alice(), - original_contract_contructor, - 0, - None - ).await - .expect("instantiate failed").account_id; + &mut original_contract_contructor, + ).submit().await + .expect("instantiate failed"); let contract_to_call_acc_id = client .instantiate( "contract_to_call", &ink_e2e::alice(), - contract_to_call_constructor, - 0, - None - ).await + &mut contract_to_call_constructor, + ).submit().await .expect("instantiate failed").account_id; - let invoke_call = build_message::( - original_contract_acc_id.clone() - ).call(|contract| contract.invoke_call(*contract_to_call_acc_id.as_ref())); - let is_the_origin_res = client.call(&ink_e2e::alice(), invoke_call, 0, None).await; + let call = original_contract.call::(); + // when + + let invoke_call = call.invoke_call(*contract_to_call_acc_id.as_ref()); + + let result = client.call(&ink_e2e::bob(), &invoke_call).submit().await; + + // then assert_eq!( - is_the_origin_res.expect("This call always returns a value").return_value(), + result.is_ok(), false ); + + // let invoke_call = build_message::( + // original_contract_acc_id.clone() + // ).call(|contract| contract.invoke_call(*contract_to_call_acc_id.as_ref())); + // let is_the_origin_res = client.call(&ink_e2e::alice(), invoke_call, 0, None).await; + + // assert_eq!( + // is_the_origin_res.expect("This call always returns a value").return_value(), + // false + // ); Ok(()) } } From c13540962b102c41d62febdc8f2ac084c273db1a Mon Sep 17 00:00:00 2001 From: Brian Ramirez Date: Mon, 13 Nov 2023 11:08:28 -0300 Subject: [PATCH 39/44] Clippy and fmt --- crates/engine/src/exec_context.rs | 2 +- crates/env/src/engine/off_chain/impls.rs | 4 +- crates/env/src/engine/off_chain/test_api.rs | 4 +- .../caller-is-origin/contract_to_call/lib.rs | 7 +- integration-tests/caller-is-origin/lib.rs | 103 ++++++++++-------- 5 files changed, 67 insertions(+), 53 deletions(-) diff --git a/crates/engine/src/exec_context.rs b/crates/engine/src/exec_context.rs index 66003836a2..5dbef96974 100644 --- a/crates/engine/src/exec_context.rs +++ b/crates/engine/src/exec_context.rs @@ -46,7 +46,7 @@ pub struct ExecContext { /// Known contract accounts pub contracts: Vec>, - pub depth: u8 + pub depth: u8, } impl ExecContext { diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index 1468b0f276..4909be8923 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -660,7 +660,7 @@ impl TypedEnvBackend for EnvInstance { ::AccountId::decode(&mut &account_id_vec[..]).unwrap(); let old_callee = self.engine.get_callee(); - self.engine.exec_context.depth+=1; + self.engine.exec_context.depth += 1; self.engine.set_callee(account_id_vec.clone()); let dispatch = < @@ -684,7 +684,7 @@ impl TypedEnvBackend for EnvInstance { .set_balance(account_id.as_mut(), endowment); self.engine.set_callee(old_callee); - self.engine.exec_context.depth-=1; + self.engine.exec_context.depth -= 1; Ok(Ok(R::ok( >::from_account_id(account_id), diff --git a/crates/env/src/engine/off_chain/test_api.rs b/crates/env/src/engine/off_chain/test_api.rs index 868f04d370..c587d50533 100644 --- a/crates/env/src/engine/off_chain/test_api.rs +++ b/crates/env/src/engine/off_chain/test_api.rs @@ -433,9 +433,7 @@ macro_rules! pay_with_call { /// Retrieves the value stored by return_value(). pub fn get_return_value() -> Vec { - ::on_instance(|instance| { - instance.get_return_value() - }) + ::on_instance(|instance| instance.get_return_value()) } /// Gets a pseudo code hash for a contract ref. diff --git a/integration-tests/caller-is-origin/contract_to_call/lib.rs b/integration-tests/caller-is-origin/contract_to_call/lib.rs index 4760fe5bf9..fbef2a2061 100644 --- a/integration-tests/caller-is-origin/contract_to_call/lib.rs +++ b/integration-tests/caller-is-origin/contract_to_call/lib.rs @@ -1,6 +1,9 @@ #![cfg_attr(not(feature = "std"), no_std, no_main)] -pub use self::contract_to_call::{ContractToCall, ContractToCallRef}; +pub use self::contract_to_call::{ + ContractToCall, + ContractToCallRef, +}; #[ink::contract] mod contract_to_call { @@ -26,4 +29,4 @@ mod contract_to_call { Self::new() } } -} \ No newline at end of file +} diff --git a/integration-tests/caller-is-origin/lib.rs b/integration-tests/caller-is-origin/lib.rs index 475d5785b2..e9501f9b9a 100644 --- a/integration-tests/caller-is-origin/lib.rs +++ b/integration-tests/caller-is-origin/lib.rs @@ -2,7 +2,14 @@ #[ink::contract] mod invoke_contract { - use ink::env::{ call::{ build_call, ExecutionInput, Selector }, DefaultEnvironment }; + use ink::env::{ + call::{ + build_call, + ExecutionInput, + Selector, + }, + DefaultEnvironment, + }; #[ink(storage)] pub struct InvokeContract {} @@ -21,9 +28,9 @@ mod invoke_contract { .call(AccountId::from(contract_to_call)) .gas_limit(0) .transferred_value(0) - .exec_input( - ExecutionInput::new(Selector::new(ink::selector_bytes!("im_the_origin"))) - ) + .exec_input(ExecutionInput::new(Selector::new(ink::selector_bytes!( + "im_the_origin" + )))) .returns::() .params(); @@ -32,7 +39,9 @@ mod invoke_contract { .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)) + .unwrap_or_else(|lang_err| { + panic!("Received a `LangError`: {:?}", lang_err) + }) } } @@ -45,14 +54,16 @@ mod invoke_contract { #[cfg(test)] mod tests { use super::*; - use contract_to_call::ContractToCall; - use contract_to_call::ContractToCallRef; + use contract_to_call::{ + ContractToCall, + ContractToCallRef, + }; #[ink::test] fn call_contract_directly() { let contract = ContractToCall::new(); let is_the_origin = contract.im_the_origin(); - assert_eq!(is_the_origin, true); + assert!(!is_the_origin); } #[ink::test] @@ -60,14 +71,15 @@ mod invoke_contract { let contract = InvokeContract::new(); let code_hash = ink::env::test::upload_code::< ink::env::DefaultEnvironment, - ContractToCallRef + ContractToCallRef, >(); - let create_params = ink::env::call - ::build_create::() + let create_params = ink::env::call::build_create::() .code_hash(code_hash) .gas_limit(0) .endowment(0) - .exec_input(ExecutionInput::new(Selector::new(ink::selector_bytes!("new")))) + .exec_input(ExecutionInput::new(Selector::new(ink::selector_bytes!( + "new" + )))) .salt_bytes(&[0_u8; 4]) .returns::() .params(); @@ -84,25 +96,30 @@ mod invoke_contract { panic!("Received a `LangError` while instatiating: {:?}", error) }); - let mut account_id = ink::ToAccountId::::to_account_id(&cr); + let mut account_id = + ink::ToAccountId::::to_account_id(&cr); let account_id: &[u8; 32] = account_id.as_mut(); let is_the_origin = contract.invoke_call(*account_id); - assert_eq!(is_the_origin, false); + assert!(!is_the_origin); } } #[cfg(all(test, feature = "e2e-tests"))] mod e2e_tests { - use contract_to_call::ContractToCallRef; + use contract_to_call::{ + ContractToCall, + ContractToCallRef, + }; use ink_e2e::ContractsBackend; - use contract_to_call::ContractToCall; use super::*; type E2EResult = std::result::Result>; #[ink_e2e::test(additional_contracts = "./contract_to_call/Cargo.toml")] - async fn call_contract_directly(mut client: ink_e2e::Client) -> E2EResult<()> { + async fn call_contract_directly( + mut client: ink_e2e::Client, + ) -> E2EResult<()> { // given let mut contract_to_call_constructor = ContractToCallRef::new(); @@ -111,7 +128,8 @@ mod invoke_contract { "contract_to_call", &ink_e2e::alice(), &mut contract_to_call_constructor, - ).submit() + ) + .submit() .await .expect("instantiate failed"); let call = contract.call::(); @@ -119,23 +137,23 @@ mod invoke_contract { // when let im_the_origin_call = call.im_the_origin(); - let result = client.call(&ink_e2e::alice(), &im_the_origin_call).submit().await; + let result = client + .call(&ink_e2e::alice(), &im_the_origin_call) + .submit() + .await; // then - assert_eq!( - result.expect("This call always returns a value").return_value(), - true - ); - // assert_eq!( - // is_the_origin_res.expect("This call always returns a value").return_value(), - // true - // ); + assert!(result + .expect("This call always returns a value") + .return_value()); Ok(()) } #[ink_e2e::test(additional_contracts = "./contract_to_call/Cargo.toml")] - async fn call_contract_indirectly(mut client: ink_e2e::Client) -> E2EResult<()> { + async fn call_contract_indirectly( + mut client: ink_e2e::Client, + ) -> E2EResult<()> { // given let mut original_contract_contructor = InvokeContractRef::new(); let mut contract_to_call_constructor = ContractToCallRef::new(); @@ -145,7 +163,9 @@ mod invoke_contract { "invoke_contract", &ink_e2e::alice(), &mut original_contract_contructor, - ).submit().await + ) + .submit() + .await .expect("instantiate failed"); let contract_to_call_acc_id = client @@ -153,8 +173,11 @@ mod invoke_contract { "contract_to_call", &ink_e2e::alice(), &mut contract_to_call_constructor, - ).submit().await - .expect("instantiate failed").account_id; + ) + .submit() + .await + .expect("instantiate failed") + .account_id; let call = original_contract.call::(); @@ -165,20 +188,10 @@ mod invoke_contract { let result = client.call(&ink_e2e::bob(), &invoke_call).submit().await; // then - assert_eq!( - result.is_ok(), - false - ); - - // let invoke_call = build_message::( - // original_contract_acc_id.clone() - // ).call(|contract| contract.invoke_call(*contract_to_call_acc_id.as_ref())); - // let is_the_origin_res = client.call(&ink_e2e::alice(), invoke_call, 0, None).await; - - // assert_eq!( - // is_the_origin_res.expect("This call always returns a value").return_value(), - // false - // ); + assert!(!result + .expect("This call always returns a value") + .return_value()); + Ok(()) } } From 4e87e30afcae5c758809d0538fb934c05a1a9adc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Mon, 13 Nov 2023 11:39:03 -0300 Subject: [PATCH 40/44] Updated changelog. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c9bca7643..b92b86d7a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [E2E] Call builders and extra gas margin option - [#1917](https://github.com/paritytech/ink/pull/1917) - Make `set_code_hash` generic - [#1906](https://github.com/paritytech/ink/pull/1906) - Clean E2E configuration parsing - [#1922](https://github.com/paritytech/ink/pull/1922) -- Implement instantiate_contract() in off-chain environment engine - [#1957](https://github.com/paritytech/ink/pull/1957) +- Implement contract invokation in off-chain environment engine - [#1957](https://github.com/paritytech/ink/pull/1988) ### Changed - Fail when decoding from storage and not all bytes consumed - [#1897](https://github.com/paritytech/ink/pull/1897) From f87e5ddb3f9aaa45a18e70bdce14c2686333122a Mon Sep 17 00:00:00 2001 From: Brian Ramirez Date: Mon, 13 Nov 2023 12:19:00 -0300 Subject: [PATCH 41/44] Add comment and fix integration tests --- crates/engine/src/exec_context.rs | 2 +- integration-tests/caller-is-origin/lib.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/engine/src/exec_context.rs b/crates/engine/src/exec_context.rs index 5dbef96974..b8c1d9fe6d 100644 --- a/crates/engine/src/exec_context.rs +++ b/crates/engine/src/exec_context.rs @@ -45,7 +45,7 @@ pub struct ExecContext { pub block_timestamp: BlockTimestamp, /// Known contract accounts pub contracts: Vec>, - + /// This value is used to know the origin of the contract calls. pub depth: u8, } diff --git a/integration-tests/caller-is-origin/lib.rs b/integration-tests/caller-is-origin/lib.rs index e9501f9b9a..4f52a1222c 100644 --- a/integration-tests/caller-is-origin/lib.rs +++ b/integration-tests/caller-is-origin/lib.rs @@ -63,7 +63,7 @@ mod invoke_contract { fn call_contract_directly() { let contract = ContractToCall::new(); let is_the_origin = contract.im_the_origin(); - assert!(!is_the_origin); + assert!(is_the_origin); } #[ink::test] @@ -182,7 +182,6 @@ mod invoke_contract { let call = original_contract.call::(); // when - let invoke_call = call.invoke_call(*contract_to_call_acc_id.as_ref()); let result = client.call(&ink_e2e::bob(), &invoke_call).submit().await; From e5c4edaa3a29d755f980004e6e02d9cf48cb6003 Mon Sep 17 00:00:00 2001 From: Brian Ramirez Date: Tue, 14 Nov 2023 11:04:01 -0300 Subject: [PATCH 42/44] Add changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b92b86d7a3..b3425a29fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Make `set_code_hash` generic - [#1906](https://github.com/paritytech/ink/pull/1906) - Clean E2E configuration parsing - [#1922](https://github.com/paritytech/ink/pull/1922) - Implement contract invokation in off-chain environment engine - [#1957](https://github.com/paritytech/ink/pull/1988) +- Implement `caller_is_origin()` in off-chain environment engine - [#1991](https://github.com/paritytech/ink/pull/1991) ### Changed - Fail when decoding from storage and not all bytes consumed - [#1897](https://github.com/paritytech/ink/pull/1897) From 3e32419c05ddba57fe28e9713b026e745d4a0555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20M=2E=20Gonz=C3=A1lez?= Date: Wed, 15 Nov 2023 14:48:33 -0300 Subject: [PATCH 43/44] Fixed clippy errors. --- integration-tests/contract-invocation/lib.rs | 22 ++++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/integration-tests/contract-invocation/lib.rs b/integration-tests/contract-invocation/lib.rs index 89aca51e46..bd4604547a 100644 --- a/integration-tests/contract-invocation/lib.rs +++ b/integration-tests/contract-invocation/lib.rs @@ -190,7 +190,7 @@ mod instantiate_contract { fn to_array(address: &mut AccountId) -> [u8; 32]{ let temp: &[u8; 32] = address.as_mut(); - temp.clone() + *temp } #[ink::test] @@ -218,32 +218,32 @@ mod instantiate_contract { assert_eq!(x, c); assert_eq!(y, c); }; - check_hashes(&contract1_address1_account, &contract1_address2_account, code_hash1.clone()); - check_hashes(&contract2_address1_account, &contract2_address2_account, code_hash2.clone()); + check_hashes(&contract1_address1_account, &contract1_address2_account, code_hash1); + check_hashes(&contract2_address1_account, &contract2_address2_account, code_hash2); let check_values1 = |a, b| { - let x = contract.contract1_get_x(contract1_address1.clone()); - let y = contract.contract1_get_x(contract1_address2.clone()); + let x = contract.contract1_get_x(contract1_address1); + let y = contract.contract1_get_x(contract1_address2); assert_eq!(x, a); assert_eq!(y, b); }; let check_values2 = |a, b| { - let x = contract.contract2_get_x(contract2_address1.clone()); - let y = contract.contract2_get_x(contract2_address2.clone()); + let x = contract.contract2_get_x(contract2_address1); + let y = contract.contract2_get_x(contract2_address2); assert_eq!(x, a); assert_eq!(y, b); }; check_values1(42, 42); check_values2(123456, 123456); - contract.contract2_set_x(contract2_address1.clone(), 78); + contract.contract2_set_x(contract2_address1, 78); check_values1(42, 42); check_values2(123456, 123456); - contract.contract1_set_x(contract1_address1.clone(), 123); - contract.contract2_set_x(contract2_address2.clone(), 87); + contract.contract1_set_x(contract1_address1, 123); + contract.contract2_set_x(contract2_address2, 87); check_values1(123, 42); check_values2(123456, 123456); - contract.contract1_set_x(contract1_address2.clone(), 321); + contract.contract1_set_x(contract1_address2, 321); check_values1(123, 321); check_values2(123456, 123456); From 784e2b899eeebaceb54f740efc3f01df82bfeb24 Mon Sep 17 00:00:00 2001 From: Brian Ramirez Date: Thu, 16 Nov 2023 09:45:26 -0300 Subject: [PATCH 44/44] Passed through rustfmt. --- crates/ink/codegen/src/generator/trait_def/trait_registry.rs | 4 +--- crates/ink/ir/src/ir/attrs.rs | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/crates/ink/codegen/src/generator/trait_def/trait_registry.rs b/crates/ink/codegen/src/generator/trait_def/trait_registry.rs index b0fe1a25bd..6d6471e53e 100644 --- a/crates/ink/codegen/src/generator/trait_def/trait_registry.rs +++ b/crates/ink/codegen/src/generator/trait_def/trait_registry.rs @@ -21,9 +21,7 @@ use super::TraitDefinition; use crate::{ - generator::{ - self, - }, + generator::{self,}, traits::GenerateCode, EnforcedErrors, }; diff --git a/crates/ink/ir/src/ir/attrs.rs b/crates/ink/ir/src/ir/attrs.rs index 100efa0654..4cd8320f43 100644 --- a/crates/ink/ir/src/ir/attrs.rs +++ b/crates/ink/ir/src/ir/attrs.rs @@ -32,9 +32,7 @@ use syn::{ }; use crate::{ - ast::{ - self, - }, + ast::{self,}, error::ExtError as _, ir, ir::{