Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
5030d89
implement `gas_limit` host fn
LucasGrasso Oct 24, 2025
f04d729
add tests for `gas_limit` host fn
LucasGrasso Oct 24, 2025
0eec69d
remove off-chain tests for `gas_limit`
LucasGrasso Oct 24, 2025
fddfab0
Merge branch 'use-ink:master' into master
LucasGrasso Oct 24, 2025
95162a9
add changes to changelog
LucasGrasso Oct 24, 2025
1e63416
run formatting
LucasGrasso Oct 26, 2025
9c3ab41
fix error in env-access ui test
LucasGrasso Oct 26, 2025
e0c8351
run formatting
LucasGrasso Oct 27, 2025
eb2f8a3
Apply suggestions from code review
LucasGrasso Oct 28, 2025
4a1f7e3
update versions in gas and misc hostfns internal tests
LucasGrasso Oct 28, 2025
6609561
Merge branch 'master' of https://github.com/LucasGrasso/ink
LucasGrasso Oct 28, 2025
dc87592
Merge remote-tracking branch 'upstream/master'
LucasGrasso Oct 29, 2025
b408418
Merge branch 'use-ink:master' into master
LucasGrasso Oct 30, 2025
ab37628
Merge branch 'use-ink:master' into master
LucasGrasso Nov 7, 2025
23c0ba3
Merge branch 'use-ink:master' into master
LucasGrasso Nov 8, 2025
560cf92
impl and test `chain_id` hostfn
LucasGrasso Nov 9, 2025
aced728
add entry to changelog
LucasGrasso Nov 9, 2025
b970f07
impl and test `balance_of` host fn
LucasGrasso Nov 9, 2025
8e5e5eb
impl and test `base_fee`
LucasGrasso Nov 9, 2025
efaa0b8
impl and test `origin`
LucasGrasso Nov 9, 2025
071db36
impl and test `code_size` hostfn
LucasGrasso Nov 9, 2025
64c31f9
impl and test `block_author`
LucasGrasso Nov 9, 2025
2b92a3f
impl and test `block_hash`
LucasGrasso Nov 9, 2025
28e25f9
run formatting
LucasGrasso Nov 9, 2025
7b06709
Merge remote-tracking branch 'upstream/master'
LucasGrasso Nov 10, 2025
ca4eb06
fix some ci/cd issues
LucasGrasso Nov 10, 2025
d9b2e3d
fix error[E0412]: cannot find type in this scope
LucasGrasso Nov 10, 2025
a0cd8c5
fix docs for chain_id
LucasGrasso Nov 11, 2025
ef52f4c
fix `block_hash` doc error
LucasGrasso Nov 11, 2025
196e9d7
Merge branch 'master' into master
LucasGrasso Nov 11, 2025
c908a73
run formatting
LucasGrasso Nov 11, 2025
399341d
Merge branch 'master' of https://github.com/LucasGrasso/ink
LucasGrasso Nov 11, 2025
a6f75b4
Merge branch 'master' into master
LucasGrasso Nov 24, 2025
06ab2c5
fix merge errors on changelog
LucasGrasso Nov 25, 2025
c50d31d
Merge branch 'use-ink:master' into master
LucasGrasso Nov 25, 2025
f6e3345
start refactoring block_hash
LucasGrasso Nov 25, 2025
a2cc91d
Merge branch 'master' of https://github.com/LucasGrasso/ink
LucasGrasso Nov 25, 2025
e15d33d
finish block_hash refatoring
LucasGrasso Nov 25, 2025
00c0d7f
use take_encoded to avoid allocation
LucasGrasso Nov 25, 2025
6971272
run formatting
LucasGrasso Nov 25, 2025
6c97c5e
Merge branch 'use-ink:master' into master
LucasGrasso Nov 29, 2025
e79f555
define trait and start impl
LucasGrasso Nov 30, 2025
857fedc
Merge branch 'data-copy-hostfns'
LucasGrasso Nov 30, 2025
1822f5c
implement `call_data_load` hostfn
LucasGrasso Nov 30, 2025
e0fe6cc
fix call_data_load docs
LucasGrasso Nov 30, 2025
612af80
implement set_storage and set_transient_storage
LucasGrasso Nov 30, 2025
1139945
implement get_storage and get_transient_storage
LucasGrasso Nov 30, 2025
87eec11
run formatting
LucasGrasso Nov 30, 2025
e9a079f
add entry to changelog
LucasGrasso Nov 30, 2025
695eaff
Merge branch 'master' into master
LucasGrasso Dec 18, 2025
8c94c02
Update CHANGELOG with new API implementations
LucasGrasso Dec 18, 2025
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[Unreleased]

### Added
- Implements the API for the `pallet-revive` host functions `set_storage_or_clear`, `get_storage_or_zero`, `call_data_load`, `return_data_copy` - [#2739](https://github.com/use-ink/ink/pull/2739)
- 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)
- Implement `From<ink::Address>` for "ink-as-dependency" contract refs - [#2728](https://github.com/use-ink/ink/pull/2728)

Expand Down
55 changes: 55 additions & 0 deletions crates/env/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,61 @@ pub fn block_author() -> Address {
<EnvInstance as OnInstance>::on_instance(TypedEnvBackend::block_author)
}

/// Returns the U256 value at the given offset from the input passed by the caller,
/// akin to the EVM [CALLDATALOAD](https://www.evm.codes/?fork=cancun#35) opcode.
///
/// # Note
///
/// - If `offset` is out of bounds, a value of zero will be returned.
/// - If `offset` is in bounds but there is not enough call data, the available data is
/// right-padded in order to fill a whole U256 value.
/// - The data returned is a little endian U256 integer value.
pub fn call_data_load(offset: u32) -> U256 {
<EnvInstance as OnInstance>::on_instance(|instance| {
TypedEnvBackend::call_data_load(instance, offset)
})
}

/// Sets the storage entry for a fixed 256-bit key with a fixed 256-bit value,
/// akin to the EVM [SSTORE](https://www.evm.codes/?fork=cancun#55) opcode.
///
/// If the provided value is all zeros then the key is cleared (i.e. deleted).
/// Returns the size (in bytes) of the pre-existing value at the specified key, if any.
pub fn set_storage(key: U256, value: &[u8; 32]) -> Option<u32> {
<EnvInstance as OnInstance>::on_instance(|instance| {
TypedEnvBackend::set_storage(instance, key, value)
})
}

/// Sets the transient storage entry for a fixed 256-bit key with a fixed 256-bit value,
/// akin to the EVM [TSTORE](https://www.evm.codes/?fork=cancun#5D) opcode.
///
/// If the provided value is all zeros then the key is cleared (i.e. deleted).
/// Returns the size (in bytes) of the pre-existing value at the specified key, if any.
pub fn set_transient_storage(key: U256, value: &[u8; 32]) -> Option<u32> {
<EnvInstance as OnInstance>::on_instance(|instance| {
TypedEnvBackend::set_transient_storage(instance, key, value)
})
}

/// Retrieves the storage entry for a fixed 256-bit key.
/// If the key does not exist, it returns 32 zero bytes.
/// This is akin to the EVM [SLOAD](https://www.evm.codes/?fork=cancun#54) opcode.
pub fn get_storage(key: U256) -> [u8; 32] {
<EnvInstance as OnInstance>::on_instance(|instance| {
TypedEnvBackend::get_storage(instance, key)
})
}

/// Retrieves the transient storage entry for a fixed 256-bit key.
/// If the key does not exist, it returns 32 zero bytes.
/// This is akin to the EVM [TLOAD](https://www.evm.codes/?fork=cancun#5C) opcode.
pub fn get_transient_storage(key: U256) -> [u8; 32] {
<EnvInstance as OnInstance>::on_instance(|instance| {
TypedEnvBackend::get_transient_storage(instance, key)
})
}

/// Returns the transferred value for the contract execution.
///
/// # Errors
Expand Down
51 changes: 51 additions & 0 deletions crates/env/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,57 @@ pub trait TypedEnvBackend: EnvBackend {
/// For more details visit: [`block_author`][`crate::block_author`]
fn block_author(&mut self) -> Address;

/// Returns the U256 value at given `offset` from the input passed by the caller.
/// This is akin to the EVM [CALLDATALOAD](https://www.evm.codes/?fork=cancun#35) opcode.
///
/// # Note
///
/// - If `offset` is out of bounds, a value of zero will be returned.
/// - If `offset` is in bounds but there is not enough call data, the available data
/// is right-padded in order to fill a whole U256 value.
/// - The data returned is a little endian U256 integer value.
///
/// For more details visit: [`call_data_load`][`crate::call_data_load`]
fn call_data_load(&mut self, offset: u32) -> U256;

/// Sets the storage entry for a fixed 256‑bit key with a fixed 256‑bit value.
/// If the provided 32‑byte value is all zeros then the key is cleared (i.e. deleted).
/// Returns the size (in bytes) of the pre‑existing value at the specified key, if
/// any. This is akin to the EVM [SSTORE](https://www.evm.codes/?fork=cancun#55) opcode.
///
/// # Note
///
/// For more details visit: [`set_storage`][`crate::set_storage`]
fn set_storage(&mut self, key: U256, value: &[u8; 32]) -> Option<u32>;

/// Sets the transient storage entry for a fixed 256‑bit key with a fixed 256‑bit
/// value. If the provided 32‑byte value is all zeros then the key is cleared
/// (i.e. deleted). Returns the size (in bytes) of the pre‑existing value at the
/// specified key, if any. This is akin to the EVM [TSTORE](https://www.evm.codes/?fork=cancun#5D) opcode.
///
/// # Note
///
/// For more details visit: [`set_transient_storage`][`crate::set_transient_storage`]
fn set_transient_storage(&mut self, key: U256, value: &[u8; 32]) -> Option<u32>;

/// Retrieves the storage entry for a fixed 256‑bit key.
/// If the key does not exist, it returns 32 zero bytes.
/// This is akin to the EVM [SLOAD](https://www.evm.codes/?fork=cancun#54) opcode.
///
/// # Note
///
/// For more details visit: [`get_storage`][`crate::get_storage`]
fn get_storage(&mut self, key: U256) -> [u8; 32];

/// Retrieves the transient storage entry for a fixed 256‑bit key.
/// If the key does not exist, it returns 32 zero bytes.
/// This is akin to the EVM [TLOAD](https://www.evm.codes/?fork=cancun#5C) opcode.
///
/// # Note
///
/// For more details visit: [`get_transient_storage`][`crate::get_transient_storage`]
fn get_transient_storage(&mut self, key: U256) -> [u8; 32];

/// Returns the transferred value for the contract execution.
///
/// # Note
Expand Down
20 changes: 20 additions & 0 deletions crates/env/src/engine/off_chain/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,26 @@ impl TypedEnvBackend for EnvInstance {
unimplemented!("not implemented, the off-chain environment will be removed");
}

fn call_data_load(&mut self, _offset: u32) -> U256 {
unimplemented!("not implemented, the off-chain environment will be removed");
}

fn set_storage(&mut self, _key: U256, _value: &[u8; 32]) -> Option<u32> {
unimplemented!("not implemented, the off-chain environment will be removed");
}

fn set_transient_storage(&mut self, _key: U256, _value: &[u8; 32]) -> Option<u32> {
unimplemented!("not implemented, the off-chain environment will be removed");
}

fn get_storage(&mut self, _key: U256) -> [u8; 32] {
unimplemented!("not implemented, the off-chain environment will be removed");
}

fn get_transient_storage(&mut self, _key: U256) -> [u8; 32] {
unimplemented!("not implemented, the off-chain environment will be removed");
}

fn transferred_value(&mut self) -> U256 {
self.get_property(Engine::value_transferred)
.unwrap_or_else(|error| {
Expand Down
37 changes: 37 additions & 0 deletions crates/env/src/engine/on_chain/pallet_revive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,7 @@ fn decode_bytes(input: &[u8], out: &mut [u8]) -> usize {
}

const STORAGE_FLAGS: StorageFlags = StorageFlags::empty();
const TRANSIENT_STORAGE_FLAGS: StorageFlags = StorageFlags::TRANSIENT;

impl EnvBackend for EnvInstance {
fn set_contract_storage<K, V>(&mut self, key: &K, value: &V) -> Option<u32>
Expand Down Expand Up @@ -1093,6 +1094,42 @@ impl TypedEnvBackend for EnvInstance {
h160.into()
}

fn call_data_load(&mut self, offset: u32) -> U256 {
let mut scope = self.scoped_buffer();
let u256: &mut [u8; 32] = scope.take(32).try_into().unwrap();

ext::call_data_load(u256, offset);
U256::from_le_bytes(*u256)
}

fn set_storage(&mut self, key: U256, value: &[u8; 32]) -> Option<u32> {
let mut scope = self.scoped_buffer();
let key: &mut [u8; 32] = scope.take_encoded(&key).try_into().unwrap();
ext::set_storage_or_clear(STORAGE_FLAGS, key, value)
}

fn set_transient_storage(&mut self, key: U256, value: &[u8; 32]) -> Option<u32> {
let mut scope = self.scoped_buffer();
let key: &mut [u8; 32] = scope.take_encoded(&key).try_into().unwrap();
ext::set_storage_or_clear(TRANSIENT_STORAGE_FLAGS, key, value)
}

fn get_storage(&mut self, key: U256) -> [u8; 32] {
let mut scope = self.scoped_buffer();
let key: &mut [u8; 32] = scope.take_encoded(&key).try_into().unwrap();
let value: &mut [u8; 32] = scope.take(32).try_into().unwrap();
ext::get_storage_or_zero(STORAGE_FLAGS, key, value);
*value
}

fn get_transient_storage(&mut self, key: U256) -> [u8; 32] {
let mut scope = self.scoped_buffer();
let key: &mut [u8; 32] = scope.take_encoded(&key).try_into().unwrap();
let value: &mut [u8; 32] = scope.take(32).try_into().unwrap();
ext::get_storage_or_zero(TRANSIENT_STORAGE_FLAGS, key, value);
*value
}

fn transferred_value(&mut self) -> U256 {
let mut scope = self.scoped_buffer();
let u256: &mut [u8; 32] = scope.take(32).try_into().unwrap();
Expand Down
182 changes: 182 additions & 0 deletions crates/ink/src/env_access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,188 @@ where
ink_env::return_data_size()
}

/// Returns the U256 value at the given offset from the input passed by the caller,
/// akin to the EVM [CALLDATALOAD](https://www.evm.codes/?fork=cancun#35) 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_call_data_at_offset(&self, offset: u32) -> U256 {
/// self.env().call_data_load(offset)
/// }
/// }
/// }
/// ```
///
/// # Note
///
/// For more details visit: [`ink_env::call_data_load`]
pub fn call_data_load(self, offset: u32) -> U256 {
ink_env::call_data_load(offset)
}

/// Sets the storage entry for a fixed 256-bit key with a fixed 256-bit value.
/// If the provided 32-byte value is all zeros then the key is cleared (i.e. deleted).
/// Returns the size (in bytes) of the pre-existing value at the specified key, if
/// any. This is akin to the EVM [SSTORE](https://www.evm.codes/?fork=cancun#55) 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 store_value(&self) {
/// let key = U256::from(42u32);
/// let value = [0xDEu8; 32];
/// self.env().set_storage(key, &value);
/// }
/// }
/// }
/// ```
///
/// # Note
///
/// For more details visit: [`ink_env::set_storage`]
pub fn set_storage(self, key: U256, value: &[u8; 32]) -> Option<u32> {
ink_env::set_storage(key, value)
}

/// Sets the transient storage entry for a fixed 256-bit key with a fixed 256-bit
/// value. If the provided 32-byte value is all zeros then the key is cleared
/// (i.e. deleted). Returns the size (in bytes) of the pre-existing value at the
/// specified key, if any. This is akin to the EVM [TSTORE](https://www.evm.codes/?fork=cancun#5D) 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 store_transient(&self) {
/// let key = U256::from(42u32);
/// let value = [0xABu8; 32];
/// self.env().set_transient_storage(key, &value);
/// }
/// }
/// }
/// ```
///
/// # Note
///
/// For more details visit: [`ink_env::set_transient_storage`]
pub fn set_transient_storage(self, key: U256, value: &[u8; 32]) -> Option<u32> {
ink_env::set_transient_storage(key, value)
}

/// Retrieves the storage entry for a fixed 256-bit key.
/// If the key does not exist, it returns 32 zero bytes.
/// This is akin to the EVM [SLOAD](https://www.evm.codes/?fork=cancun#54) 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 load_value(&self) -> [u8; 32] {
/// let key = U256::from(42u32);
/// self.env().get_storage(key)
/// }
/// }
/// }
/// ```
///
/// # Note
///
/// For more details visit: [`ink_env::get_storage`]
pub fn get_storage(self, key: U256) -> [u8; 32] {
ink_env::get_storage(key)
}

/// Retrieves the transient storage entry for a fixed 256-bit key.
/// If the key does not exist, it returns 32 zero bytes.
/// This is akin to the EVM [TLOAD](https://www.evm.codes/?fork=cancun#5C) 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 load_transient(&self) -> [u8; 32] {
/// let key = U256::from(42u32);
/// self.env().get_transient_storage(key)
/// }
/// }
/// }
/// ```
///
/// # Note
///
/// For more details visit: [`ink_env::get_transient_storage`]
pub fn get_transient_storage(self, key: U256) -> [u8; 32] {
ink_env::get_transient_storage(key)
}

/// 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.
///
Expand Down
Loading
Loading