Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

[Unreleased]

### Added
- Implements the API for the `pallet-revive` host function `to_account_id` - [#2578](https://github.com/use-ink/ink/pull/2578)

### Changed
- Marks the `pallet-revive` host function `account_id` stable - [#2578](https://github.com/use-ink/ink/pull/2578)

## Version 6.0.0-alpha.4

### Added
Expand Down
23 changes: 21 additions & 2 deletions crates/engine/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ 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:";
const ACCOUNT_ID_OF: &[u8] = b"account-id:";

/// Returns the database key under which to find the balance for contract `who`.
pub fn balance_of_key(who: &Address) -> [u8; 32] {
Expand All @@ -36,6 +37,14 @@ pub fn balance_of_key(who: &Address) -> [u8; 32] {
hashed_key
}

/// Returns the database key under which to find the account id for the address `who`.
pub fn account_id_of_key(who: &Address) -> [u8; 32] {
let keyed = who.0.to_vec().to_keyed_vec(ACCOUNT_ID_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 storage for contract `who`.
pub fn storage_of_contract_key(who: &Address, key: &[u8]) -> [u8; 32] {
let keyed = who
Expand Down Expand Up @@ -152,15 +161,25 @@ impl Database {
}

/// Returns the balance of the contract at `addr`, if available.
pub fn get_acc_balance(&self, _addr: &AccountId) -> Option<Balance> {
pub fn get_acc_balance(&self, _account_id: &AccountId) -> Option<Balance> {
todo!()
}

/// Sets the balance of `addr` to `new_balance`.
pub fn set_acc_balance(&mut self, _addr: &AccountId, _new_balance: Balance) {
pub fn set_acc_balance(&mut self, _account_id: &AccountId, _new_balance: Balance) {
todo!()
}

/// Retrieves the account id for a specified address.
pub fn to_account_id(&self, addr: &Address) -> Vec<u8> {
let hashed_key = account_id_of_key(addr);
self.get(&hashed_key).cloned().unwrap_or_else(|| {
let mut bytes = [0xEE; 32];
bytes[..20].copy_from_slice(&addr.as_bytes()[..20]);
Vec::from(bytes)
})
}

pub fn get_balance(&self, addr: &Address) -> Option<U256> {
let hashed_key = balance_of_key(addr);
self.get(&hashed_key).map(|encoded_balance| {
Expand Down
18 changes: 18 additions & 0 deletions crates/engine/src/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,24 @@ impl Engine {
set_output(output, callee)
}

pub fn account_id(&self, output: &mut &mut [u8]) {
let callee = self
.exec_context
.callee
.as_ref()
.expect("no callee has been set");
let account_id = self.database.to_account_id(callee);
set_output(output, account_id.as_slice())
}

/// Retrieves the account id for a specified address.
pub fn to_account_id(&self, input: &[u8], output: &mut &mut [u8]) {
let addr =
scale::Decode::decode(&mut &input[..]).expect("unable to decode Address");
let account_id = self.database.to_account_id(&addr);
set_output(output, account_id.as_slice())
}

/// Conduct the BLAKE-2 256-bit hash and place the result into `output`.
pub fn hash_blake2_256(input: &[u8], output: &mut [u8; 32]) {
super::hashing::blake2b_256(input, output);
Expand Down
15 changes: 15 additions & 0 deletions crates/env/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,21 @@ where
})
}

/// Retrieves the account id for a specified address.
///
/// # Errors
///
/// If the returned value cannot be properly decoded.
#[cfg(feature = "unstable-hostfn")]
pub fn to_account_id<E>(addr: Address) -> E::AccountId
where
E: Environment,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
TypedEnvBackend::to_account_id::<E>(instance, addr)
})
}

/// Returns the account ID of the executed contract.
///
/// # Note
Expand Down
8 changes: 8 additions & 0 deletions crates/env/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,14 @@ pub trait TypedEnvBackend: EnvBackend {
/// For more details visit: [`block_timestamp`][`crate::block_timestamp`]
fn block_timestamp<E: Environment>(&mut self) -> E::Timestamp;

/// Retrieves the account id for a specified address.
///
/// # Note
///
/// For more details visit: [`to_account_id`][`crate::to_account_id`]
#[cfg(feature = "unstable-hostfn")]
fn to_account_id<E: Environment>(&mut self, addr: Address) -> E::AccountId;

/// Returns the address of the executed contract.
///
/// # Note
Expand Down
11 changes: 9 additions & 2 deletions crates/env/src/engine/off_chain/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -560,9 +560,16 @@ impl TypedEnvBackend for EnvInstance {
})
}

#[cfg(feature = "unstable-hostfn")]
fn to_account_id<E: Environment>(&mut self, addr: Address) -> E::AccountId {
let mut full_scope: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];
let full_scope = &mut &mut full_scope[..];
Engine::to_account_id(&self.engine, addr.as_bytes(), full_scope);
scale::Decode::decode(&mut &full_scope[..]).unwrap()
}

fn account_id<E: Environment>(&mut self) -> E::AccountId {
// todo should not use `Engine::account_id`
self.get_property::<E::AccountId>(Engine::address)
self.get_property::<E::AccountId>(Engine::account_id)
.unwrap_or_else(|error| {
panic!("could not read `account_id` property: {error:?}")
})
Expand Down
9 changes: 9 additions & 0 deletions crates/env/src/engine/on_chain/pallet_revive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -880,6 +880,15 @@ impl TypedEnvBackend for EnvInstance {
scale::Decode::decode(&mut &output[64..96]).expect("must exist")
}

#[cfg(feature = "unstable-hostfn")]
fn to_account_id<E: Environment>(&mut self, addr: Address) -> E::AccountId {
let mut scope = self.scoped_buffer();
let account_id: &mut [u8; 32] = scope.take(32).try_into().unwrap();
ext::to_account_id(addr.as_fixed_bytes(), account_id);
scale::Decode::decode(&mut &account_id[..])
.expect("A contract being executed must have a valid account id.")
}

fn address(&mut self) -> Address {
let mut scope = self.scoped_buffer();

Expand Down
53 changes: 47 additions & 6 deletions crates/ink/src/env_access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ where
/// #[ink(message)]
/// pub fn foo(&self) {}
///
/// // todo
/// // /// Returns a tuple of
/// // /// - the result of adding the `rhs` to the `lhs`
/// // /// - the gas costs of this addition operation
Expand Down Expand Up @@ -224,37 +225,77 @@ where
ink_env::block_timestamp::<E>()
}

/// Retrieves the account id for a specified address.
///
/// # Example
///
/// ```
/// #[ink::contract]
/// pub mod only_owner {
/// #[ink(storage)]
/// pub struct OnlyOwner {
/// owner: AccountId,
/// value: u32,
/// }
///
/// impl OnlyOwner {
/// #[ink(constructor)]
/// pub fn new(owner: AccountId) -> Self {
/// Self { owner, value: 0 }
/// }
///
/// /// Allows incrementing the contract's `value` only
/// /// for the owner.
/// ///
/// /// The contract panics if the caller is not the owner.
/// #[ink(message)]
/// pub fn increment(&mut self) {
/// let caller = self.env().address();
/// let caller_acc = self.env().to_account_id(caller);
/// assert!(self.owner == caller_acc);
/// self.value = self.value + 1;
/// }
/// }
/// }
/// ```
///
/// # Note
///
/// For more details visit: [`ink_env::to_account_id`]
#[cfg(feature = "unstable-hostfn")]
pub fn to_account_id(self, addr: Address) -> E::AccountId {
ink_env::to_account_id::<E>(addr)
}

/// Returns the account ID of the executed contract.
///
/// # Example
///
/// todo this code example doesn't use `account_id()`.
/// ```
/// #[ink::contract]
/// pub mod only_owner {
/// #[ink(storage)]
/// pub struct OnlyOwner {
/// owner: ink::Address,
/// owner: AccountId,
/// value: u32,
/// }
///
/// impl OnlyOwner {
/// #[ink(constructor)]
/// pub fn new() -> Self {
/// Self {
/// owner: Self::env().caller(),
/// owner: Self::env().account_id(),
/// value: 0,
/// }
/// }
///
/// /// Allows incrementing the contract's `value` only
/// /// for the owner (i.e. the account which instantiated
/// /// this contract.
/// /// for the owner.
/// ///
/// /// The contract panics if the caller is not the owner.
/// #[ink(message)]
/// pub fn increment(&mut self) {
/// let caller = self.env().caller();
/// let caller = self.env().account_id();
/// assert!(self.owner == caller);
/// self.value = self.value + 1;
/// }
Expand Down
2 changes: 1 addition & 1 deletion integration-tests/internal/lang-err/call-builder/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ mod call_builder {

let result = params
.try_instantiate()
.expect("Error from the Contracts pallet.");
.expect("Error from the `pallet-revive`.");

match result {
Ok(_) => None,
Expand Down
27 changes: 27 additions & 0 deletions integration-tests/internal/misc-hostfns/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[package]
name = "misc_hostfns"
description = "E2E tests for various host functions"
version = "6.0.0-alpha.1"
authors = ["Use Ink <ink@use.ink>"]
edition = "2021"
publish = false

[dependencies]
ink = { path = "../../../crates/ink", default-features = false, features = ["unstable-hostfn"] }

[dev-dependencies]
ink_e2e = { path = "../../../crates/e2e" }

[lib]
path = "lib.rs"

[features]
default = ["std"]
std = [
"ink/std",
]
ink-as-dependency = []
e2e-tests = []

[package.metadata.ink-lang]
abi = "ink"
65 changes: 65 additions & 0 deletions integration-tests/internal/misc-hostfns/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#![cfg_attr(not(feature = "std"), no_std, no_main)]
#![allow(clippy::new_without_default)]

#[ink::contract]
mod misc_hostfns {
#[ink(storage)]
pub struct MiscHostfns {}

impl MiscHostfns {
#[ink(constructor)]
pub fn new() -> Self {
Self {}
}

/// Takes an auction data struct as input and returns it back.
#[ink(message)]
pub fn addr_account_id(&self) {
let addr = self.env().address();
let to_account_id = self.env().to_account_id(addr);
let account_id = self.env().account_id();
assert_eq!(to_account_id, account_id);
}
}

#[cfg(test)]
mod tests {
use super::*;

#[ink::test]
fn works() {
let contract = MiscHostfns::new();
contract.addr_account_id();
}
}

#[cfg(all(test, feature = "e2e-tests"))]
mod e2e_tests {
use super::*;
use ink_e2e::ContractsBackend;

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

#[ink_e2e::test]
async fn e2e_works<Client: E2EBackend>(mut client: Client) -> E2EResult<()> {
// given
let mut constructor = MiscHostfnsRef::new();
let contract = client
.instantiate("misc_hostfns", &ink_e2e::alice(), &mut constructor)
.submit()
.await
.expect("instantiate failed");
let call_builder = contract.call_builder::<MiscHostfns>();

// then
let acc = call_builder.addr_account_id();
let _call_res = client
.call(&ink_e2e::alice(), &acc)
.submit()
.await
.expect("call failed");

Ok(())
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ use pallet_revive::{
use sp_runtime::traits::Bounded;

pub struct PalletReviveExecutor<E: Environment, Runtime: pallet_revive::Config> {
// todo
//pub origin: AccountIdOf<Runtime>,
pub origin: OriginFor<Runtime>,
pub contract: Address,
pub value: BalanceOf<Runtime>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ pub mod delegator {
.await;

/*
// todo
let code_hash = client
.upload("delegatee", &origin)
.submit()
Expand Down Expand Up @@ -284,6 +285,7 @@ pub mod delegator {
.await;

/*
// todo
let code_hash = client
.upload("delegatee", &origin)
.submit()
Expand All @@ -308,6 +310,7 @@ pub mod delegator {
let delegatee_addr = contract.addr;

/*
// todo
let code_hash2 = client
.upload("delegatee2", &origin)
.submit()
Expand Down
Loading