Skip to content

Commit

Permalink
the gas limit API
Browse files Browse the repository at this point in the history
Signed-off-by: Cyrill Leutwiler <[email protected]>
  • Loading branch information
xermicus committed Dec 17, 2024
1 parent 5b04b45 commit 9113580
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
use common::input;
use uapi::{HostFn, HostFnImpl as api, StorageFlags};

static BUFFER: [u8; 512] = [0u8; 512];
static BUFFER: [u8; 384] = [0u8; 384];

#[no_mangle]
#[polkavm_derive::polkavm_export]
Expand Down
34 changes: 34 additions & 0 deletions substrate/frame/revive/fixtures/contracts/gas_limit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// 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.

//! Returns the block ref_time limit back to the caller.
#![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() {}

#[no_mangle]
#[polkavm_derive::polkavm_export]
pub extern "C" fn call() {
api::return_value(ReturnFlags::empty(), &api::gas_limit().to_le_bytes());
}
11 changes: 11 additions & 0 deletions substrate/frame/revive/src/benchmarking/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,17 @@ mod benchmarks {
assert_eq!(U256::from_little_endian(&memory[..]), U256::from(128));
}

#[benchmark(pov_mode = Measured)]
fn seal_gas_limit() {
build_runtime!(runtime, memory: []);
let result;
#[block]
{
result = runtime.bench_gas_limit(&mut memory);
}
assert_eq!(result.unwrap(), T::BlockWeights::get().max_block.ref_time());
}

#[benchmark(pov_mode = Measured)]
fn seal_block_number() {
build_runtime!(runtime, memory: [[0u8;32], ]);
Expand Down
2 changes: 1 addition & 1 deletion substrate/frame/revive/src/limits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub const NUM_EVENT_TOPICS: u32 = 4;
pub const DELEGATE_DEPENDENCIES: u32 = 32;

/// Maximum size of events (including topics) and storage values.
pub const PAYLOAD_BYTES: u32 = 512;
pub const PAYLOAD_BYTES: u32 = 384;

/// The maximum size of the transient storage in bytes.
///
Expand Down
26 changes: 24 additions & 2 deletions substrate/frame/revive/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,14 +374,15 @@ impl RegisteredChainExtension<Test> for TempStorageExtension {
parameter_types! {
pub BlockWeights: frame_system::limits::BlockWeights =
frame_system::limits::BlockWeights::simple_max(
Weight::from_parts(2u64 * WEIGHT_REF_TIME_PER_SECOND, u64::MAX),
Weight::from_parts(2 * WEIGHT_REF_TIME_PER_SECOND, u64::MAX),
);
pub static ExistentialDeposit: u64 = 1;
}

#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
impl frame_system::Config for Test {
type Block = Block;
type BlockWeights = BlockWeights;
type AccountId = AccountId32;
type Lookup = IdentityLookup<Self::AccountId>;
type AccountData = pallet_balances::AccountData<u64>;
Expand Down Expand Up @@ -3483,7 +3484,7 @@ fn deposit_limit_in_nested_calls() {
// Require more than the sender's balance.
// Limit the sub call to little balance so it should fail in there
let ret = builder::bare_call(addr_caller)
.data((512u32, &addr_callee, U256::from(1u64)).encode())
.data((384u32, &addr_callee, U256::from(1u64)).encode())
.build_and_unwrap_result();
assert_return_code!(ret, RuntimeReturnCode::OutOfResources);

Expand Down Expand Up @@ -4818,6 +4819,27 @@ fn skip_transfer_works() {
});
}

#[test]
fn gas_limit_api_works() {
let (code, _) = compile_module("gas_limit").unwrap();

ExtBuilder::default().existential_deposit(100).build().execute_with(|| {
let _ = <Test as Config>::Currency::set_balance(&ALICE, 1_000_000);

// Create fixture: Constructor does nothing
let Contract { addr, .. } =
builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract();

// Call the contract: It echoes back the value returned by the gas limit API.
let received = builder::bare_call(addr).build_and_unwrap_result();
assert_eq!(received.flags, ReturnFlags::empty());
assert_eq!(
u64::from_le_bytes(received.data[..].try_into().unwrap()),
<Test as frame_system::Config>::BlockWeights::get().max_block.ref_time()
);
});
}

#[test]
fn unknown_syscall_rejected() {
let (code, _) = compile_module("unknown_syscall").unwrap();
Expand Down
11 changes: 11 additions & 0 deletions substrate/frame/revive/src/wasm/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,8 @@ pub enum RuntimeCosts {
BlockHash,
/// Weight of calling `seal_now`.
Now,
/// Weight of calling `seal_gas_limit`.
GasLimit,
/// Weight of calling `seal_weight_to_fee`.
WeightToFee,
/// Weight of calling `seal_terminate`, passing the number of locked dependencies.
Expand Down Expand Up @@ -452,6 +454,7 @@ impl<T: Config> Token<T> for RuntimeCosts {
BlockNumber => T::WeightInfo::seal_block_number(),
BlockHash => T::WeightInfo::seal_block_hash(),
Now => T::WeightInfo::seal_now(),
GasLimit => T::WeightInfo::seal_gas_limit(),
WeightToFee => T::WeightInfo::seal_weight_to_fee(),
Terminate(locked_dependencies) => T::WeightInfo::seal_terminate(locked_dependencies),
DepositEvent { num_topic, len } => T::WeightInfo::seal_deposit_event(num_topic, len),
Expand Down Expand Up @@ -1508,6 +1511,14 @@ pub mod env {
)?)
}

/// Returns the block ref_time limit.
/// See [`pallet_revive_uapi::HostFn::gas_limit`].
#[stable]
fn gas_limit(&mut self, memory: &mut M) -> Result<u64, TrapReason> {
self.charge_gas(RuntimeCosts::GasLimit)?;
Ok(<E::T as frame_system::Config>::BlockWeights::get().max_block.ref_time())
}

/// Stores the value transferred along with this call/instantiate into the supplied buffer.
/// See [`pallet_revive_uapi::HostFn::value_transferred`].
#[stable]
Expand Down
15 changes: 15 additions & 0 deletions substrate/frame/revive/src/weights.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions substrate/frame/revive/uapi/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,9 @@ pub trait HostFn: private::Sealed {
/// - `output`: A reference to the output data buffer to write the timestamp.
fn now(output: &mut [u8; 32]);

/// Returns the block ref_time limit.
fn gas_limit() -> u64;

/// Cease contract execution and save a data buffer as a result of the execution.
///
/// This function never returns as it stops execution of the caller.
Expand Down
5 changes: 5 additions & 0 deletions substrate/frame/revive/uapi/src/host/riscv64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ mod sys {
pub fn chain_id(out_ptr: *mut u8);
pub fn value_transferred(out_ptr: *mut u8);
pub fn now(out_ptr: *mut u8);
pub fn gas_limit() -> u64;
pub fn minimum_balance(out_ptr: *mut u8);
pub fn deposit_event(
topics_ptr: *const [u8; 32],
Expand Down Expand Up @@ -393,6 +394,10 @@ impl HostFn for HostFnImpl {
unsafe { sys::call_data_load(out_ptr.as_mut_ptr(), offset) };
}

fn gas_limit() -> u64 {
unsafe { sys::gas_limit() }
}

fn return_value(flags: ReturnFlags, return_value: &[u8]) -> ! {
unsafe { sys::seal_return(flags.bits(), return_value.as_ptr(), return_value.len() as u32) }
panic!("seal_return does not return");
Expand Down

0 comments on commit 9113580

Please sign in to comment.