Skip to content

Commit dba5858

Browse files
authored
Implement txGasPrice in PVM mode (#380)
* Implementation * Revert cheatcodes module to private * Removed unnecessary overwrite and added tests for txGasPrice * fmt * Set effective_gas_price in ExecConfig for PVM CREATE/CALL
1 parent 55b17e8 commit dba5858

File tree

4 files changed

+138
-2
lines changed

4 files changed

+138
-2
lines changed

crates/forge/tests/it/revive/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ pub mod cheat_mock_functions;
88
pub mod cheat_prank;
99
pub mod cheat_store;
1010
pub mod migration;
11+
pub mod tx_gas_price;
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
use crate::{config::*, test_helpers::TEST_DATA_REVIVE};
2+
use foundry_test_utils::Filter;
3+
use revive_strategy::ReviveRuntimeMode;
4+
use revm::primitives::hardfork::SpecId;
5+
use rstest::rstest;
6+
7+
#[rstest]
8+
#[case::pvm(ReviveRuntimeMode::Pvm)]
9+
#[case::evm(ReviveRuntimeMode::Evm)]
10+
#[tokio::test(flavor = "multi_thread")]
11+
async fn test_tx_gas_price_works(#[case] runtime_mode: ReviveRuntimeMode) {
12+
let runner: forge::MultiContractRunner = TEST_DATA_REVIVE.runner_revive(runtime_mode);
13+
let filter = Filter::new("testTxGasPriceWorks", "TxGasPrice", ".*/revive/.*");
14+
15+
TestConfig::with_filter(runner, filter).spec_id(SpecId::PRAGUE).run().await;
16+
}
17+
18+
#[rstest]
19+
#[case::pvm(ReviveRuntimeMode::Pvm)]
20+
#[case::evm(ReviveRuntimeMode::Evm)]
21+
#[tokio::test(flavor = "multi_thread")]
22+
async fn test_tx_gas_price_works_with_zero(#[case] runtime_mode: ReviveRuntimeMode) {
23+
let runner: forge::MultiContractRunner = TEST_DATA_REVIVE.runner_revive(runtime_mode);
24+
let filter = Filter::new("testTxGasPriceWorksWithZero", "TxGasPrice", ".*/revive/.*");
25+
26+
TestConfig::with_filter(runner, filter).spec_id(SpecId::PRAGUE).run().await;
27+
}
28+
29+
#[rstest]
30+
#[case::pvm(ReviveRuntimeMode::Pvm)]
31+
#[case::evm(ReviveRuntimeMode::Evm)]
32+
#[tokio::test(flavor = "multi_thread")]
33+
async fn test_tx_gas_price_works_with_large_value(#[case] runtime_mode: ReviveRuntimeMode) {
34+
let runner: forge::MultiContractRunner = TEST_DATA_REVIVE.runner_revive(runtime_mode);
35+
let filter = Filter::new("testTxGasPriceWorksWithLargeValue", "TxGasPrice", ".*/revive/.*");
36+
37+
TestConfig::with_filter(runner, filter).spec_id(SpecId::PRAGUE).run().await;
38+
}
39+
40+
#[rstest]
41+
#[case::pvm(ReviveRuntimeMode::Pvm)]
42+
#[case::evm(ReviveRuntimeMode::Evm)]
43+
#[tokio::test(flavor = "multi_thread")]
44+
async fn test_tx_gas_price_works_in_both_modes(#[case] runtime_mode: ReviveRuntimeMode) {
45+
let runner: forge::MultiContractRunner = TEST_DATA_REVIVE.runner_revive(runtime_mode);
46+
let filter = Filter::new("testTxGasPriceWorksInBothModes", "TxGasPrice", ".*/revive/.*");
47+
48+
TestConfig::with_filter(runner, filter).spec_id(SpecId::PRAGUE).run().await;
49+
}
50+
51+
#[rstest]
52+
#[case::pvm(ReviveRuntimeMode::Pvm)]
53+
#[case::evm(ReviveRuntimeMode::Evm)]
54+
#[tokio::test(flavor = "multi_thread")]
55+
async fn test_tx_gas_price_preserved_in_pvm_contract(#[case] runtime_mode: ReviveRuntimeMode) {
56+
let runner: forge::MultiContractRunner = TEST_DATA_REVIVE.runner_revive(runtime_mode);
57+
let filter = Filter::new("testTxGasPricePreservedInPvmContract", "TxGasPrice", ".*/revive/.*");
58+
59+
TestConfig::with_filter(runner, filter).spec_id(SpecId::PRAGUE).run().await;
60+
}

crates/revive-strategy/src/cheatcodes/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,8 @@ impl foundry_cheatcodes::CheatcodeInspectorStrategyExt for PvmCheatcodeInspector
851851
}
852852
};
853853

854+
let gas_price_pvm =
855+
sp_core::U256::from_little_endian(&U256::from(ecx.tx.gas_price).as_le_bytes());
854856
let mut tracer = Tracer::new(true);
855857
let res = execute_with_externalities(|externalities| {
856858
externalities.execute_with(|| {
@@ -871,7 +873,7 @@ impl foundry_cheatcodes::CheatcodeInspectorStrategyExt for PvmCheatcodeInspector
871873
let exec_config = ExecConfig {
872874
bump_nonce: true,
873875
collect_deposit_from_hold: None,
874-
effective_gas_price: Some(<Pallet<Runtime>>::evm_base_fee()),
876+
effective_gas_price: Some(gas_price_pvm),
875877
mock_handler: Some(Box::new(mock_handler.clone())),
876878
is_dry_run: false,
877879
};
@@ -993,6 +995,8 @@ impl foundry_cheatcodes::CheatcodeInspectorStrategyExt for PvmCheatcodeInspector
993995

994996
tracing::info!("running call on pallet-revive with {} {:#?}", ctx.runtime_mode, call);
995997

998+
let gas_price_pvm =
999+
sp_core::U256::from_little_endian(&U256::from(ecx.tx.gas_price).as_le_bytes());
9961000
let mock_handler = MockHandlerImpl::new(
9971001
&ecx,
9981002
&call.caller,
@@ -1017,7 +1021,7 @@ impl foundry_cheatcodes::CheatcodeInspectorStrategyExt for PvmCheatcodeInspector
10171021
let exec_config = ExecConfig {
10181022
bump_nonce: true,
10191023
collect_deposit_from_hold: None,
1020-
effective_gas_price: Some(<Pallet<Runtime>>::evm_base_fee()),
1024+
effective_gas_price: Some(gas_price_pvm),
10211025
mock_handler: Some(Box::new(mock_handler.clone())),
10221026
is_dry_run: false,
10231027
};
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
pragma solidity ^0.8.18;
3+
4+
import "ds-test/test.sol";
5+
import "cheats/Vm.sol";
6+
7+
contract GasPriceChecker {
8+
function getGasPrice() public view returns (uint256) {
9+
return tx.gasprice;
10+
}
11+
}
12+
13+
contract TxGasPriceTest is DSTest {
14+
Vm constant vm = Vm(HEVM_ADDRESS);
15+
16+
function testTxGasPriceWorks() public {
17+
// Set a new gas price
18+
uint256 newGasPrice = 100_000_000_000; // 100 gwei
19+
vm.txGasPrice(newGasPrice);
20+
21+
// Verify the gas price was updated
22+
assertEq(tx.gasprice, newGasPrice, "gas price should be updated");
23+
}
24+
25+
function testTxGasPriceWorksWithZero() public {
26+
// Set gas price to zero
27+
vm.txGasPrice(0);
28+
29+
// Verify the gas price was updated to zero
30+
assertEq(tx.gasprice, 0, "gas price should be zero");
31+
}
32+
33+
function testTxGasPriceWorksWithLargeValue() public {
34+
uint256 largeGasPrice = 1_000_000_000_000_000; // 1 million gwei
35+
vm.txGasPrice(largeGasPrice);
36+
37+
// Verify the gas price was updated
38+
assertEq(tx.gasprice, largeGasPrice, "gas price should be updated to large value");
39+
}
40+
41+
function testTxGasPriceWorksInBothModes() public {
42+
// Test in EVM mode
43+
vm.pvm(false);
44+
uint256 evmGasPrice = 50_000_000_000; // 50 gwei
45+
vm.txGasPrice(evmGasPrice);
46+
assertEq(tx.gasprice, evmGasPrice, "gas price should work in EVM mode");
47+
48+
// Test in PVM mode
49+
vm.pvm(true);
50+
uint256 pvmGasPrice = 75_000_000_000; // 75 gwei
51+
vm.txGasPrice(pvmGasPrice);
52+
assertEq(tx.gasprice, pvmGasPrice, "gas price should work in PVM mode");
53+
}
54+
55+
function testTxGasPricePreservedInPvmContract() public {
56+
// Set gas price in EVM mode
57+
vm.pvm(false);
58+
uint256 evmGasPrice = 50_000_000_000; // 50 gwei
59+
vm.txGasPrice(evmGasPrice);
60+
61+
// Switch to PVM mode (gas price should be preserved)
62+
vm.pvm(true);
63+
64+
// Deploy a contract in PVM mode - it should see the preserved gas price
65+
GasPriceChecker checker = new GasPriceChecker();
66+
67+
// Call the contract - it should see the same gas price
68+
uint256 gasPriceFromContract = checker.getGasPrice();
69+
assertEq(gasPriceFromContract, evmGasPrice, "gas price should be preserved in PVM contract");
70+
}
71+
}

0 commit comments

Comments
 (0)