-
Notifications
You must be signed in to change notification settings - Fork 773
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
VM: Add option to add custom opcodes #1705
Conversation
Codecov Report
Flags with carried forward coverage won't be shown. Click here to find out more. |
Oof I just realized we have a problem here. I am writing to the constants of How should I approach solving this? It would imply that we now need to deep-copy |
This looks already pretty cool, thanks a lot for addressing so quickly Jochem! 🙂 Let's keep this a bit in discussion for a couple of days - independently from if we find answers to the existing questions. This is such a profound change, I guess it would be good if we let this new API sink in a bit and shovel this back and forth to think about use cases and implications. 😋 (and no need to merge this in particularly early or fast) |
@@ -96,6 +98,71 @@ tape('VM.runCode: interpreter', (t) => { | |||
}) | |||
}) | |||
|
|||
tape('VM: custom opcodes', (t) => { |
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 sure if this new test suite belongs in runCode, i suggest we make a new file tests/api/evm/customOpcodes.spec.ts
@@ -143,6 +166,7 @@ export default class VM extends AsyncEventEmitter { | |||
protected _opcodes: OpcodeList | |||
protected readonly _hardforkByBlockNumber: boolean | |||
protected readonly _hardforkByTD?: BNLike | |||
protected readonly _customOpcodes?: CustomOpcode[] |
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.
Totally a side topic here but just want to mention on the occasion since we are already so much in these StateManager design questions: my dream ("I have a dream", lol) for the breaking releases is still that we also manage to separate the EVM itself (so basically: everything in the evm
folder) and all this outer execution stuff (so roughly: everything - at least - from VM.runTx()
upwards).
This mangling together of the pure EVM execution logic (opcodes in, result out, basically 😋) and all this outer environment stuff with running txs, creating receipts, running the block, assiging block rewards in this one big VM
object is one of the biggest design flaws we have. One can see this over and over again, e.g. this customOpcodes
option would - if we would have that - also rather only be a thing to be passed to a clean (inner) EVM
interface (in the sense of: API) and nothing to be babbled to this monster object with all the additional logic.
I guess this outer thing is something which rather would belong to the client then to the VM (we for sure doesn't want to integrate though) and historically likely was bapped on to the VM because there just wasn't a wrapping client or something and people needed this functionality.
Maybe we can come up with a separate package or so - VMExecutionEnv
(I have totally no idea on a fitting name yet) - and then create a stable interface (again: API) to the EVM package.
This would lead to a lot of new use cases. The EVM package could be swapped out, extended by others, used in a standalone-context, etc.. I am also pretty sure that our overall VM architecture would greatly benefit by refactoring questions which come up along the way.
This would need some serious design thinking though, not sure if we would make it with this into this round of breaking releases. I guess one main thing would be where to place and how to put in all this EEI stuff, since the inner EVM needs to have some environment information finally. Maybe you also want to give this some thinking already. 🙂
P.S.: I know, comment is totally misplaced 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 think the general point you are making here is that we should take a deep look at our internals in the VM to see if we should refactor there. I'm also getting the feeling that some things are "all over the place" and maybe a bit misplaced in some cases as well. We might do an internal refactor 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.
I would like to do one along the breaking releases, with the optimal outcome that we can separate EVM and VM and have a clean (and somewhat refactored) API between them (what also comes into play here is this EVMC interface https://github.com/ethereum/evmc eventually).
Not sure if we'll make it though to full extend in this round, this is particularly hard.
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 looks already pretty great, cool, thanks for tackling this so quickly! 🚀
Some things for discussion and comments with suggestions for some additions/modifications.
packages/vm/src/evm/opcodes/codes.ts
Outdated
} | ||
opcodeBuilder = { ...opcodeBuilder, ...entry } | ||
if (code.gasFunction) { | ||
dynamicGasHandlers.set(code.opcode, code.gasFunction) |
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 love this so much to see how these things play so nicely together close to everytime we do a profound refactoring which was initially meant to solve something completely different! 🥳
Thanks again for this great work! ❤️
}) | ||
}) | ||
|
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.
Love these tests, great! 🙂
@jochem-brouwer do you have some time to pick this up this week? Would be great if we can move this forward (merge). 🙂 |
I'm gonna need to give this a little bit more thought. The problem is that the handlers (gas handler + logic handler) are used everywhere from using the exported values from their respective files (e.g. here:
getOpcodesForHF here
Does that make sense? So we (1) need to create copies of the gas/logic maps (https://github.com/ethereumjs/ethereumjs-monorepo/blob/c842a973bc8058df71cda140fe0720292e1aafe1/packages/vm/src/evm/opcodes/gas.ts, https://github.com/ethereumjs/ethereumjs-monorepo/blob/c842a973bc8058df71cda140fe0720292e1aafe1/packages/vm/src/evm/opcodes/functions.ts) and (2) we need to somehow integrate it in the VM such that these values are read internally (probably EVM). However, maybe EVM is also not the right place because each Tx would create new EVM ethereumjs-monorepo/packages/vm/src/runTx.ts Line 392 in c842a97
Thoughts? |
I think at this point EVM.ts would be the right place to put these maps. |
I think I am not getting the problem yet. So lets take e.g. the Istn't this just a one-liner to expand |
Update: ah, I think I am slowly getting what you mean. I have the impression you are thinking the wrong way around.
Does this make sense? |
Update 2: ah, just seeing that this Wouldn't think that this would draw in some performance penalty. |
For some reason I cannot reply to this; #1705 (comment) There is no check if the opcode is present; it does not throw if it is not present and user wants to delete ( |
I have updated, tests should pass, this should be ready for review now. Note: I added the maps to VM, not to EVM. The reason is that EVM is instantiated many times and we do not want to copy the opcode map each time. (Only once and only if it is really necessary, if opcodes have changed or upon initializing). Otherwise, each time on |
Addressed the review comments as well. |
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.
One API thing and one small question, otherwise looks good. 😄
Short note: have just merged #1757, so the PR here would need another update to be ready for review. |
I took a look at this today but the merge conflicts are very weird 🤔 Need to give this a new look later because I messed up my local merge 😞 |
Ok, this should work, ready for re-review. |
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.
Generally looks good. A couple of comments on documentation that we could take or leave.
I also verified the delete/add opcode logic by inspecting the opcode lists directly in the tests so can vouch that code works great.
This PR adds a new field to
VMOpts
to allow users to add/change/delete opcodes in the VM.Please note: in
gas.ts
the linter has inserted whitespace in almost every line, the only change there is to also allow for synchronous gas functions.