-
Notifications
You must be signed in to change notification settings - Fork 27
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: generate inversions of abi.encodePacked()
for StakingMessages.unpack*()
#482
base: main
Are you sure you want to change the base?
Conversation
Thanks for putting this together! We'll definitely want to integrate these optimizations once the Warp message definitions in question are stable. |
Yeah big fan of this method! Thanks! |
…er into arr4n/staking-messages
SetSubnetValidatorWeightMessage
(un)packing gas reductionsabi.encodePacked()
for StakingMessages.unpack*()
|
||
library Unpack { | ||
/// @dev Thrown if the input buffer to an unpack function is of the wrong length. | ||
error IncorrectInputLength(uint256 expected, uint256 actual); |
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.
how strongly do you feel about custom errors? We previously reverted from custom errors back to require
statements, because we felt some tooling weren't updated to custom errors and lacked in debugging
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.
Which tooling lacks support?
I think they're superior to string errors:
- Don't need to store the entire string in the contract code
- Can be parameterised to aid debugging and allow precise path detection in tests
- Avoid change-detector 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.
we reverted to require
statements over a year ago, so probably need to revisit this. I think back then some combination of forge
errors, block explorers, and e2e testing just showed the hex error signature. This still seems like the case for our e2e test code, but there's likely a workaround we could do.
I am also leaning towards custom errors now, but think we should tackle this in a separate issue, and still conform to require to match the rest of the repo.
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.
It's not a hill I'll die on, but something I feel I should push back on and ask "are you sure?" before I implement a toggle between the two.
Independent benchmarking of both deployment and usage gas.
Where is the problematic e2e test code?
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.
As it currently stands, these reverts can never occur because I left the original length checks in place for the time being.
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.
This folder holds the e2e tests I'm referring to https://github.com/ava-labs/teleporter/tree/main/tests/flows. This is also not a hill I'll die on, since I'm also leaning towards custom errors at this point, but wasn't sure to defer to a separate issue and changing all the require
statements in the repo together so we can keep them consistent for now.
This allows the existing tests of round-trip pack-unpack to demonstrate equivalence.
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.
LGTM once licensing is cleared up
Overall this looks so very useful! I think the current generated code was manually run on the current contracts? We should set up some sort of shell script (or add to the existing |
Just converted this to draft as it's been stale for a while and will need some reworking before it's mergeable again. |
@geoff-vball would you like me to revive it so it can be merged? At the time there wasn't consensus about its inclusion so I didn't keep up with the base branch, but if the team definitely wants it then I can update it. |
@ARR4N the issue that cropped up here was that now we have multiple dynamic fields in the message specs. All fields are prefixed with their length except for BLS key which is static at 48 bytes but appears dynamic in the definition because it's greater than 32. I started hacking at an implementation to support this but ended up deprioritizing. If you have an idea for a clean approach implementation wise I'd love to hear/ see it but it's not high priority |
Why this should be merged
Save significant gas + improve readability so it's easier to find bugs in reviews.
Gas before
Gas after
How this works
Packing was identical to
abi.encodePacked()
so it's replaced as such. There is noabi.decodePacked()
so there's a code generator to load words directly from memory. Solidity automatically performs the necessary masking forbytes<N>
types so only themload()
needs to be explicit.Warning
There's an option to use
mcopy()
but we don't have the opcode yet so the generated code defaults to using the original memory space when returning dynamically sized arrays. This is a destructive operation that corrupts the input. If this isn't acceptable I can write a manualmcopy()
instead.How this was tested
The code generator also generates round-trip fuzz tests. To demonstrate equivalence with the previous approach, I originally only changed the
pack*
methods to allow the existing tests to show that original unpacking worked as expected; only then did I change theunpack*
methods to use the generated code.How is this documented
Comments in line with implementation, if and where required.
Note
Please excuse the force push and chaotic commit history. I honestly have no idea what went wrong when rebasing (then merging) onto the changed upstream branch. This SHOULD be squash merged!