-
Notifications
You must be signed in to change notification settings - Fork 6
[issues/318] Added support for cheat code 'vm.fee' in PVM mode #331
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| }); | ||
| } | ||
|
|
||
| fn set_basefee(new_basefee: U256, ecx: Ecx<'_, '_, '_>) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay, so i assume it's not possible to modify the value of Weights::seal_base_fee on pallet-revive?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and do we have anyone who's up to date on gas mapping?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really
| import "./Vm.sol"; | ||
| import {console} from "./console.sol"; | ||
| contract Fee is DSTest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
try calling block.basefee from a contract that's deployed on pvm side
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added some more tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
forgetest!(fee_revive, |prj, cmd| {
prj.insert_ds_test();
prj.insert_vm();
prj.insert_console();
prj.add_source("C.sol",
r#"
contract C {
function example() public returns (uint256) {
return block.basefee;
}
}
"#
).unwrap();
prj.add_source(
"Fee.t.sol",
r#"
import "./test.sol";
import "./Vm.sol";
import "./C.sol";
import {console} from "./console.sol";
contract Fee is DSTest {
Vm constant vm = Vm(HEVM_ADDRESS);
function test_Fee() public {
C target = new C();
uint256 original = target.example();
vm.fee(25 gwei);
uint256 newValue = target.example();
assertEq(newValue, 25 gwei);
assert(original != newValue);
}
}
"#,
)
.unwrap();
let res = cmd.args(["test", "--resolc", "--resolc-startup", "-vvv"]).assert_success();
res.stderr_eq(str![""]).stdout_eq(str![[r#"
[COMPILING_FILES] with [SOLC_VERSION]
[SOLC_VERSION] [ELAPSED]
Compiler run successful!
[COMPILING_FILES] with [RESOLC_VERSION]
[RESOLC_VERSION] [ELAPSED]
Compiler run successful!
Ran 1 test for src/Fee.t.sol:Fee
[PASS] test_Fee() ([GAS])
Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]
Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)
"#]]);
});result:
Traces:
[83471631] Fee::test_Fee()
├─ [16788608] → new <unknown>@0x7D8CB8F412B3ee9AC79558791333F41d2b1ccDAC
│ └─ ← [Return] 2366 bytes of code
├─ [33317875] 0x7D8CB8F412B3ee9AC79558791333F41d2b1ccDAC::example()
│ └─ ← [Return] 1000000000 [1e9]
├─ [0] VM::fee(25000000000 [2.5e10])
│ └─ ← [Return]
├─ [33317875] 0x7D8CB8F412B3ee9AC79558791333F41d2b1ccDAC::example()
│ └─ ← [Return] 1000000000 [1e9]
├─ emit log(val: "Error: a == b not satisfied [uint]")
├─ emit log_named_uint(key: " Expected", val: 25000000000 [2.5e10])
├─ emit log_named_uint(key: " Actual", val: 1000000000 [1e9])There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like the pallet-revive's basefee opcode implementation doesn't read from the effective_gas_price, but has a hardcoded default value of 1 gwei.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you fill out an issue on foundry-polkadot to implement the functionality for pallet-revive/foundry-polkadot
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
|
||
| fn set_basefee(new_basefee: U256, ecx: Ecx<'_, '_, '_>) { | ||
| // Set basefee in EVM context. | ||
| ecx.block.basefee = new_basefee.try_into().expect("Basefee exceeds u64"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
did you check how zksync is handling it?
I think they keep it consistent between vm calls.
- Single Source of Truth
// vm.fee() cheatcode sets this:
ccx.ecx.block.basefee =
newBasefee.saturating_to(); // Line 459 in
evm.rs
- Shared Through EthEvmContext
When zkVM is called, it receives the same
EthEvmContext that EVM uses:
// In zksync_try_call (strategy/zksync):
foundry_zksync_core::vm::call(call,
factory_deps, ecx, ccx)
- zkVM Extracts Basefee from Shared Context
// In runner.rs:303 - zkVM reads basefee from
the shared ecx.block:
block_basefee: min(max_fee_per_gas.to_ru256(),
rU256::from(ecx.block.basefee)),
Why do we use different approach?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added shared source of truth ecx.block.basefee, then clamping the value with maximum gas price.
| impl Cheatcode for feeCall { | ||
| fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { | ||
| let Self { newBasefee } = self; | ||
| ensure!(*newBasefee <= U256::from(u64::MAX), "base fee must be less than 2^64 - 1"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why remove this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The vm.fee method accepts up to uint256.max value function fee(uint256 newBasefee) external. While testing, had one case where PVM mode was not enabled, so I observed this line throws error while the use case seems perfectly valid for EVM setup. The saturating_to() can handle u256 values and will bound them to the max (no panicking or wrapping) of basefee which is u64. Let me know if my testing was wrong for the EVM use case.
TL;DR
This pull request implements the
vm.feecheatcode for polkadot-foundry's PVM mode, following the same pattern as existing cheatcodes likevm.rollandvm.warp.Changes
vm.feehandler inrevive-strategyto updateblock.basefeein EVM contextvm.feefunctionality in PVM modeCloses #318