Skip to content

Commit

Permalink
Fix Native to Eth conversion in EVM gas fee estimation
Browse files Browse the repository at this point in the history
  • Loading branch information
pgherveou committed Jan 21, 2025
1 parent c0c0632 commit 93dd546
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2189,6 +2189,12 @@ impl_runtime_apis! {
Revive::evm_balance(&address)
}

fn block_gas_limit() -> U256 {
let weight = RuntimeBlockWeights::get().max_block;
let fee = TransactionPayment::weight_to_fee(weight);
Revive::evm_fee_to_gas(fee)
}

fn nonce(address: H160) -> Nonce {
let account = <Runtime as pallet_revive::Config>::AddressMapper::to_account_id(&address);
System::account_nonce(account)
Expand Down
6 changes: 6 additions & 0 deletions substrate/bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3301,6 +3301,12 @@ impl_runtime_apis! {
Revive::evm_balance(&address)
}

fn block_gas_limit() -> U256 {
let weight = RuntimeBlockWeights::get().max_block;
let fee = TransactionPayment::weight_to_fee(weight);
Revive::evm_fee_to_gas(fee)
}

fn nonce(address: H160) -> Nonce {
let account = <Runtime as pallet_revive::Config>::AddressMapper::to_account_id(&address);
System::account_nonce(account)
Expand Down
Binary file modified substrate/frame/revive/rpc/revive_chain.metadata
Binary file not shown.
17 changes: 6 additions & 11 deletions substrate/frame/revive/rpc/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
//! and is used by the rpc server to query and send transactions to the substrate chain.
use crate::{
extract_receipts_from_block,
runtime::gas_from_fee,
subxt_client::{
revive::calls::types::EthTransact, runtime_types::pallet_revive::storage::ContractInfo,
},
Expand Down Expand Up @@ -649,8 +648,7 @@ impl Client {
hydrated_transactions: bool,
) -> Result<Block, ClientError> {
let runtime_api = self.api.runtime_api().at(block.hash());
let max_fee = Self::weight_to_fee(&runtime_api, self.max_block_weight()).await?;
let gas_limit = gas_from_fee(max_fee);
let gas_limit = Self::block_gas_limit(&runtime_api).await?;

let header = block.header();
let timestamp = extract_block_timestamp(&block).await.unwrap_or_default();
Expand Down Expand Up @@ -695,16 +693,13 @@ impl Client {
}

/// Convert a weight to a fee.
async fn weight_to_fee(
async fn block_gas_limit(
runtime_api: &subxt::runtime_api::RuntimeApi<SrcChainConfig, OnlineClient<SrcChainConfig>>,
weight: Weight,
) -> Result<Balance, ClientError> {
let payload = subxt_client::apis()
.transaction_payment_api()
.query_weight_to_fee(weight.into());
) -> Result<U256, ClientError> {
let payload = subxt_client::apis().revive_api().block_gas_limit();

let fee = runtime_api.call(payload).await?;
Ok(fee)
let gas_limit = runtime_api.call(payload).await?;
Ok(*gas_limit)
}

/// Get the chain ID.
Expand Down
46 changes: 9 additions & 37 deletions substrate/frame/revive/src/evm/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::{
api::{GenericTransaction, TransactionSigned},
GasEncoder,
},
AccountIdOf, AddressMapper, BalanceOf, Config, MomentOf, Weight, LOG_TARGET,
AccountIdOf, AddressMapper, BalanceOf, Config, MomentOf, Pallet, LOG_TARGET,
};
use alloc::vec::Vec;
use codec::{Decode, Encode};
Expand All @@ -34,8 +34,8 @@ use sp_core::{Get, H256, U256};
use sp_runtime::{
generic::{self, CheckedExtrinsic, ExtrinsicFormat},
traits::{
self, AtLeast32BitUnsigned, Checkable, Dispatchable, ExtrinsicLike, ExtrinsicMetadata,
IdentifyAccount, Member, TransactionExtension,
self, Checkable, Dispatchable, ExtrinsicLike, ExtrinsicMetadata, IdentifyAccount, Member,
TransactionExtension,
},
transaction_validity::{InvalidTransaction, TransactionValidityError},
OpaqueExtrinsic, RuntimeDebug, Saturating,
Expand All @@ -56,34 +56,6 @@ type CallOf<T> = <T as frame_system::Config>::RuntimeCall;
/// - Not too low, enabling users to adjust the gas price to define a tip.
pub const GAS_PRICE: u32 = 1_000u32;

/// Convert a `Balance` into a gas value, using the fixed `GAS_PRICE`.
/// The gas is calculated as `balance / GAS_PRICE`, rounded up to the nearest integer.
pub fn gas_from_fee<Balance>(fee: Balance) -> U256
where
u32: Into<Balance>,
Balance: Into<U256> + AtLeast32BitUnsigned + Copy,
{
let gas_price = GAS_PRICE.into();
let remainder = fee % gas_price;
if remainder.is_zero() {
(fee / gas_price).into()
} else {
(fee.saturating_add(gas_price) / gas_price).into()
}
}

/// Convert a `Weight` into a gas value, using the fixed `GAS_PRICE`.
/// and the `Config::WeightPrice` to compute the fee.
/// The gas is calculated as `fee / GAS_PRICE`, rounded up to the nearest integer.
pub fn gas_from_weight<T: Config>(weight: Weight) -> U256
where
BalanceOf<T>: Into<U256>,
{
use sp_runtime::traits::Convert;
let fee: BalanceOf<T> = T::WeightPrice::convert(weight);
gas_from_fee(fee)
}

/// Wraps [`generic::UncheckedExtrinsic`] to support checking unsigned
/// [`crate::Call::eth_transact`] extrinsic.
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
Expand Down Expand Up @@ -393,17 +365,17 @@ pub trait EthExtra {
let nonce = nonce.unwrap_or_default().try_into().map_err(|_| InvalidTransaction::Call)?;

// Fees calculated with the fixed `GAS_PRICE`
// When we dry-run the transaction, we set the gas to `Fee / GAS_PRICE`
// When we dry-run the transaction, we set the gas to `fee / GAS_PRICE`
let eth_fee_no_tip = U256::from(GAS_PRICE)
.saturating_mul(gas)
.try_into()
.map_err(|_| InvalidTransaction::Call)?;

// Fees with the actual gas_price from the transaction.
let eth_fee: BalanceOf<Self::Config> = U256::from(gas_price.unwrap_or_default())
.saturating_mul(gas)
.try_into()
.map_err(|_| InvalidTransaction::Call)?;
// Fees calculated from the gas and gas_price of the transaction.
let eth_fee = Pallet::<Self::Config>::convert_evm_to_native(
U256::from(gas_price.unwrap_or_default()).saturating_mul(gas),
)
.map_err(|_| InvalidTransaction::Call)?;

let info = call.get_dispatch_info();
let function: CallOf<Self::Config> = call.into();
Expand Down
25 changes: 19 additions & 6 deletions substrate/frame/revive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,7 @@ pub mod tracing;
pub mod weights;

use crate::{
evm::{
runtime::{gas_from_fee, GAS_PRICE},
GasEncoder, GenericTransaction,
},
evm::{runtime::GAS_PRICE, GasEncoder, GenericTransaction},
exec::{AccountIdOf, ExecError, Executable, Ext, Key, Stack as ExecStack},
gas::GasMeter,
storage::{meter::Meter as StorageMeter, ContractInfo, DeletionQueueManager},
Expand Down Expand Up @@ -1297,7 +1294,7 @@ where
0u32.into(),
)
.into();
let eth_gas = gas_from_fee(fee);
let eth_gas = Self::evm_fee_to_gas(fee);
let eth_gas =
T::EthGasEncoder::encode(eth_gas, result.gas_required, result.storage_deposit);

Expand All @@ -1319,6 +1316,19 @@ where
Self::convert_native_to_evm(T::Currency::reducible_balance(&account, Preserve, Polite))
}

/// Convert an EVM fee into a gas value, using the fixed `GAS_PRICE`.
/// The gas is calculated as `balance / GAS_PRICE`, rounded up to the nearest integer.
pub fn evm_fee_to_gas(fee: BalanceOf<T>) -> U256 {
let fee = Self::convert_native_to_evm(fee);
let gas_price = GAS_PRICE.into();
let remainder = fee % gas_price;
if remainder.is_zero() {
(fee / gas_price).into()
} else {
(fee.saturating_add(gas_price) / gas_price).into()
}
}

/// A generalized version of [`Self::upload_code`].
///
/// It is identical to [`Self::upload_code`] and only differs in the information it returns.
Expand Down Expand Up @@ -1374,7 +1384,7 @@ where
}

/// Convert a native balance to EVM balance.
fn convert_native_to_evm(value: BalanceOf<T>) -> U256 {
pub fn convert_native_to_evm(value: BalanceOf<T>) -> U256 {
value.into().saturating_mul(T::NativeToEthRatio::get().into())
}

Expand Down Expand Up @@ -1417,6 +1427,9 @@ sp_api::decl_runtime_apis! {
Nonce: Codec,
BlockNumber: Codec,
{
/// Returns the block gas limit.
fn block_gas_limit() -> U256;

/// Returns the free balance of the given `[H160]` address, using EVM decimals.
fn balance(address: H160) -> U256;

Expand Down

0 comments on commit 93dd546

Please sign in to comment.