Skip to content

Commit

Permalink
Implemented contract instantiation and invocation for integration tes…
Browse files Browse the repository at this point in the history
…ts (#1988)

* Implementing stuff needed for instantiate_contract().

* Implemented return_value() on integration tests.

# Conflicts:
#	crates/env/src/lib.rs
#	crates/env/src/reflect/event.rs
#	crates/ink/codegen/Cargo.toml

* A couple fixes for E2E environment.

* Forgot to delete some fluff.

* Fixed dead code warnings.

* Added tests.

* Fixed-up tomls.

* Updated stderr test files.

* Updated CHANGELOG.

* Passed through rustfmt.

* Passed through clippy.

* Passed through rustfmt again.

* Fixed failing contract builds.

Moved reflection, contract, arithmetic, and miscellaneous types from ink_env
to ink_primitives.

* Revert "Updated stderr test files."

This reverts commit 2d1950a.

* Fixed format errors.

* Fixed failing test.

* Updated stderr test values.

* Fixed some dependencies for doc tests.

* Fixed rustfmt issues.

* Implemented code_hash() and set_code_hash().

* Minor behavior correction for instantiate_contract().

* Tentative invoke_contract() implementation.

* Added invoke_contract_delegate() skeleton.

* Obviated unsafe block.

* own_code_hash implementation

* Add own-code-hash integration test

* Remove unused use.

* Added some missing semantics.

* Passed through rustfmt.

* Passed through clippy.

* Fixed own_code_hash test.

* Tightening up code.

* Improved contract invokation tests. Fixed some things.

* Added tests.

* Removed unused type parameter.

* Updated changelog.

* Fixed clippy errors.

* Reapplied changes from PR 1988.

* Tests passing.

* cargo clippy

---------

Co-authored-by: Brian Ramirez <[email protected]>
  • Loading branch information
Helios-vmg and ramirez7358 authored Jan 9, 2025
1 parent 474553b commit c7de4c2
Show file tree
Hide file tree
Showing 61 changed files with 1,671 additions and 296 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

[Unreleased]

- Implement contract invokation in off-chain environment engine - [#1957](https://github.com/paritytech/ink/pull/1988)

## Changed
- Restrict which `cfg` attributes can be used ‒ [#2313](https://github.com/use-ink/ink/pull/2313)

Expand Down
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

58 changes: 58 additions & 0 deletions crates/engine/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ 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`.
pub fn balance_of_key(who: &[u8]) -> [u8; 32] {
Expand All @@ -27,6 +30,31 @@ pub fn balance_of_key(who: &[u8]) -> [u8; 32] {
hashed_key
}

pub type MessageHandler = fn(Vec<u8>) -> Vec<u8>;

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>) -> [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
}

/// Returns the database key under which to find the balance for account `who`.
pub fn storage_of_contract_key(who: &[u8], key: &[u8]) -> [u8; 32] {
let keyed = who.to_vec().to_keyed_vec(key).to_keyed_vec(STORAGE_OF);
Expand All @@ -42,13 +70,15 @@ pub fn storage_of_contract_key(who: &[u8], key: &[u8]) -> [u8; 32] {
#[derive(Default)]
pub struct Database {
hmap: HashMap<Vec<u8>, Vec<u8>>,
fmap: HashMap<Vec<u8>, MessageHandler>,
}

impl Database {
/// Creates a new database instance.
pub fn new() -> Self {
Database {
hmap: HashMap::new(),
fmap: HashMap::new(),
}
}

Expand Down Expand Up @@ -128,6 +158,34 @@ impl Database {
.and_modify(|v| *v = encoded_balance.clone())
.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);
self.fmap
.entry(hashed_key.to_vec())
.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.as_slice()).unwrap()
}

pub fn set_code_hash(&mut self, account: &Vec<u8>, 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<u8>) -> Option<Vec<u8>> {
let hashed_key = code_hash_of_key(account);
self.get(&hashed_key).cloned()
}
}

#[cfg(test)]
Expand Down
2 changes: 1 addition & 1 deletion crates/engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
2 changes: 2 additions & 0 deletions crates/env/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ ink = { path = "../ink" }
default = [ "std" ]
std = [
"blake2",
"ink/std",
"ink_allocator/std",
"ink_prelude/std",
"ink_primitives/std",
Expand All @@ -92,6 +93,7 @@ std = [
"xcm/std",
"derive_more/std"
]
test_instantiate = []

# Enable contract debug messages via `debug_print!` and `debug_println!`.
ink-debug = []
Expand Down
27 changes: 24 additions & 3 deletions crates/env/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@ use crate::{
CryptoHash,
HashOutput,
},
types::Gas,
Environment,
types::{
Environment,
Gas,
},
Result,
};
use ink_storage_traits::Storable;
Expand Down Expand Up @@ -383,7 +385,9 @@ pub fn instantiate_contract<E, ContractRef, Args, Salt, R>(
>
where
E: Environment,
ContractRef: FromAccountId<E>,
ContractRef: FromAccountId<E> + crate::ContractReverseReference,
<ContractRef as crate::ContractReverseReference>::Type:
crate::reflect::ContractConstructorDecoder,
Args: scale::Encode,
Salt: AsRef<[u8]>,
R: ConstructorReturnType<ContractRef>,
Expand Down Expand Up @@ -512,6 +516,7 @@ where
/// # Note
///
/// This function stops the execution of the contract immediately.
#[cfg(not(feature = "test_instantiate"))]
pub fn return_value<R>(return_flags: ReturnFlags, return_value: &R) -> !
where
R: scale::Encode,
Expand All @@ -521,6 +526,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<R>(return_flags: ReturnFlags, return_value: &R)
where
R: scale::Encode,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
EnvBackend::return_value::<R>(instance, return_flags, return_value)
})
}

/// Appends the given message to the debug message buffer.
pub fn debug_message(message: &str) {
<EnvInstance as OnInstance>::on_instance(|instance| {
Expand Down
21 changes: 19 additions & 2 deletions crates/env/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use crate::{
CryptoHash,
HashOutput,
},
Environment,
types::Environment,
Result,
};
use ink_storage_traits::Storable;
Expand Down Expand Up @@ -121,10 +121,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<R>(&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<R>(&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
Expand Down Expand Up @@ -363,7 +378,9 @@ pub trait TypedEnvBackend: EnvBackend {
>
where
E: Environment,
ContractRef: FromAccountId<E>,
ContractRef: FromAccountId<E> + crate::ContractReverseReference,
<ContractRef as crate::ContractReverseReference>::Type:
crate::reflect::ContractConstructorDecoder,
Args: scale::Encode,
Salt: AsRef<[u8]>,
R: ConstructorReturnType<ContractRef>;
Expand Down
6 changes: 4 additions & 2 deletions crates/env/src/call/call_builder/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ use crate::{
CallParams,
ExecutionInput,
},
Environment,
types::{
Environment,
Gas,
},
Error,
Gas,
};
use num_traits::Zero;
#[cfg(not(feature = "revive"))]
Expand Down
6 changes: 4 additions & 2 deletions crates/env/src/call/call_builder/call_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ use crate::{
CallBuilder,
ExecutionInput,
},
Environment,
types::{
Environment,
Gas,
},
Error,
Gas,
};
use num_traits::Zero;
#[cfg(not(feature = "revive"))]
Expand Down
2 changes: 1 addition & 1 deletion crates/env/src/call/call_builder/delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use crate::{
CallParams,
ExecutionInput,
},
Environment,
types::Environment,
Error,
};
#[cfg(not(feature = "revive"))]
Expand Down
2 changes: 1 addition & 1 deletion crates/env/src/call/call_builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use crate::{
Execution,
ExecutionInput,
},
Environment,
types::Environment,
};
use core::marker::PhantomData;

Expand Down
14 changes: 11 additions & 3 deletions crates/env/src/call/create_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use crate::{
Selector,
},
ContractEnv,
Environment,
types::Environment,
Error,
};
use core::marker::PhantomData;
Expand Down Expand Up @@ -293,7 +293,11 @@ impl<E, ContractRef, Args, Salt, R>
CreateParams<E, ContractRef, LimitParamsV2<E>, Args, Salt, R>
where
E: Environment,
ContractRef: FromAccountId<E>,
ContractRef: FromAccountId<E> + crate::ContractReverseReference,
<ContractRef as crate::ContractReverseReference>::Type:
crate::reflect::ContractConstructorDecoder,
<ContractRef as crate::ContractReverseReference>::Type:
crate::reflect::ContractMessageDecoder,
Args: scale::Encode,
Salt: AsRef<[u8]>,
R: ConstructorReturnType<ContractRef>,
Expand Down Expand Up @@ -883,7 +887,11 @@ impl<E, ContractRef, Args, Salt, RetType>
>
where
E: Environment,
ContractRef: FromAccountId<E>,
ContractRef: FromAccountId<E> + crate::ContractReverseReference,
<ContractRef as crate::ContractReverseReference>::Type:
crate::reflect::ContractConstructorDecoder,
<ContractRef as crate::ContractReverseReference>::Type:
crate::reflect::ContractMessageDecoder,
Args: scale::Encode,
Salt: AsRef<[u8]>,
RetType: ConstructorReturnType<ContractRef>,
Expand Down
4 changes: 2 additions & 2 deletions crates/env/src/engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ pub(crate) fn decode_instantiate_result<I, E, ContractRef, R>(
) -> EnvResult<ConstructorResult<<R as ConstructorReturnType<ContractRef>>::Output>>
where
I: scale::Input,
E: crate::Environment,
E: crate::types::Environment,
ContractRef: FromAccountId<E>,
R: ConstructorReturnType<ContractRef>,
{
Expand All @@ -106,7 +106,7 @@ fn decode_instantiate_err<I, E, ContractRef, R>(
) -> EnvResult<ConstructorResult<<R as ConstructorReturnType<ContractRef>>::Output>>
where
I: scale::Input,
E: crate::Environment,
E: crate::types::Environment,
ContractRef: FromAccountId<E>,
R: ConstructorReturnType<ContractRef>,
{
Expand Down
Loading

0 comments on commit c7de4c2

Please sign in to comment.