This MIP proposes a generic scheme by which new opcodes can be added to the Monad VM, while minimising the risk of collisions with future Ethereum changes.
Disclaimer: I’m currently analyzing the JUMPDEST situation, and might propose a different approach to it (that there are reasons for the extension opcode to be JUMPDEST-analysis neutral).
This is more of an editorial suggestion to current approach:
In the Jumpdest Analysis section, the rule is too weak. In current form 0xEE605B would cause the 0x5B to be an invalid jump destination. I think it should read:
As for
PUSH1opcode, an immediate data byte following a0xEEbyte is skipped over during JUMPDEST analysis.
In particular:
- In
0xEE5Bthe0x5Bis not a valid jump destination - In
0xEE605Bthe0x5Bis a valid jump destination - In
0xEE615B5Bboth0x5B’s are valid jump destinations etc.
For completeness: we’re unfortunate EIP-8024 is considered for Amsterdam, complicating things. If it goes in, 0xE6EE5B, 0xEEE65B (and similar) must be dealt with.
I would recommend that an EIP-8024-like approach to JUMPDEST-analysis is taken.
Problem statement
Let’s call the current approach “JUMPDEST-analysis expanding”, because we’re expanding the rules of the analysis, to cover 0xEE immediate arguments.
The interaction of current JUMPDEST-analysis expanding MIP-7 and EIP-8024 is broken:
Consider the bytecode: 0xE6 0xEE 0x60 0x5B. Here we compare how its JUMPDEST analysis and execution unfold:
| EVM | Jumpdest Analysis | Execution |
|---|---|---|
| Osaka | 0x5B is an invalid jumpdest as it is a PUSH1 argument: JDâś— |
invalid, invalid, PUSH1 0x5B |
| EIP-8024 | 0x5B is an invalid jumpdest as it is a PUSH1 argument: JDâś— |
DUPN-0xEE (valid), PUSH1-0x5B |
| MIP-7 | 0xEE skips 0x60 making 0x5B a valid jump destination: JDâś“ |
invalid, EXTENSION-0x60, JUMPDEST |
| Both | 0xEE skips 0x60 making 0x5B a valid jump destination: JDâś“ |
DUPN-0xEE (valid), PUSH1-0x5B |
Osaka and MIP-7 rows are less of a concern, as they contain invalid operation in the bytecode. However, code which is correct under EIP-8024 and executes as a DUPN-0xEE and PUSH1-0x5B, with the argument of the push being an invalid jump destination, becomes something different when combined with MIP-7.
A more severe variant is 0xE6 0xEE 0x60 0x60 0x5B, where MIP-7 causes the jump destination to vanish. 0xE6 0xEE 0x7F ... 0x5B demonstrates that the effect can cascade across the entire remainder of the bytecode.
Proposed solution
In general, let’s declare that the extension opcode 0xEE (in MIP-7 but also in whatever EIP we’re going to put up) is not altering JUMPDEST analysis in any way, that is, the set of valid jump destinations remains the same with or without MIP-7, for all bytecodes.
One way to do this is to adopt the approach EIP-8024 is taking, discussed as 2.2.1 in here. The advantages of this are:
- Increases the chance of success of the MIP-7’s EIP counterpart, because it dodges the subject of backwards comptibility of JUMPDEST-analysis, just like EIP-8024 did
- Increases the cross-compatiblity of the bytecode between EVMs adopting MIP-7 and others. Imagine bytecode which is aware of the EVM it’s running in (think a bundler which runs a hypothetical
0xEE-0x60combo on a chain which recognizes this extension and jumps over it otherwise). It would not work cross chain if0xEE 0x60 0x5Bcombination was treated with expanded JUMPDEST-analysis - Consistent with EIP-8024, which I assume Monad is going to adopt anyway, if it goes into Amsterdam
- Still bytecode-efficient compared to 2.2.3 in here, and cleaner than 2.2.2 therein
In case >1byte immediate arguments are needed (or variadic) for the extension, approach 2.2.3 in here still can be used. MIP-7’s EIP counterpart may not prescribe the concrete variant, but it should require that the extension opcode doesn’t alter JUMPDEST analysis generally.
Added a proposal to MIP-7 to update and align with EIP-8163: Reserve EXTENSION (0xae) opcode