-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
fix(vm.cool) Persist storage changes #5852
base: master
Are you sure you want to change the base?
Conversation
dccebea
to
3814faf
Compare
09c6522
to
33e3500
Compare
just looping in @mds1 for discussing approach — will review soon! |
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.
Still haven't reviewed for correctness—some nits
#[derive(Clone, Debug)] | ||
pub enum CoolState { | ||
CalledAndAccessed, | ||
Called, | ||
} | ||
|
||
#[derive(Clone, Debug)] | ||
pub enum CoolStorageState { | ||
Warm, | ||
WarmAndSSTORED, |
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.
Let's add docs for these—wdyt about naming @mds1?
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.
FWIW I can't tell what this enum is supposed to represent from the names here alone, so we probably need to change the names and agree with adding docs. CoolStorageState::Warm
and CoolStorageState::WarmAndSSTORED
feel like conflicting names, e.g. how is the state cool and warm? Also maybe WarmWithSSTORE
or WarmWithSstore
would be easier to read since SSTORED
isn't a usage I've seen
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.
right, i didn't know what to name the hashmap itself so it's coolstoragestate
but it's more the storage state that is tracked when calling vm.cool
, not that the state is actually both cool and warm at the same time. i'm ok just calling storagestate but it felt generic
it's tracking whether it's warm, or warm and the storage store was set, or that it's cool. Maybe very confusing but if it's empty it means it's cool (because each vm.cool resets the whole hashmap to be empty)
so it's either empty value (none), or warm (the sload makes it warm), or warm and sstore was called
I suppose this means cool, sloaded, or sstored, and each of those should change the gas increase
ok updated the renames, attempted to fix the ci issues.. |
a6ffc9d
to
68c3804
Compare
thread 'cheats::test_cheats_local' panicked at 'called `Result::unwrap()` on an `Err` value: Test testCool_call() did not pass as expected.
Reason: None
Logs:
Error: a == b not satisfied [uint]
Expected: 44835
Actual: 45299
Error: a == b not satisfied [uint]
Expected: 27735
Actual: 28199 |
@ditto-eth you can use |
ah i'd been using a custom command I made up |
68c3804
to
9643e4d
Compare
|
||
// if cool cheatcode was ever called on this address | ||
let contract_address = interpreter.contract().address.to_ethers(); | ||
if state.addresses.get(&contract_address).is_some() { |
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.
vm.cool
involves two parts: making theaddress
itself cool, making the storage slots cool- check that
vm.cool
was passed to thisaddress
- if so, track a few opcodes (call/balance/etc) to mark the address as warm, as well as queuing up additional gas to be added to the next opcode. a warm address is 100, a cool one is 2600, so add 2500.
- check the storage slots
- if.an sload or sstore, mark address as warm but add different wants of extra gas depending on the situation.
Curious what the behavior will be for cold-marked accounts/slots accessed within reverting callframes (some context) For EVM-accurate measurements, reverting callframes will have to "re-cool" This is something I was wrestling with in my much more roundabout account/slot enumeration cheatcodes. |
awesome thanks for the feedback/comment!
i'm not that familiar - is this when a new contract/function is called that fails within a try/catch? if so, then yea it would need to deduct the same amount back? i didn't think that would be a common case in the context of a gas test but maybe just ignorant of that (and why I wasn't sure what handling reverts meant as in my mind it would just fail the test anyway) |
Yeah, a It probably shouldn't be a blocker to shipping the fix, since this helps a ton with getting gas reports more accurate – but full accuracy for complex protocols probably relies on supporting these edge cases. |
i guess the selfdestruct won't be happening if it's being deprecated later i heard?
down to make it accurate as possible in the next PRs, as i'm trying to test it on my protocol now which spurred my interest in figuring this out! also in writing the tests, i started getting confused what i'd even expect the result to be 🙂 so curious on reviewing that. tests are probably based on number of opt runs which change the opcodes being done (this is annoying to test sload/sstore, as you can't just do a |
does anyone know how the gas is modified with reverts normally? sounds like i'd need to track the additional gas per frame and then subtract it if revert goes through? maybe the code related to gas metering in |
I think moreso that (An exception here is reverting CREATEs; the "CREATE"d address always gets marked warm, even if create fails) |
9643e4d
to
18d8fd3
Compare
i'm not sure what else needs to be done for this pr if we move the following points out of this
|
@mds1 I'm a bit out of the loop here does this sound conceptionally right? |
explained a bit here, but i can break it down more: #5852 (review)
|
light ping, let me know if there's anything else I should explain or add! |
Hey @ditto-eth, we recently refactored how cheatcodes are implemented in #6131. You can read more about it in the dev docs. Please let me know if you have any problems rebasing! |
7a09292
to
c1a9bb6
Compare
@DaniPopes thanks for the ping, wasn't too bad as I already did a previous rebase so a bit more familiar now - also decided to squash into 1 commit to make that easier. |
c1a9bb6
to
0a53cbe
Compare
823447f
to
ee35f1b
Compare
ee35f1b
to
632656c
Compare
hey @ditto-eth
Can you elaborate on whether there are synergies between the two? sorry for the late reply |
Motivation
this is a wip, a lot of things to finish up but wanted to get feedback as i finally got somewhere.(also happy to chat in more real time on twitter/telegram)Help Test!
gh pr checkout 5852 cargo r --bin forge test --contracts ../proj_root --config-path ../proj_root/foundry.toml
removed the account warm/cold for now, just focusing on the slotsdonecold
because they are always warm at the start of the tx (precompiles, from, to). How do you know which address isfrom
orto
? (the test address?) do I just check state for the first address touched? q around what the expected behavior should befunction cool(StorageSlot[] memory slots) external;
not implemented but should be simple if this approach works (i think this can just be a separate pr)vm.cool
but it's not a sstore/sload issue thenSolution
via
revm
telegram:^ approach seems to generally make sense? added a
step_end
to cheatcodes inspector, so onSSTORE/SLOAD
i can manipulate theinterpreter.gas
value. The idea is that a certain amount of cost needs to be added back depending onsstore
.fyi i kept all my(moved toprintln
calls in case someone wanted to check it out locally, will remove when the pr is ready to govm.cool-fix-print
branch.vm.cool
sets the variables ^. It just saves whether an address' slots are cool/warm or not by resetting it everytime thevm.cool
is called. then just calculate the added gas cost (usually +2100), but different if an sstore is done and mark the slot as "warm" so the regular gas is sufficient (until the nextvm.cool
is called if necessary). can add a few more kinds of tests.refs
https://eips.ethereum.org/EIPS/eip-2200
https://eips.ethereum.org/EIPS/eip-2929
evm.codes