Skip to content

Conversation

@pgherveou
Copy link
Contributor

@pgherveou pgherveou commented Oct 28, 2025

Fix gas_used calculation introduced in #9418 to use the actual gas instead of just ref_time.

With these changes we now guarantee that tx_cost = effective_gas_price * gas.
Note that since we compute gas as fee / gas_price, this can lead to rounding errors when the chain uses SlowAdjustingFeeUpdate (i.e. the fee is not a multiple of the gas price).
The changes in this PR ensure the fee still matches by burning the rounding remainder.

This PR also fixes how the actual fee is computed and introduces a new compute_actual_fee in Config::FeeInfo.
The previous fee calculation was skipping the extension_weight in the fee calculation.

The updated tests ensure that the tx cost reported in the receipt matches the fees deducted from the user account:

https://github.com/paritytech/evm-test-suite/blob/460b2c9aa3a3019d3508bb5a34a2498ea86035ff/src/gas.test.ts?plain=1#L31-L61

@pgherveou pgherveou marked this pull request as ready for review October 28, 2025 21:59
@pgherveou pgherveou requested review from a team as code owners October 28, 2025 21:59
@pgherveou pgherveou changed the title eth-rpc fix reported gas used revive fix reported gas used Oct 28, 2025
@pgherveou
Copy link
Contributor Author

/cmd prdoc --audience runtime_dev --bump patch

@pgherveou pgherveou added the T7-smart_contracts This PR/Issue is related to smart contracts. label Oct 28, 2025
@pgherveou
Copy link
Contributor Author

Still some discrepancy in thr tx cost for instantiating

Debugging...

Copy link
Contributor

@lexnv lexnv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks for handling this @pgherveou 🙏

@pgherveou pgherveou marked this pull request as draft October 29, 2025 08:41
there is still a rounding factor to deal with
Copy link
Contributor

@TorstenStueber TorstenStueber left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with most changes in this PR and most of the logic is more correct this way, particularly that receipts use the actual effective gas price and that (effective_gas_price * gas_used) = deducted amount.

I just have my problems with the gas estimate being (total cost) / (effective gas price) instead of (total cost) / (next fee multiplier).

I understand that the resulting gas_used as reported in the receipt should closely agree with the gas estimate but I would

  • either accept that gas_used is lower (in Remix the gas estimate seems to also be 15% above the resulting actually used gas)
  • don't just deduct the resulting cost (transaction fees + storage deposit) from the user but scale that by (effective gas price) / (next fee multiplier) and deduct/burn that additional amount; at least the user would be fine with that as that is consistent with Ethereum behavior

I was thinking about the last option in the last couple of days. I don't implement it that way yet in my PR but it is the most consistent option: with the first option, if a contract measures it's own gas usage through gasleft() at the beginning and end, it will see a higher usage during execution than what will be the resulting gas_used value. Not sure whether we should worry about that.

@pgherveou
Copy link
Contributor Author

@TorstenStueber

don't just deduct the resulting cost (transaction fees + storage deposit) from the user but scale that by (effective gas price) / (next fee multiplier) and deduct/burn that additional amount; at least the user would be fine with that as that is consistent with Ethereum behavior

so essentially you want to do

-		let fee = Pallet::<T>::convert_native_to_evm(match output.storage_deposit {
+		let fee = match output.storage_deposit {
 			StorageDeposit::Refund(refund) => native_fee.saturating_sub(refund),
 			StorageDeposit::Charge(amount) => native_fee.saturating_add(amount),
-		});
+		};
+
+		let ratio = FixedU128::from_rational(
+			effective_gas_price.as_u128(),
+			Pallet::<T>::evm_base_fee().as_u128(),
+		);
+
+		let fee = Pallet::<T>::convert_native_to_evm(
+			ratio.saturating_mul_int(fee).saturating_add(1_u32.into()),
+		);

@TorstenStueber
Copy link
Contributor

Yes, indeed and I gave my reasoning here: https://shade-verse-e97.notion.site/Gas-vs-Cost-2a08532a7ab580848878f67d756468da?pvs=74

@alindima
Copy link
Contributor

alindima commented Nov 4, 2025

@pgherveou could we please get this merged today? It's blocking both anvil and embedded EVM at the moment. Thanks!

@pgherveou
Copy link
Contributor Author

@pgherveou could we please get this merged today? It's blocking both anvil and embedded EVM at the moment. Thanks!

will address the latest comments and merge

@github-actions
Copy link
Contributor

github-actions bot commented Nov 4, 2025

Differential Tests Results

Specified Tests

  • simple
  • complex
  • translated_semantic_tests

Counts

  • Total Number of Test Cases: 26447
  • Total Number of Successes: 19156
  • Total Number of Failures: 37
  • Total Number of Ignores: 7254

Failures

The test specifiers seen in this section have the format 'path::case_idx::compilation_mode' and they're compatible with the revive differential tests framework and can be specified to it directly in the same way that they're provided through the --test argument of the framework.

The failures are provided in an expandable section to ensure that the PR does not get polluted with information. Please click on the section below for more information

Detailed Differential Tests Failure Information
Test Specifier Failure Reason Note
complex/create/create2_many/test.json::1::Y+ Failed to execute all of the steps on the driver: Failure on step 0: Function call step Failed: Failed to handle function call assertions: Transaction status assertion failed - Expected true but got false. Revert reason: Some("OutOfGas")
complex/create/create2_many/test.json::1::E+ Failed to execute all of the steps on the driver: Failure on step 0: Function call step Failed: Failed to handle function call assertions: Transaction status assertion failed - Expected true but got false. Revert reason: Some("")
complex/create/create_many/test.json::1::E+ Failed to execute all of the steps on the driver: Failure on step 0: Function call step Failed: Failed to handle function call assertions: Transaction status assertion failed - Expected true but got false. Revert reason: Some("")
complex/create/create_many/test.json::1::Y+ Failed to execute all of the steps on the driver: Failure on step 0: Function call step Failed: Failed to handle function call assertions: Transaction status assertion failed - Expected true but got false. Revert reason: Some("OutOfGas")
complex/defi/UniswapV2Router01/UniswapV2Pair/test.json::1::E+ Failed to execute all of the steps on the driver: Failure on step 11: Function call step Failed: Failed to handle function call assertions: Calldata assertion failed - Expected Compound([CalldataItem("99999999999999900000000")]) but got 0x000000000000000000000000000000000000000000002a5a058fc295e70a1f00
complex/defi/UniswapV2Router01/UniswapV2Pair/test.json::1::Y+ Failed to execute all of the steps on the driver: Failure on step 11: Function call step Failed: Failed to handle function call assertions: Calldata assertion failed - Expected Compound([CalldataItem("99999999999999900000000")]) but got 0x000000000000000000000000000000000000000000002a5a058fc295e70a1f00
complex/defi/UniswapV2Router01/UniswapV2Pair/test.json::1::Y- Failed to execute all of the steps on the driver: Failure on step 11: Function call step Failed: Failed to handle function call assertions: Calldata assertion failed - Expected Compound([CalldataItem("99999999999999900000000")]) but got 0x000000000000000000000000000000000000000000002a5a058fc295e70a1f00
complex/defi/UniswapV2Router01/UniswapV2Pair/test.json::1::E- Failed to execute all of the steps on the driver: Failure on step 11: Function call step Failed: Failed to handle function call assertions: Calldata assertion failed - Expected Compound([CalldataItem("99999999999999900000000")]) but got 0x000000000000000000000000000000000000000000002a5a058fc295e70a1f00
complex/defi/UniswapV3/test_evm.json::0::E+ =0.7.6 Failed to execute all of the steps on the driver: Failure on step 7: Function call step Failed: Failed to handle function call assertions: Transaction status assertion failed - Expected true but got false. Revert reason: Some("OutOfGas")
complex/voting/test.json::0::Y- >=0.8.1 Failed to execute all of the steps on the driver: Failure on step 2: Function call step Failed: Failed to handle function call assertions: Transaction status assertion failed - Expected true but got false. Revert reason: Some("")
complex/voting/test.json::0::Y+ >=0.8.1 Failed to execute all of the steps on the driver: Failure on step 2: Function call step Failed: Failed to handle function call assertions: Transaction status assertion failed - Expected true but got false. Revert reason: Some("")
complex/voting/test.json::0::E+ >=0.8.1 Failed to execute all of the steps on the driver: Failure on step 2: Function call step Failed: Failed to handle function call assertions: Transaction status assertion failed - Expected true but got false. Revert reason: Some("")
complex/voting/test.json::0::E- >=0.8.1 Failed to execute all of the steps on the driver: Failure on step 2: Function call step Failed: Failed to handle function call assertions: Transaction status assertion failed - Expected true but got false. Revert reason: Some("")
complex/yul_instructions/calldatasize/test_evm.json::11::Y- Failed to execute all of the steps on the driver: Failure on step 0: Function call step Failed: Failed to handle function call assertions: Transaction status assertion failed - Expected true but got false. Revert reason: Some("OutOfGas")
complex/yul_instructions/calldatasize/test_evm.json::11::E- Failed to execute all of the steps on the driver: Failure on step 0: Function call step Failed: Failed to handle function call assertions: Transaction status assertion failed - Expected true but got false. Revert reason: Some("OutOfGas")
complex/yul_instructions/calldatasize/test_evm.json::11::Y+ Failed to execute all of the steps on the driver: Failure on step 0: Function call step Failed: Failed to handle function call assertions: Transaction status assertion failed - Expected true but got false. Revert reason: Some("OutOfGas")
complex/yul_instructions/calldatasize/test_evm.json::11::E+ Failed to execute all of the steps on the driver: Failure on step 0: Function call step Failed: Failed to handle function call assertions: Transaction status assertion failed - Expected true but got false. Revert reason: Some("OutOfGas")
simple/solidity_by_example/simple/function_modifier.sol::1::Y+ >=0.8.1 Failed to execute all of the steps on the driver: Failure on step 1: Function call step Failed: Failed to handle function call assertions: Transaction status assertion failed - Expected false but got true. Revert reason: None
simple/solidity_by_example/simple/function_modifier.sol::1::E+ >=0.8.1 Failed to execute all of the steps on the driver: Failure on step 1: Function call step Failed: Failed to handle function call assertions: Transaction status assertion failed - Expected false but got true. Revert reason: None
simple/solidity_by_example/simple/function_modifier.sol::1::E- >=0.8.1 Failed to execute all of the steps on the driver: Failure on step 1: Function call step Failed: Failed to handle function call assertions: Transaction status assertion failed - Expected false but got true. Revert reason: None
simple/solidity_by_example/simple/function_modifier.sol::1::Y- >=0.8.1 Failed to execute all of the steps on the driver: Failure on step 1: Function call step Failed: Failed to handle function call assertions: Transaction status assertion failed - Expected false but got true. Revert reason: None
simple/try_catch/unbalanced_gas_limit.sol::0::E+ Failed to execute all of the steps on the driver: Failure on step 0: Function call step Failed: Failed to handle function call assertions: Calldata assertion failed - Expected Compound([CalldataItem("0"), CalldataItem("1"), CalldataItem("0"), CalldataItem("0")]) but got 0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
simple/try_catch/unbalanced_gas_limit.sol::0::Y+ Failed to execute all of the steps on the driver: Failure on step 0: Function call step Failed: Failed to handle function call assertions: Calldata assertion failed - Expected Compound([CalldataItem("0"), CalldataItem("1"), CalldataItem("0"), CalldataItem("0")]) but got 0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
simple/try_catch/unbalanced_gas_limit.sol::0::Y- Failed to execute all of the steps on the driver: Failure on step 0: Function call step Failed: Failed to handle function call assertions: Calldata assertion failed - Expected Compound([CalldataItem("0"), CalldataItem("1"), CalldataItem("0"), CalldataItem("0")]) but got 0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
simple/try_catch/unbalanced_gas_limit.sol::0::E- Failed to execute all of the steps on the driver: Failure on step 0: Function call step Failed: Failed to handle function call assertions: Calldata assertion failed - Expected Compound([CalldataItem("0"), CalldataItem("1"), CalldataItem("0"), CalldataItem("0")]) but got 0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
simple/yul_instructions/blockhash.sol::3::Y+ Failed to execute all of the steps on the driver: Failure on step 0: Function call step Failed: Failed to handle function call assertions: Calldata assertion failed - Expected Compound([CalldataItem("$BLOCK_HASH:256")]) but got 0x6308ce345faef9726e4e74f544ff17042ead1ba5defccf02420a14625b69963f
simple/yul_instructions/blockhash.sol::3::E- Failed to execute all of the steps on the driver: Failure on step 0: Function call step Failed: Failed to handle function call assertions: Calldata assertion failed - Expected Compound([CalldataItem("$BLOCK_HASH:256")]) but got 0x8a5df03ce189c8e1a8b1e44a841d9a3f0e70d49a55466b43b76721569b47c451
simple/yul_instructions/blockhash.sol::3::E+ Failed to execute all of the steps on the driver: Failure on step 0: Function call step Failed: Failed to handle function call assertions: Calldata assertion failed - Expected Compound([CalldataItem("$BLOCK_HASH:256")]) but got 0x14ad0084d660de9c730988c5946a811b0f6bbd89942f4083749dfe8ab6a3374f
simple/yul_instructions/blockhash.sol::3::Y- Failed to execute all of the steps on the driver: Failure on step 0: Function call step Failed: Failed to handle function call assertions: Calldata assertion failed - Expected Compound([CalldataItem("$BLOCK_HASH:256")]) but got 0xdd6695393bae5662171a46bd563f1b3ce0d7a130cbdaa1fdc2c0d12a090380a5
simple/yul_instructions/blockhash.sol::4::Y- Failed to execute all of the steps on the driver: Failure on step 0: Function call step Failed: Failed to handle function call assertions: Calldata assertion failed - Expected Compound([CalldataItem("$BLOCK_HASH:255")]) but got 0xe065a3ce679daf163efb3d671f5224558c61d8f548e4559bbff351db902afe18 This test case succeeded with other compilation modes: {'E-', 'E+', 'Y+'}
translated_semantic_tests/array/array_storage_index_access/test.json::0::E- Failed to execute all of the steps on the driver: Failure on step 6: Function call step Failed: Failed to handle function call assertions: Transaction status assertion failed - Expected true but got false. Revert reason: Some("OutOfGas")
translated_semantic_tests/array/array_storage_length_access/test.json::0::E- Failed to execute all of the steps on the driver: Failure on step 5: Function call step Failed: Failed to handle function call assertions: Transaction status assertion failed - Expected true but got false. Revert reason: Some("OutOfGas")
translated_semantic_tests/array/array_storage_push_empty_length_address/test.json::0::E- Failed to execute all of the steps on the driver: Failure on step 6: Function call step Failed: Failed to handle function call assertions: Transaction status assertion failed - Expected true but got false. Revert reason: Some("OutOfGas")
translated_semantic_tests/array/array_storage_push_pop/test.json::0::E- Failed to execute all of the steps on the driver: Failure on step 5: Function call step Failed: Failed to handle function call assertions: Transaction status assertion failed - Expected true but got false. Revert reason: Some("OutOfGas")
translated_semantic_tests/functionCall/gas_and_value_basic/test.json::0::E- Failed to execute all of the steps on the driver: Failure on step 2: Function call step Failed: Failed to handle function call assertions: Transaction status assertion failed - Expected false but got true. Revert reason: None
translated_semantic_tests/various/selfdestruct_post_cancun/test.json::0::E- Failed to execute all of the steps on the driver: Failure on step 2: Function call step Failed: Failed to handle function call assertions: Transaction status assertion failed - Expected true but got false. Revert reason: Some("panic: assertion failed (0x01)")
translated_semantic_tests/various/selfdestruct_post_cancun_multiple_beneficiaries/test.json::0::E- Failed to execute all of the steps on the driver: Failure on step 7: Balance Assertion Step Failed: Balance assertion failed - Expected 1000000000000000000 but got 0 for 0x1111111111111111111111111111111111111111 resolved to 0x1111111111111111111111111111111111111111

@pgherveou
Copy link
Contributor Author

/cmd prdoc --audience runtime_dev --bump patch --force

@pgherveou
Copy link
Contributor Author

Yes, indeed and I gave my reasoning here: https://shade-verse-e97.notion.site/Gas-vs-Cost-2a08532a7ab580848878f67d756468da?pvs=74

will add that in once the effective_gas_price can deviate from the base_fee, for now it can't
https://github.com/paritytech/polkadot-sdk/blob/pg/fix-gas-used/substrate/frame/revive/src/evm/api/rpc_types.rs?plain=1#L224-L212

So since we can't really test the change from the evm-test-suite, I suggest we keep it for a follow up
pg/fix-gas-used...pg/10148-follow-up

cc @TorstenStueber

@paritytech-workflow-stopper
Copy link

All GitHub workflows were cancelled due to failure one of the required jobs.
Failed workflow url: https://github.com/paritytech/polkadot-sdk/actions/runs/19075463391
Failed job name: test-linux-stable

Copy link
Contributor

@TorstenStueber TorstenStueber left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed that for us, effective gas price is always base price. So it was a lot of fuzz about nothing.

All right, thanks for the PR. 👍

@pgherveou pgherveou enabled auto-merge November 4, 2025 17:45
@pgherveou pgherveou added this pull request to the merge queue Nov 4, 2025
Merged via the queue into master with commit 23d90a0 Nov 4, 2025
238 of 239 checks passed
@pgherveou pgherveou deleted the pg/fix-gas-used branch November 4, 2025 20:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T7-smart_contracts This PR/Issue is related to smart contracts.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants