Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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 Cargo.lock

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

23 changes: 23 additions & 0 deletions prdoc/pr_10018.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
title: 'pallet_revive: Change EVM call opcodes to respect the gas limit passed'
doc:
- audience: Runtime Dev
description: |-
So far the EVM family of call opcodes did ignore the `gas` argument passed to them. The consequence was that we were not able to limit the resource usage of sub contract calls. This PR changes that. **Gas is now fully functional on the EVM backend.**

The resources of any sub contract call are now effectively limited. This is both true for `Weight` and storage deposit. The algorithm works in a way that if you pass `x%` of the current `GAS` the the `CALL` opcode the sub call will have `x%` of currently available `Weight` and storage deposit available. This allows the caller to always make sure to execute code after retuning from a sub call.

### Changes to the gas meter

I needed to change the gas meter to track `gas_consumed` instead of `gas_left`. Otherwise it is not possible to know the total amount of gas spent for a call stack that is not unwinded, yet.

### Followup
- Implement a new PVM syscall that takes the new unified gas instead of `Weight` and storage deposit limit
- Change resolc to use this new syscall
- Enable the test added here to run on resolc
crates:
- name: pallet-revive
bump: major
- name: pallet-revive-eth-rpc
bump: major
- name: pallet-revive-fixtures
bump: major
1 change: 1 addition & 0 deletions substrate/frame/revive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ subxt-signer = { workspace = true, optional = true, features = ["unstable-eth"]
alloy-consensus = { workspace = true, default-features = true }
array-bytes = { workspace = true, default-features = true }
assert_matches = { workspace = true }
itertools = { workspace = true }
pretty_assertions = { workspace = true }
secp256k1 = { workspace = true, features = ["recovery"] }
serde_json = { workspace = true }
Expand Down
4 changes: 4 additions & 0 deletions substrate/frame/revive/fixtures/contracts/Callee.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,8 @@ contract Callee {
stop()
}
}

function consumeAllReftime() external {
while (true) {}
}
}
20 changes: 20 additions & 0 deletions substrate/frame/revive/fixtures/contracts/Caller.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ contract ChildRevert {
}

contract Caller {
uint256 public data;

function normal(address _callee, uint64 _value, bytes memory _data, uint64 _gas)
external
returns (bool success, bytes memory output)
Expand Down Expand Up @@ -65,4 +67,22 @@ contract Caller {
}
}
}

function callPartialGas(address _callee, bytes memory _data, uint64 _gasDivisor, uint8 _callType)
external
returns (bool success)
{
uint256 gas = gasleft() / _gasDivisor;
bytes memory output;
if (_callType == 0) {
(success, output) = _callee.call{gas: gas }(_data);
} else if (_callType == 1) {
(success, output) = _callee.staticcall{gas: gas }(_data);
} else if (_callType == 2) {
(success, output) = _callee.delegatecall{gas: gas }(_data);
} else {
revert("unknown call type");
}
data = 42;
}
}
38 changes: 10 additions & 28 deletions substrate/frame/revive/src/evm/fees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ pub trait InfoT<T: Config>: seal::Sealed {
}

/// Convert a weight to an unadjusted fee.
fn weight_to_fee(_weight: &Weight, _combinator: Combinator) -> BalanceOf<T> {
fn weight_to_fee(_weight: &Weight) -> BalanceOf<T> {
Zero::zero()
}

Expand Down Expand Up @@ -168,14 +168,6 @@ pub trait InfoT<T: Config>: seal::Sealed {
}
}

/// Which function to use in order to combine `ref_time` and `proof_size` to a fee.
pub enum Combinator {
/// Minimum function.
Min,
/// Maximum function.
Max,
}

impl<const P: u128, const Q: u128, T: Config> BlockRatioFee<P, Q, T> {
const REF_TIME_TO_FEE: FixedU128 = {
assert!(P > 0 && Q > 0);
Expand All @@ -189,26 +181,17 @@ impl<const P: u128, const Q: u128, T: Config> BlockRatioFee<P, Q, T> {
FixedU128::from_rational(max_weight.ref_time().into(), max_weight.proof_size().into());
Self::REF_TIME_TO_FEE.saturating_mul(ratio)
}

/// Calculate the fee for a weight.
fn weight_to_fee(weight: &Weight, combinator: Combinator) -> BalanceOf<T> {
let ref_time_fee = Self::REF_TIME_TO_FEE
.saturating_mul_int(BalanceOf::<T>::saturated_from(weight.ref_time()));
let proof_size_fee = Self::proof_size_to_fee()
.saturating_mul_int(BalanceOf::<T>::saturated_from(weight.proof_size()));

match combinator {
Combinator::Max => ref_time_fee.max(proof_size_fee),
Combinator::Min => ref_time_fee.min(proof_size_fee),
}
}
}

impl<const P: u128, const Q: u128, T: Config> WeightToFee for BlockRatioFee<P, Q, T> {
type Balance = BalanceOf<T>;

fn weight_to_fee(weight: &Weight) -> Self::Balance {
Self::weight_to_fee(weight, Combinator::Max)
let ref_time_fee = Self::REF_TIME_TO_FEE
.saturating_mul_int(BalanceOf::<T>::saturated_from(weight.ref_time()));
let proof_size_fee = Self::proof_size_to_fee()
.saturating_mul_int(BalanceOf::<T>::saturated_from(weight.proof_size()));
ref_time_fee.max(proof_size_fee)
}
}

Expand Down Expand Up @@ -254,8 +237,8 @@ where
/// Calculate the fee using the weight instead of a dispatch info.
fn tx_fee_from_weight(encoded_len: u32, weight: &Weight) -> BalanceOf<E::Config> {
let fixed_fee = Self::fixed_fee(encoded_len);
let weight_fee = Self::next_fee_multiplier()
.saturating_mul_int(Self::weight_to_fee(weight, Combinator::Max));
let weight_fee =
Self::next_fee_multiplier().saturating_mul_int(Self::weight_to_fee(weight));
fixed_fee.saturating_add(weight_fee)
}

Expand All @@ -264,7 +247,6 @@ where
&<E::Config as frame_system::Config>::BlockWeights::get()
.get(DispatchClass::Normal)
.base_extrinsic,
Combinator::Max,
)
.saturating_add(Self::length_to_fee(encoded_len))
}
Expand Down Expand Up @@ -322,8 +304,8 @@ where
uxt.encoded_size() as u32
}

fn weight_to_fee(weight: &Weight, combinator: Combinator) -> BalanceOf<E::Config> {
<E::Config as TxConfig>::WeightToFee::weight_to_fee(&weight, combinator)
fn weight_to_fee(weight: &Weight) -> BalanceOf<E::Config> {
<E::Config as TxConfig>::WeightToFee::weight_to_fee(weight)
}

/// Convert an unadjusted fee back to a weight.
Expand Down
Loading
Loading