Skip to content
Snippets Groups Projects
Unverified Commit 6ad74885 authored by Cyrill Leutwiler's avatar Cyrill Leutwiler Committed by GitHub
Browse files

[pallet-revive] implement the ref_time_left API (#6908)


This PR implements the ref_time_left API method. Solidity knows only a
single "gas" dimension; Solidity contracts will use this to query the
gas left.

---------

Signed-off-by: default avatarxermicus <cyrill@parity.io>
Signed-off-by: default avatarCyrill Leutwiler <bigcyrill@hotmail.com>
Co-authored-by: command-bot <>
parent 9da3394c
No related merge requests found
Pipeline #509938 waiting for manual action with stages
in 31 minutes and 34 seconds
title: '[pallet-revive] implement the ref_time_left API'
doc:
- audience: Runtime Dev
description: This PR implements the ref_time_left API method. Solidity knows only
a single "gas" dimension; Solidity contracts will use this to query the gas left.
crates:
- name: pallet-revive-fixtures
bump: minor
- name: pallet-revive
bump: minor
- name: pallet-revive-uapi
bump: minor
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#![no_std]
#![no_main]
extern crate common;
use uapi::{HostFn, HostFnImpl as api, ReturnFlags};
#[no_mangle]
#[polkavm_derive::polkavm_export]
pub extern "C" fn deploy() {
assert!(api::ref_time_left() > api::ref_time_left());
}
#[no_mangle]
#[polkavm_derive::polkavm_export]
pub extern "C" fn call() {
api::return_value(ReturnFlags::empty(), &api::ref_time_left().to_le_bytes());
}
...@@ -671,6 +671,18 @@ mod benchmarks { ...@@ -671,6 +671,18 @@ mod benchmarks {
); );
} }
#[benchmark(pov_mode = Measured)]
fn seal_ref_time_left() {
build_runtime!(runtime, memory: [vec![], ]);
let result;
#[block]
{
result = runtime.bench_ref_time_left(memory.as_mut_slice());
}
assert_eq!(result.unwrap(), runtime.ext().gas_meter().gas_left().ref_time());
}
#[benchmark(pov_mode = Measured)] #[benchmark(pov_mode = Measured)]
fn seal_balance() { fn seal_balance() {
build_runtime!(runtime, memory: [[0u8;32], ]); build_runtime!(runtime, memory: [[0u8;32], ]);
......
...@@ -1874,6 +1874,27 @@ fn lazy_batch_removal_works() { ...@@ -1874,6 +1874,27 @@ fn lazy_batch_removal_works() {
}); });
} }
#[test]
fn ref_time_left_api_works() {
let (code, _) = compile_module("ref_time_left").unwrap();
ExtBuilder::default().existential_deposit(100).build().execute_with(|| {
let _ = <Test as Config>::Currency::set_balance(&ALICE, 1_000_000);
// Create fixture: Constructor calls ref_time_left twice and asserts it to decrease
let Contract { addr, .. } =
builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract();
// Call the contract: It echoes back the ref_time returned by the ref_time_left API.
let received = builder::bare_call(addr).build_and_unwrap_result();
assert_eq!(received.flags, ReturnFlags::empty());
let returned_value = u64::from_le_bytes(received.data[..8].try_into().unwrap());
assert!(returned_value > 0);
assert!(returned_value < GAS_LIMIT.ref_time());
});
}
#[test] #[test]
fn lazy_removal_partial_remove_works() { fn lazy_removal_partial_remove_works() {
let (code, _hash) = compile_module("self_destruct").unwrap(); let (code, _hash) = compile_module("self_destruct").unwrap();
......
...@@ -306,6 +306,8 @@ pub enum RuntimeCosts { ...@@ -306,6 +306,8 @@ pub enum RuntimeCosts {
CallerIsRoot, CallerIsRoot,
/// Weight of calling `seal_address`. /// Weight of calling `seal_address`.
Address, Address,
/// Weight of calling `seal_ref_time_left`.
RefTimeLeft,
/// Weight of calling `seal_weight_left`. /// Weight of calling `seal_weight_left`.
WeightLeft, WeightLeft,
/// Weight of calling `seal_balance`. /// Weight of calling `seal_balance`.
...@@ -462,6 +464,7 @@ impl<T: Config> Token<T> for RuntimeCosts { ...@@ -462,6 +464,7 @@ impl<T: Config> Token<T> for RuntimeCosts {
CallerIsOrigin => T::WeightInfo::seal_caller_is_origin(), CallerIsOrigin => T::WeightInfo::seal_caller_is_origin(),
CallerIsRoot => T::WeightInfo::seal_caller_is_root(), CallerIsRoot => T::WeightInfo::seal_caller_is_root(),
Address => T::WeightInfo::seal_address(), Address => T::WeightInfo::seal_address(),
RefTimeLeft => T::WeightInfo::seal_ref_time_left(),
WeightLeft => T::WeightInfo::seal_weight_left(), WeightLeft => T::WeightInfo::seal_weight_left(),
Balance => T::WeightInfo::seal_balance(), Balance => T::WeightInfo::seal_balance(),
BalanceOf => T::WeightInfo::seal_balance_of(), BalanceOf => T::WeightInfo::seal_balance_of(),
...@@ -1701,6 +1704,14 @@ pub mod env { ...@@ -1701,6 +1704,14 @@ pub mod env {
Ok(result?) Ok(result?)
} }
/// Returns the amount of ref_time left.
/// See [`pallet_revive_uapi::HostFn::ref_time_left`].
#[stable]
fn ref_time_left(&mut self, memory: &mut M) -> Result<u64, TrapReason> {
self.charge_gas(RuntimeCosts::RefTimeLeft)?;
Ok(self.ext.gas_meter().gas_left().ref_time())
}
/// Call into the chain extension provided by the chain if any. /// Call into the chain extension provided by the chain if any.
/// See [`pallet_revive_uapi::HostFn::call_chain_extension`]. /// See [`pallet_revive_uapi::HostFn::call_chain_extension`].
fn call_chain_extension( fn call_chain_extension(
......
This diff is collapsed.
...@@ -398,6 +398,9 @@ pub trait HostFn: private::Sealed { ...@@ -398,6 +398,9 @@ pub trait HostFn: private::Sealed {
/// - `offset`: Byte offset into the returned data /// - `offset`: Byte offset into the returned data
fn return_data_copy(output: &mut &mut [u8], offset: u32); fn return_data_copy(output: &mut &mut [u8], offset: u32);
/// Returns the amount of ref_time left.
fn ref_time_left() -> u64;
/// Stores the current block number of the current contract into the supplied buffer. /// Stores the current block number of the current contract into the supplied buffer.
/// ///
/// # Parameters /// # Parameters
......
...@@ -76,6 +76,7 @@ mod sys { ...@@ -76,6 +76,7 @@ mod sys {
pub fn address(out_ptr: *mut u8); pub fn address(out_ptr: *mut u8);
pub fn weight_to_fee(ref_time: u64, proof_size: u64, out_ptr: *mut u8); pub fn weight_to_fee(ref_time: u64, proof_size: u64, out_ptr: *mut u8);
pub fn weight_left(out_ptr: *mut u8, out_len_ptr: *mut u32); pub fn weight_left(out_ptr: *mut u8, out_len_ptr: *mut u32);
pub fn ref_time_left() -> u64;
pub fn get_immutable_data(out_ptr: *mut u8, out_len_ptr: *mut u32); pub fn get_immutable_data(out_ptr: *mut u8, out_len_ptr: *mut u32);
pub fn set_immutable_data(ptr: *const u8, len: u32); pub fn set_immutable_data(ptr: *const u8, len: u32);
pub fn balance(out_ptr: *mut u8); pub fn balance(out_ptr: *mut u8);
...@@ -440,6 +441,10 @@ impl HostFn for HostFnImpl { ...@@ -440,6 +441,10 @@ impl HostFn for HostFnImpl {
extract_from_slice(output, output_len as usize); extract_from_slice(output, output_len as usize);
} }
fn ref_time_left() -> u64 {
unsafe { sys::ref_time_left() }
}
#[cfg(feature = "unstable-api")] #[cfg(feature = "unstable-api")]
fn block_hash(block_number_ptr: &[u8; 32], output: &mut [u8; 32]) { fn block_hash(block_number_ptr: &[u8; 32], output: &mut [u8; 32]) {
unsafe { sys::block_hash(block_number_ptr.as_ptr(), output.as_mut_ptr()) }; unsafe { sys::block_hash(block_number_ptr.as_ptr(), output.as_mut_ptr()) };
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment