diff --git a/EIPS/eip-4200.md b/EIPS/eip-4200.md index 19497a60abcc80..1f407df79940a1 100644 --- a/EIPS/eip-4200.md +++ b/EIPS/eip-4200.md @@ -47,11 +47,11 @@ If the code is valid EOF1: 1. `RJUMP relative_offset` sets the `PC` to `PC_post_instruction + relative_offset`. 2. `RJUMPI relative_offset` pops a value (`condition`) from the stack, and sets the `PC` to `PC_post_instruction + ((condition == 0) ? 0 : relative_offset)`. -3. `RJUMPV count relative_offset+` pops a value (`case`) from the stack, and sets the `PC` to `PC_post_instruction + ((case >= count) ? 0 : relative_offset[case])`. +3. `RJUMPV max_index relative_offset+` pops a value (`case`) from the stack, and sets the `PC` to `PC_post_instruction + ((case > max_index) ? 0 : relative_offset[case])`. The immediate argument `relative_offset` is encoded as a 16-bit **signed** (two's-complement) big-endian value. Under `PC_post_instruction` we mean the `PC` position after the entire immediate value. -The immediate encoding of `RJUMPV` is more special: the 8-bit `count` value determines the number of `relative_offset` values following. Validation algorithm of [EIP-3670](./eip-3670.md) is extended to verify that `count >= 1`. The encoding of `RJUMPV` must have at least one `relative_offset` and thus it will take at minimum 4 bytes. Furthermore, the `case >= count` condition falling through means that in many use cases one would place the *default* path following the `RJUMPV` instruction. An interesting feature is that `RJUMPV 1 relative_offset` is an inverted-`RJUMPI`, which can be used in many cases instead of `ISZERO RJUMPI relative_offset`. +The immediate encoding of `RJUMPV` is more special: the unsigned 8-bit `max_index` value determines the maximum index in the jump table. The number of `relative_offset` values following is `max_index+1`. This allows table sizes up to 256. The encoding of `RJUMPV` must have at least one `relative_offset` and thus it will take at minimum 4 bytes. Furthermore, the `case > max_index` condition falling through means that in many use cases, one would place the *default* path following the `RJUMPV` instruction. An interesting feature is that `RJUMPV 0 relative_offset` is an inverted-`RJUMPI`, which can be used in many cases instead of `ISZERO RJUMPI relative_offset`. We also extend the validation algorithm of [EIP-3670](./eip-3670.md) to verify that each `RJUMP`/`RJUMPI`/`RJUMPV` has a `relative_offset` pointing to an instruction. This means it cannot point to an immediate data of `PUSHn`/`RJUMP`/`RJUMPI`/`RJUMPV`. It cannot point outside of code bounds. It is allowed to point to a `JUMPDEST`, but is not required to. @@ -126,7 +126,7 @@ This change poses no risk to backwards compatibility, as it is introduced at the - `relative_offset` is positive/negative/`0` - `RJUMP`/`RJUMPI`/`RJUMPV` with instruction other than `JUMPDEST` as target - `relative_offset` is positive/negative/`0` -- `RJUMPV` with various valid table sizes from 1 to 255 +- `RJUMPV` with various valid table sizes from 1 to 256 #### Invalid cases @@ -135,7 +135,6 @@ This change poses no risk to backwards compatibility, as it is introduced at the - `RJUMP`/`RJUMPI`/`RJUMPV` target outside of code section bounds - `RJUMP`/`RJUMPI`/`RJUMPV` target push data - `RJUMP`/`RJUMPI`/`RJUMPV` target another `RJUMP`/`RJUMPI`/`RJUMPV` immediate argument -- `RJUMPV` with table size 0 ### Execution @@ -146,13 +145,13 @@ This change poses no risk to backwards compatibility, as it is introduced at the - `relative_offset` is positive/negative/`0` - `condition` equals `0` - `condition` does not equal `0` -- `RJUMPV 1 relative_offset` +- `RJUMPV 0 relative_offset` - `case` equals `0` - `case` does not equal `0` - `RJUMPV` with table containing positive, negative, `0` offsets - `case` equals `0` - `case` does not equal `0` - - `case` outside of table bounds (`case >= count`, fallback case) + - `case` outside of table bounds (`case > max_index`, fallback case) - `case` > 255 ## Reference Implementation @@ -216,9 +215,7 @@ def validate_code(code: bytes): elif opcode == 0x5e: if pos + 1 > len(code): raise ValidationException("truncated jump table") - jump_table_size = code[pos] - if jump_table_size == 0: - raise ValidationException("empty jump table") + jump_table_size = code[pos] + 1 pc_post_instruction = pos + 1 + 2 * jump_table_size if pc_post_instruction > len(code):