ink icon indicating copy to clipboard operation
ink copied to clipboard

Implement missing host functions

Open cmichi opened this issue 3 months ago • 7 comments

pallet-revive has added a number of host functions that we don't support in ink! yet. I've just compiled the list and am creating this tracking issue for them.

  • [ ] fn get_immutable_data(output: &mut &mut [u8]);
  • [ ] fn set_immutable_data(data: &[u8]);
  • [x] fn balance_of(addr: &[u8; 20], output: &mut [u8; 32]);
  • [x] fn chain_id(output: &mut [u8; 32]);
  • [x] fn gas_price() -> u64;
  • [x] fn base_fee(output: &mut [u8; 32]);
  • [x] fn call_data_size() -> u64;
  • [x] fn origin(output: &mut [u8; 20]);
  • [x] fn code_size(addr: &[u8; 20]) -> u64;
  • [ ] fn call_data_load(output: &mut [u8; 32], offset: u32);
  • [x] fn gas_limit() -> u64;
  • [ ] fn set_storage_or_clear(flags: StorageFlags, key: &[u8; 32], value: &[u8; 32]) -> Option<u32>;
  • [ ] fn get_storage_or_zero(flags: StorageFlags, key: &[u8; 32], output: &mut [u8; 32]);
  • [x] fn return_data_size() -> u64;
  • [ ] fn return_data_copy(output: &mut &mut [u8], offset: u32);
  • [x] fn ref_time_left() -> u64;
  • [x] fn block_author(output: &mut [u8; 20]);
  • [x] fn block_hash(block_number: &[u8; 32], output: &mut [u8; 32]);

Having the host functions supported is not a requirement for an ink! v6 release. Some are easy to implement, while others (e.g. immutable data) require more thought about the design.

cmichi avatar Sep 23 '25 09:09 cmichi

@LucasGrasso This is a tracking issue, so you don't have to implement all of these functions at all. Let's just start with a single one: gas_limit. This is a host function that pallet-revive exposes to us, it already exists there. It just doesn't exist in ink! yet.

You can take a look at the function transferred_value and how we've implemented it (just full-text search the codebase). It's a similar function, it just gets some value from pallet-revive and returns it to the smart contract.

You'll find a number of places where transferred_value is used and you can implement gas_limit by taking the transferred_value code as a blueprint.

We use transferred_value in a bunch of contract examples (those are in integration-tests). For gas_limit it's best if you add a new contract example integration-tests/internal/gas. This contract should have a contract function that uses gas_limit + an E2E test that tests this contract function.

Feel free to ask questions in case you have questions!

Edit: Some pointers

  • https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/revive/src/vm/pvm/env.rs#L625-L631 This is where pallet-revive defines gas_limit.
  • https://github.com/use-ink/ink/blob/master/crates/env/src/engine/on_chain/pallet_revive.rs#L890-L896 This is how transferred_value calls pallet-revive. There are traits and trait implementations that call this function, hence you're best of doing a full-text search.

cmichi avatar Oct 23 '25 16:10 cmichi

Thanks for the introduction and help. How should one implement the hostfn in the off-chain engine? I suppose that the gas limit value should be stored in the Engine Database as one can not access revive? How are those db values configured?

LucasGrasso avatar Oct 24 '25 04:10 LucasGrasso

@LucasGrasso We are in the process of removing the off-chain testing environment. Hence you can just add the method there, but panic inside of it.

cmichi avatar Oct 24 '25 06:10 cmichi

  • gas_limit should be marked as completed.
  • I will continue with the implementation of the rest of the 0-ary functions fn gas_price() -> u64 fn call_data_size() -> u64 fn return_data_size() -> u64 fn ref_time_left() -> u64

LucasGrasso avatar Oct 29 '25 02:10 LucasGrasso

I will continue implementing the getters akin to EVM opcodes and block_author.

  • fn chain_id(output: &mut [u8; 32]);
  • fn balance_of(addr: &[u8; 20], output: &mut [u8; 32]);
  • fn base_fee(output: &mut [u8; 32]);
  • fn origin(output: &mut [u8; 20]);
  • fn code_size(addr: &[u8; 20]) -> u64;
  • fn block_hash(block_number: &[u8; 32], output: &mut [u8; 32]);
  • fn block_author(output: &mut [u8; 20]);

Please mark gas_price, call_data_size, return_data_size, ref_time_left as completed.

LucasGrasso avatar Nov 07 '25 01:11 LucasGrasso

@LucasGrasso That's great! I've marked the others as ☑️.

cmichi avatar Nov 08 '25 07:11 cmichi

Now that #2719 is merged, please mark chain_id, balance_of, base_fee, origin, code_size, block_hash, block_author as ☑️.

Will continue implementing the two "easy" hostnfs(return_data_copy and call_data_load) and the storage ones. Would you rather have two separate storage getters / setters based on the flag (Transient Storage or not)? That way we can be more assimilated to the SSTORE-SLOAD and TSTORE-TLOAD opcodes.

To begin thinking about the inmutable data hostfns: what are some designs considerations to take into account?

LucasGrasso avatar Nov 26 '25 14:11 LucasGrasso