-
Notifications
You must be signed in to change notification settings - Fork 21.4k
core/vm: optimize opCreate and opCreate2 by not copy memory #32918
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
base: master
Are you sure you want to change the base?
Conversation
cuiweixie
commented
Oct 15, 2025
It seems like it could be okay. But also could potentially be a very dangerous change. contract creation happens relatively less often and isn't a bottleneck in the EVM. So based on the risk/reward tradeoff here, I'd be inclined to close this. |
|
offset, size = scope.Stack.pop(), scope.Stack.pop() | ||
salt = scope.Stack.pop() | ||
input = scope.Memory.GetCopy(offset.Uint64(), size.Uint64()) | ||
input = scope.Memory.GetPtr(offset.Uint64(), size.Uint64()) |
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.
By changing to the GetPtr, the same byte slice will be referenced/used in two call frames: one in the contract creation and another is the caller frame.
It might introduce some unexpected edge cases where the slice mutations from one side affect another side. It feels a very dangerous change to me.
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.
- in ethereum white paper mention that "code is theoretically immutable".
- "By changing to the GetPtr, the same byte slice will be referenced/used in two call frames: one in the contract creation and another is the caller frame.
It might introduce some unexpected edge cases where the slice mutations from one side affect another side. "
this is same to opcall. but op call already change to GetPtr!.
3. as in this pr. "I'm not 100% sure we need it, but Create/Create2 holds on to that code, and stores it in a struct for later processing. I didn't consider it safe to change that now", actually, Not only code(input) is stores in struct for later processing, but also the opCall input. GetPtr is call here. and assign to contract.Input here. Which is next next to Code field in contract here.
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.
I have digged into this, and even though this thing looks wrong, I am convinced that it is ok:
- the input data would be a reference, but accessing it from the contract would cause a copy as
CALLDATALOAD
callsgetData
, which makes a copy. There is no way for the caller to directly modify the input slice. - the data that would be saved to disk is also copied from memory, so there is no issue there
- As the author notes, this optimization is already used in
opCall
and it works
Nonetheless, I think it's a bad idea because although it works today, we are not protected from future modifications that would somehow uncover that problem. I'm going to approve but let Gary have the final say.