diff --git a/CHANGELOG.md b/CHANGELOG.md index d33fbe03b5..d98b9f5ac8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `packed` flag to `storage_item` attribute and improve related diagnostics - [](https://github.com/use-ink/ink/pull/2722) ### Changed -- Refactor contract ref generation and add automatic re-exporting ‒ [#2710](https://github.com/use-ink/ink/pull/2710) +- Implements the API for the `pallet-revive` host functions `chain_id`, `balance_of`, `base_fee`, `origin`, `code_size`, `block_hash`, `block_author` - [#2719](https://github.com/use-ink/ink/pull/2719) +- Refactor contract ref generation and add automatic re-exporting - [#2710](https://github.com/use-ink/ink/pull/2710) - Implement and stabilize `terminate_contract` ‒ [2708](https://github.com/use-ink/ink/pull/2708) ## Version 6.0.0-beta diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index 6105dd8d26..758771549e 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -26,6 +26,7 @@ use ink_primitives::{ Sol, }, sol::SolResultEncode, + types::BlockNumber, }; use ink_storage_traits::Storable; use pallet_revive_uapi::ReturnFlags; @@ -111,6 +112,62 @@ pub fn return_data_size() -> u64 { ::on_instance(TypedEnvBackend::return_data_size) } +/// Returns the [EIP-155](https://eips.ethereum.org/EIPS/eip-155) chain ID, +/// akin to the EVM [CHAINID](https://www.evm.codes/?fork=cancun#46) opcode. +pub fn chain_id() -> U256 { + ::on_instance(TypedEnvBackend::chain_id) +} + +/// Returns the **reducible** native balance of the supplied address, +/// akin to the EVM [BALANCE](https://www.evm.codes/?fork=cancun#31) opcode. +pub fn balance_of(addr: Address) -> U256 { + ::on_instance(|instance| { + TypedEnvBackend::balance_of(instance, addr) + }) +} + +/// Returns the base fee. +/// This is akin to the EVM [BASEFEE](https://www.evm.codes/?fork=cancun#48) opcode. +pub fn base_fee() -> U256 { + ::on_instance(TypedEnvBackend::base_fee) +} + +/// Returns the origin address (initator of the call stack). +/// This is akin to the EVM [ORIGIN](https://www.evm.codes/?fork=cancun#32) opcode. +/// +/// # Errors +/// +/// - If there is no address associated with the origin (e.g. because the origin is root). +pub fn origin() -> Address { + ::on_instance(TypedEnvBackend::origin) +} + +/// Returns the code size for a specified contract address. +/// This is akin to the EVM [CODESIZE](https://www.evm.codes/?fork=cancun#38) opcode. +/// +/// # Note +/// +/// If `addr` is not a contract the `output` will be zero. +pub fn code_size(addr: Address) -> u64 { + ::on_instance(|instance| { + TypedEnvBackend::code_size(instance, addr) + }) +} + +/// Returns the block hash of the given block number. +/// This is akin to the EVM [BLOCKHASH](https://www.evm.codes/?fork=cancun#40) opcode. +pub fn block_hash(block_number: BlockNumber) -> H256 { + ::on_instance(|instance| { + TypedEnvBackend::block_hash(instance, block_number) + }) +} + +/// Returns the current block author. +/// This is akin to the EVM [COINBASE](https://www.evm.codes/?fork=cancun#41) opcode. +pub fn block_author() -> Address { + ::on_instance(TypedEnvBackend::block_author) +} + /// Returns the transferred value for the contract execution. /// /// # Errors diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index f71a0ca063..b5794fe343 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -20,7 +20,10 @@ use ink_primitives::{ H256, U256, sol::SolResultEncode, - types::Environment, + types::{ + BlockNumber, + Environment, + }, }; use ink_storage_traits::Storable; pub use pallet_revive_uapi::ReturnFlags; @@ -304,9 +307,71 @@ pub trait TypedEnvBackend: EnvBackend { /// /// # Note /// - /// For more details visit: [`return_data_size`][`crate::return_data_size] + /// For more details visit: [`return_data_size`][`crate::return_data_size`] fn return_data_size(&mut self) -> u64; + /// Returns the [EIP-155](https://eips.ethereum.org/EIPS/eip-155) chain ID. + /// This is akin to the EVM [CHAINID](https://www.evm.codes/?fork=cancun#46) opcode. + /// + /// # Note + /// + /// For more details visit: [`chain_id`][`crate::chain_id`] + fn chain_id(&mut self) -> U256; + + /// Returns the **reducible** native balance of the supplied address. + /// This is akin to the EVM [BALANCE](https://www.evm.codes/?fork=cancun#31) opcode. + /// + /// # Note + /// + /// For more details visit: [`balance_of`][`crate::balance_of`] + fn balance_of(&mut self, addr: Address) -> U256; + + /// Returns the base fee. + /// This is akin to the EVM [BASEFEE](https://www.evm.codes/?fork=cancun#48) opcode. + /// + /// # Note + /// + /// For more details visit: [`base_fee`][`crate::base_fee`] + fn base_fee(&mut self) -> U256; + + /// Returns the origin address (initator of the call stack). + /// This is akin to the EVM [ORIGIN](https://www.evm.codes/?fork=cancun#32) opcode. + /// + /// # Errors + /// + /// - If there is no address associated with the origin (e.g. because the origin is + /// root). + /// + /// # Note + /// + /// For more details visit: [`origin`][`crate::origin`] + fn origin(&mut self) -> Address; + + /// Returns the code size for a specified contract address. + /// This is akin to the EVM [CODESIZE](https://www.evm.codes/?fork=cancun#38) opcode. + /// + /// # Note + /// + /// If `addr` is not a contract the `output` will be zero. + /// For more details visit: [`code_size`][`crate::code_size`] + fn code_size(&mut self, addr: Address) -> u64; + + /// Returns the block hash of the given block number. + /// This is akin to the EVM [BLOCKHASH](https://www.evm.codes/?fork=cancun#40) opcode. + /// + /// # Note + /// + /// For more details visit: [`block_hash`][`crate::block_hash`] + fn block_hash(&mut self, block_number: BlockNumber) -> H256; + + /// Returns the current block author. + /// This is akin to the EVM [COINBASE](https://www.evm.codes/?fork=cancun#41) opcode. + /// + /// # Note + /// + /// For more details visit: [`block_author`][`crate::block_author`] + fn block_author(&mut self) -> Address; + /// Returns the transferred value for the contract execution. /// /// # Note diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index 6854b77c27..5e04239876 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -28,6 +28,7 @@ use ink_primitives::{ sol::SolResultEncode, types::{ AccountIdMapper, + BlockNumber, Environment, }, }; @@ -582,6 +583,34 @@ impl TypedEnvBackend for EnvInstance { unimplemented!("not implemented, the off-chain environment will be removed"); } + fn chain_id(&mut self) -> U256 { + unimplemented!("not implemented, the off-chain environment will be removed"); + } + + fn balance_of(&mut self, _addr: Address) -> U256 { + unimplemented!("not implemented, the off-chain environment will be removed"); + } + + fn base_fee(&mut self) -> U256 { + unimplemented!("not implemented, the off-chain environment will be removed"); + } + + fn origin(&mut self) -> Address { + unimplemented!("not implemented, the off-chain environment will be removed"); + } + + fn block_hash(&mut self, _block_number: BlockNumber) -> H256 { + unimplemented!("not implemented, the off-chain environment will be removed"); + } + + fn block_author(&mut self) -> Address { + unimplemented!("not implemented, the off-chain environment will be removed"); + } + + fn code_size(&mut self, _addr: Address) -> u64 { + unimplemented!("not implemented, the off-chain environment will be removed"); + } + fn call_data_size(&mut self) -> u64 { unimplemented!("not implemented, the off-chain environment will be removed"); } diff --git a/crates/env/src/engine/on_chain/pallet_revive.rs b/crates/env/src/engine/on_chain/pallet_revive.rs index 329968be10..b0bacae2f4 100644 --- a/crates/env/src/engine/on_chain/pallet_revive.rs +++ b/crates/env/src/engine/on_chain/pallet_revive.rs @@ -25,6 +25,7 @@ use ink_primitives::{ Sol, }, sol::SolResultEncode, + types::BlockNumber, }; use ink_storage_traits::{ Storable, @@ -1027,6 +1028,70 @@ impl TypedEnvBackend for EnvInstance { ext::return_data_size() } + fn chain_id(&mut self) -> U256 { + let mut scope = self.scoped_buffer(); + let u256: &mut [u8; 32] = scope.take(32).try_into().unwrap(); + + ext::chain_id(u256); + U256::from_le_bytes(*u256) + } + + fn balance_of(&mut self, addr: Address) -> U256 { + let mut scope = self.scoped_buffer(); + let u256: &mut [u8; 32] = scope.take(32).try_into().unwrap(); + + let addr = addr.as_fixed_bytes(); + + ext::balance_of(&addr, u256); + U256::from_le_bytes(*u256) + } + + fn base_fee(&mut self) -> U256 { + let mut scope = self.scoped_buffer(); + let u256: &mut [u8; 32] = scope.take(32).try_into().unwrap(); + + ext::base_fee(u256); + U256::from_le_bytes(*u256) + } + + fn origin(&mut self) -> Address { + let mut scope = self.scoped_buffer(); + let h160: &mut [u8; 20] = scope.take(20).try_into().unwrap(); + + ext::origin(h160); + h160.into() + } + + fn code_size(&mut self, addr: Address) -> u64 { + let addr = addr.as_fixed_bytes(); + + ext::code_size(addr) + } + + fn block_hash(&mut self, block_number: BlockNumber) -> H256 { + let mut scope = self.scoped_buffer(); + let output: &mut [u8; 32] = scope.take(32).try_into().unwrap(); + + let block_number = { + let mut bytes = [0u8; 32]; + bytes[..4].copy_from_slice(&block_number.to_le_bytes()); + bytes + }; + + ext::block_hash(&block_number, output); + H256::from_slice(output) + } + + fn block_author(&mut self) -> Address { + let h160 = { + let mut scope = self.scoped_buffer(); + let h160: &mut [u8; 20] = scope.take(20).try_into().unwrap(); + ext::block_author(h160); + *h160 + }; + h160.into() + } + fn transferred_value(&mut self) -> U256 { let mut scope = self.scoped_buffer(); let u256: &mut [u8; 32] = scope.take(32).try_into().unwrap(); diff --git a/crates/ink/src/env_access.rs b/crates/ink/src/env_access.rs index 2f726baca0..9a01847f56 100644 --- a/crates/ink/src/env_access.rs +++ b/crates/ink/src/env_access.rs @@ -46,6 +46,7 @@ use ink_primitives::{ Ink, Sol, }, + types::BlockNumber, }; use pallet_revive_uapi::ReturnErrorCode; @@ -274,6 +275,242 @@ where ink_env::return_data_size() } + /// Returns the [EIP-155](https://eips.ethereum.org/EIPS/eip-155) chain ID, + /// akin to the EVM [CHAINID](https://www.evm.codes/?fork=cancun#46) opcode. + /// + /// # Example + /// + /// ``` + /// #[ink::contract] + /// mod my_contract { + /// use ink::U256; + /// + /// #[ink(storage)] + /// pub struct MyContract; + /// + /// impl MyContract { + /// #[ink(constructor)] + /// pub fn new() -> Self { + /// Self {} + /// } + /// + /// #[ink(message)] + /// pub fn get_chain_id(&self) -> U256 { + /// self.env().chain_id() + /// } + /// } + /// } + /// ``` + /// + /// # Note + /// + /// For more details visit: [`ink_env::chain_id`] + pub fn chain_id(self) -> U256 { + ink_env::chain_id() + } + + /// Returns the **reducible** native balance of the supplied address. + /// This is akin to the EVM [BALANCE](https://www.evm.codes/?fork=cancun#31) opcode. + /// + /// # Example + /// + /// ``` + /// #[ink::contract] + /// mod my_contract { + /// use ink::U256; + /// + /// #[ink(storage)] + /// pub struct MyContract; + /// + /// impl MyContract { + /// #[ink(constructor)] + /// pub fn new() -> Self { + /// Self {} + /// } + /// + /// #[ink(message)] + /// pub fn get_my_balance(&self) -> U256 { + /// let caller = self.env().caller(); + /// self.env().balance_of(caller) + /// } + /// } + /// } + /// ``` + /// + /// # Note + /// + /// For more details visit: [`ink_env::balance_of`] + pub fn balance_of(self, addr: Address) -> U256 { + ink_env::balance_of(addr) + } + + /// Returns the base fee. + /// This is akin to the EVM [BASEFEE](https://www.evm.codes/?fork=cancun#48) opcode. + /// + /// # Example + /// + /// ``` + /// #[ink::contract] + /// mod my_contract { + /// use ink::U256; + /// + /// #[ink(storage)] + /// pub struct MyContract; + /// + /// impl MyContract { + /// #[ink(constructor)] + /// pub fn new() -> Self { + /// Self {} + /// } + /// + /// #[ink(message)] + /// pub fn get_base_fee(&self) -> U256 { + /// self.env().base_fee() + /// } + /// } + /// } + /// ``` + /// + /// # Note + /// + /// For more details visit: [`ink_env::base_fee`] + pub fn base_fee(self) -> U256 { + ink_env::base_fee() + } + + /// Returns the origin address (initator of the call stack). + /// This is akin to the EVM [ORIGIN](https://www.evm.codes/?fork=cancun#32) opcode. + /// + /// # Example + /// + /// ``` + /// #[ink::contract] + /// mod my_contract { + /// #[ink(storage)] + /// pub struct MyContract; + /// + /// impl MyContract { + /// #[ink(constructor)] + /// pub fn new() -> Self { + /// Self {} + /// } + /// + /// #[ink(message)] + /// pub fn get_origin(&self) -> Address { + /// self.env().origin() + /// } + /// } + /// } + /// ``` + /// + /// # Note + /// + /// For more details visit: [`ink_env::origin`] + pub fn origin(self) -> Address { + ink_env::origin() + } + + /// Returns the code size for a specified contract address. + /// This is akin to the EVM [CODESIZE](https://www.evm.codes/?fork=cancun#38) opcode. + /// + /// # Example + /// + /// ``` + /// #[ink::contract] + /// mod my_contract { + /// #[ink(storage)] + /// pub struct MyContract; + /// + /// impl MyContract { + /// #[ink(constructor)] + /// pub fn new() -> Self { + /// Self {} + /// } + /// + /// #[ink(message)] + /// pub fn get_code_size_of_this_contract(&self) -> u64 { + /// let this_addr = self.env().address(); + /// self.env().code_size(this_addr) + /// } + /// } + /// } + /// ``` + /// + /// # Note + /// + /// If `addr` is not a contract the `output` will be zero. + /// For more details visit: [`ink_env::code_size`] + pub fn code_size(self, addr: Address) -> u64 { + ink_env::code_size(addr) + } + + /// Returns the block hash of the given block number. + /// This is akin to the EVM [BLOCKHASH](https://www.evm.codes/?fork=cancun#40) opcode. + /// + /// # Example + /// + /// ``` + /// #[ink::contract] + /// mod my_contract { + /// #[ink(storage)] + /// pub struct MyContract; + /// + /// impl MyContract { + /// #[ink(constructor)] + /// pub fn new() -> Self { + /// Self {} + /// } + /// + /// #[ink(message)] + /// pub fn get_block_hash( + /// &self, + /// block_number: BlockNumber, + /// ) -> ink_primitives::H256 { + /// self.env().block_hash(block_number) + /// } + /// } + /// } + /// ``` + /// + /// # Note + /// + /// For more details visit: [`ink_env::block_hash`] + pub fn block_hash(self, block_number: BlockNumber) -> H256 { + ink_env::block_hash(block_number) + } + + /// Returns the current block author. + /// This is akin to the EVM [COINBASE](https://www.evm.codes/?fork=cancun#41) opcode. + /// + /// # Example + /// + /// ``` + /// #[ink::contract] + /// mod my_contract { + /// #[ink(storage)] + /// pub struct MyContract; + /// + /// impl MyContract { + /// #[ink(constructor)] + /// pub fn new() -> Self { + /// Self {} + /// } + /// + /// #[ink(message)] + /// pub fn get_block_author(&self) -> Address { + /// self.env().block_author() + /// } + /// } + /// } + /// ``` + /// + /// # Note + /// + /// For more details visit: [`ink_env::block_author`] + pub fn block_author(self) -> Address { + ink_env::block_author() + } + /// Returns the transferred value for the contract execution. /// /// # Example diff --git a/crates/ink/tests/ui/contract/pass/env-access.rs b/crates/ink/tests/ui/contract/pass/env-access.rs index 0d515966a6..672443cff6 100644 --- a/crates/ink/tests/ui/contract/pass/env-access.rs +++ b/crates/ink/tests/ui/contract/pass/env-access.rs @@ -17,8 +17,12 @@ mod contract { let _ = Self::env().gas_limit(); let _ = Self::env().gas_price(); let _ = Self::env().gas_left(); + let _ = Self::env().chain_id(); let _ = Self::env().call_data_size(); let _ = Self::env().return_data_size(); + let _ = Self::env().base_fee(); + let _ = Self::env().origin(); + let _ = Self::env().block_author(); let _ = Self::env().transferred_value(); let _ = Self::env().weight_to_fee(0); Self {} @@ -35,8 +39,12 @@ mod contract { let _ = self.env().gas_limit(); let _ = self.env().gas_price(); let _ = self.env().gas_left(); + let _ = self.env().chain_id(); let _ = self.env().call_data_size(); let _ = self.env().return_data_size(); + let _ = self.env().base_fee(); + let _ = self.env().origin(); + let _ = self.env().block_author(); let _ = self.env().transferred_value(); let _ = self.env().weight_to_fee(0); } diff --git a/integration-tests/internal/misc-evm-getters-hostfns/Cargo.toml b/integration-tests/internal/misc-evm-getters-hostfns/Cargo.toml new file mode 100755 index 0000000000..0bca3e10d1 --- /dev/null +++ b/integration-tests/internal/misc-evm-getters-hostfns/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "misc-evm-getters-hostfns" +description = "E2E tests for evm getters related host functions" +version = "6.0.0-beta" +authors = ["Use Ink "] +edition = "2021" +publish = false + +[dependencies] +ink = { path = "../../../crates/ink", default-features = false } + +[dev-dependencies] +ink_e2e = { path = "../../../crates/e2e" } +ink_primitives = { path = "../../../crates/primitives" } + +[lib] +path = "lib.rs" + +[features] +default = ["std"] +std = [ + "ink/std", +] +ink-as-dependency = [] +e2e-tests = [] + +[package.metadata.ink-lang] +abi = "ink" diff --git a/integration-tests/internal/misc-evm-getters-hostfns/lib.rs b/integration-tests/internal/misc-evm-getters-hostfns/lib.rs new file mode 100644 index 0000000000..24109cbb7b --- /dev/null +++ b/integration-tests/internal/misc-evm-getters-hostfns/lib.rs @@ -0,0 +1,287 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] +#![allow(clippy::new_without_default)] + +#[ink::contract] +mod misc_evm_getters_hostfns { + use ink::{ + H256, + U256, + }; + + #[ink(storage)] + pub struct MiscEVMGettersfns {} + + impl MiscEVMGettersfns { + #[ink(constructor)] + pub fn new() -> Self { + Self {} + } + + /// Checks that the host function `chain_id` works + #[ink(message)] + pub fn chain_id(&self) -> U256 { + self.env().chain_id() + } + + /// Checks that the host function `balance_of` works + #[ink(message)] + pub fn balance_of(&self) -> U256 { + let caller = self.env().caller(); + self.env().balance_of(caller) + } + + /// Checks that the host function `base_fee` works + #[ink(message)] + pub fn base_fee(&self) -> U256 { + self.env().base_fee() + } + + /// Checks that the host function `origin` works + #[ink(message)] + pub fn origin(&self) -> Address { + self.env().origin() + } + + /// Checks that the host function `code_size` works + #[ink(message)] + pub fn code_size(&self) -> u64 { + let this_addr = self.env().address(); + self.env().code_size(this_addr) + } + + /// Checks that the host function `block_hash` works + #[ink(message)] + pub fn block_hash(&self, block_number: BlockNumber) -> H256 { + self.env().block_hash(block_number) + } + + /// Checks that the host function `block_author` works + #[ink(message)] + pub fn block_author(&self) -> Address { + self.env().block_author() + } + } + + #[cfg(all(test, feature = "e2e-tests"))] + mod e2e_tests { + use super::*; + use ink_e2e::{ + ContractsBackend, + address_from_keypair, + }; + + type E2EResult = std::result::Result>; + + #[ink_e2e::test] + async fn e2e_chain_id_works( + mut client: Client, + ) -> E2EResult<()> { + // given + let contract = client + .instantiate( + "misc_evm_getters_hostfns", + &ink_e2e::alice(), + &mut MiscEVMGettersfnsRef::new(), + ) + .submit() + .await + .expect("instantiate failed"); + let call_builder = contract.call_builder::(); + + // then + let call_res = client + .call(&ink_e2e::alice(), &call_builder.chain_id()) + .submit() + .await + .unwrap_or_else(|err| { + panic!("call failed: {:#?}", err); + }); + + assert!(call_res.return_value() > U256::from(0)); + + Ok(()) + } + + #[ink_e2e::test] + async fn e2e_balance_of_works( + mut client: Client, + ) -> E2EResult<()> { + // given + let contract = client + .instantiate( + "misc_evm_getters_hostfns", + &ink_e2e::alice(), + &mut MiscEVMGettersfnsRef::new(), + ) + .submit() + .await + .expect("instantiate failed"); + let call_builder = contract.call_builder::(); + + // then + let call_res = client + .call(&ink_e2e::alice(), &call_builder.balance_of()) + .submit() + .await + .unwrap_or_else(|err| { + panic!("call failed: {:#?}", err); + }); + + assert!(call_res.return_value() > U256::from(0)); + + Ok(()) + } + + #[ink_e2e::test] + async fn e2e_base_fee_works( + mut client: Client, + ) -> E2EResult<()> { + // given + let contract = client + .instantiate( + "misc_evm_getters_hostfns", + &ink_e2e::alice(), + &mut MiscEVMGettersfnsRef::new(), + ) + .submit() + .await + .expect("instantiate failed"); + let call_builder = contract.call_builder::(); + + // then + let call_res = client + .call(&ink_e2e::alice(), &call_builder.base_fee()) + .submit() + .await + .unwrap_or_else(|err| { + panic!("call failed: {:#?}", err); + }); + + assert!(call_res.return_value() > U256::from(0)); + + Ok(()) + } + + #[ink_e2e::test] + async fn e2e_origin_works( + mut client: Client, + ) -> E2EResult<()> { + // given + let contract = client + .instantiate( + "misc_evm_getters_hostfns", + &ink_e2e::alice(), + &mut MiscEVMGettersfnsRef::new(), + ) + .submit() + .await + .expect("instantiate failed"); + let call_builder = contract.call_builder::(); + + // then + let call_res = client + .call(&ink_e2e::alice(), &call_builder.origin()) + .submit() + .await + .unwrap_or_else(|err| { + panic!("call failed: {:#?}", err); + }); + + assert_eq!( + call_res.return_value(), + address_from_keypair::(&ink_e2e::alice()) + ); + + Ok(()) + } + + #[ink_e2e::test] + async fn e2e_code_size_works( + mut client: Client, + ) -> E2EResult<()> { + // given + let contract = client + .instantiate( + "misc_evm_getters_hostfns", + &ink_e2e::alice(), + &mut MiscEVMGettersfnsRef::new(), + ) + .submit() + .await + .expect("instantiate failed"); + let call_builder = contract.call_builder::(); + + // then + let call_res = client + .call(&ink_e2e::alice(), &call_builder.code_size()) + .submit() + .await + .unwrap_or_else(|err| { + panic!("call failed: {:#?}", err); + }); + + assert!(call_res.return_value() > 0); + + Ok(()) + } + + #[ink_e2e::test] + async fn e2e_block_hash_works( + mut client: Client, + ) -> E2EResult<()> { + // given + let contract = client + .instantiate( + "misc_evm_getters_hostfns", + &ink_e2e::alice(), + &mut MiscEVMGettersfnsRef::new(), + ) + .submit() + .await + .expect("instantiate failed"); + let call_builder = contract.call_builder::(); + + // then + let _call_res = client + .call( + &ink_e2e::alice(), + &call_builder.block_hash(BlockNumber::from(0u32)), + ) + .submit() + .await + .unwrap_or_else(|err| { + panic!("call failed: {:#?}", err); + }); + + Ok(()) + } + + #[ink_e2e::test] + async fn e2e_block_author_works( + mut client: Client, + ) -> E2EResult<()> { + // given + let contract = client + .instantiate( + "misc_evm_getters_hostfns", + &ink_e2e::alice(), + &mut MiscEVMGettersfnsRef::new(), + ) + .submit() + .await + .expect("instantiate failed"); + let call_builder = contract.call_builder::(); + + // then + let _call_res = client + .call(&ink_e2e::alice(), &call_builder.block_author()) + .submit() + .await + .unwrap_or_else(|err| { + panic!("call failed: {:#?}", err); + }); + + Ok(()) + } + } +}