-
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
feat: new getMemory cheatcode #4664
Conversation
thank you for this before we proceed with this I'd get @mds1 and @clabby opinion on this. an issue is that
this isn't actually a big deal because memory is of type |
It also modifies memory when it stores the function arguments for the call to the cheatcode contract, no? |
Yes you're right. Really not the best... In my head, this cheatcode was meant as a quick (and dirty) way to access the memory for now. @Philogy wrote here https://t.me/foundry_rs/27582 we should write something on top of |
you could have your cheatcode implementation strip its own call and modify the 0x40 freemem pointer 🤔 basically remove its impact on the memory is there a reason that you return the memory and write it into memory? if you just want to inspect local memory, then a pointer lib would be better for that? if the puprose is to log it, better to make a lib on top of console.log? 🤔 |
Just updated my work on this new cheatcode. Based on @prestwich 's advice, I decided to move it to the Console instead. Unfortunately, the memory is still modified, due to an external call being made. I couldn't figure out how to remove the modified memory from the call simply. It involved too many changes, and I dont think it's worth it for this feature. cc @clabby |
what to do with this @mds1 ? imo we can live with this
|
Just to add some details for the reviewers: Regarding the change to
This is what the logs will look like:
Same for Scripts
|
So one thought is that we might soon have 3 ways to get memory:
I haven't compared (1) and (3) but it feels redundant to have both? But I can see how it's useful to have at least one of them as an alternative to the deubgger. TBH I don't often have the need to inspect memory so I'm probably not the best person to decide here and would defer to some optimzoooors like @teddav @Philogy @clabby @brockelmore to figure out the best path forward |
@mds1 I agree it might be redundant with the debugger, but not with safeconsole. Regarding safeconsole, I think what @Philogy did is great and could definitely be used to improve this PR, but they are 2 different things. safeconsole is a console lib that restores the memory after the log, here we're just logging the memory. I think the cheatcode could be helpful but if others think this cheatcode is useless I'm ok to close the PR. I won't fight for it 😁 |
A bit biased here since I opened the PR to add the memory-preserving logging library, but if the goal is to be able to log slices of memory I think it's better to avoid adding complexity to the core of foundry if the same effect can be achieved with external and/or the standard library. Another problem with the cheatcode-based approach is that Solidity treats them like normal calls meaning it'll in and of itself change memory for the call to the magic cheatcode address. It will only change "free" memory but this may be relevant in certain more optimized contracts (e.g. Seaport relies on the integrity of free memory for its transfer accumulator meaning you can't use cheatcodes or the normal logging libs without breaking actual logic in certain code sections). PoC: function testCheatcode() public {
address user = makeAddr("user");
uint256 fp1;
uint256 d1;
assembly {
fp1 := mload(0x40)
d1 := mload(fp1)
}
vm.prank(user);
uint256 fp2;
uint256 d2;
assembly {
fp2 := mload(0x40)
d2 := mload(fp2)
}
// Shows that calling a cheat code alone affects the free memory
assertTrue(d1 != d2);
// Free memory pointer stays intact tho.
assertEq(fp1, fp2);
} It'd be pretty straightforward to write a memory slice logging library function assuming you had a formatting flag that'd allow you to get a string display in hex. Alternatively you could leverage the |
Created a memory preserving |
I tend to agree with @Philogy here - given that this can be done in Solidity with relative ease + without modifying existing memory, it makes more sense to add this to Alternatively, if the cheatcode can take a snapshot of the memory before the call and restore it prior to logging, that would work as well - it does feel a bit messier than the |
Thanks for the thoughts @clabby @Philogy! So I'm thinking we:
@teddav lmk if you have any objections here, appreciate the PR though! |
All good. I agree with the comments above. |
Per above convo, I'm going to close this PR and later today review/merge the safeconsole one in forge-std. Sorry for the wasted work here @teddav, thanks for your understanding! |
getMemory
cheatcodeAddition of 3 new cheatcodes:
Motivation
In Solidity, the memory can only be accessed in blocks of 32 bytes. It can be more convenient to inspect the memory as a whole and log the chunks of memory we're interested in.
The debugger is a great tool but takes too much time to go through when you just need to log parts of the memory at a specific moment.
The
expectSafeMemory
cheat by @clabby was a great addition to keep memory safe. ThisgetMemory
cheatcode comes in addition to it, to ease debugging and visualize the memory while writing tests.Solution
I added 3 different cheatcodes to make it as easy as possible for the user.
The formatted memory looks like this:
Issues
string
orbytes
so it modifies the memory, which is obviously not ideal for a cheatcode that's supposed to help inspect the current memory.I think that the only way to avoid that is to just log the memory straight from the cheatcode, and avoid returning it.
apply_cheatcode()
function. So I had to clone the memory in everystep()
which obviously seems unnecessary. How can I copy the memory only before the cheatcode is applied?