Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions EIPS/eip-8024.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ def decode_pair(x: int) -> tuple[int, int]:
k = x if x <= 79 else x - 48
q, r = divmod(k, 16)
if q < r:
return q + 2, r + 2
return q + 1, r + 1
else:
return r + 2, 30 - q
return r + 1, 29 - q
```

Assemblers and compilers must emit a 1-byte immediate after each of these opcodes that decodes to the required `n, m` operands. For reference, this can be done by `encode_single` and `encode_pair`:
Expand All @@ -99,11 +99,11 @@ def encode_single(n: int) -> int:
return n + 20

def encode_pair(n: int, m: int) -> int:
assert 2 <= n <= 14 and n < m <= 30 and n + m <= 32
if m <= 17:
q, r = n - 2, m - 2
assert 1 <= n <= 13 and n < m <= 29 and n + m <= 30
if m <= 16:
q, r = n - 1, m - 1
else:
q, r = 30 - m, n - 2
q, r = 29 - m, n - 1
k = 16 * q + r
return k if k <= 79 else k + 48
```
Expand All @@ -130,6 +130,8 @@ A previous formulation of `EXCHANGE` allowed swapping stack elements only if the

In addition, the exact formulation was chosen to make `decode_pair` a simple function using only basic arithmetic, bitwise operations (division by 16), and few branches. A small trade-off in the number of addressable pairs was made to reduce the number of necessary branches; this implies some of the immediate range is not allocated, and it could be used to add a dozen more addressable pairs at the cost of more decoding complexity, potentially in a future network upgrade.

Finally, note that the operands in the assembly instruction `EXCHANGE n m` appear "off by one", i.e. it operates on the stack elements at depths `n + 1` and `m + 1`. These offsets were chosen to match the `SWAP` and `SWAPN` opcodes such that `EXCHANGE n m` has an effect equivalent to the sequence `SWAP{n} SWAP{m} SWAP{n}`.

### Size of immediate operand

For `DUPN` and `SWAPN` a 16-bit size was considered to accommodate the full stack space of 1024 items, however:
Expand Down Expand Up @@ -162,8 +164,8 @@ This has no effect on contracts that would never attempt to execute the opcodes
- `e6605b` is `[INVALID_DUPN, PUSH1 0x5b]`
- `e7610000` is `[INVALID_SWAPN, PUSH2 0x0000]`
- `e65f` is `[INVALID_DUPN, PUSH0]`
- `e812` is `[EXCHANGE 3 4]`
- `e8d0` is `[EXCHANGE 2 20]`
- `e812` is `[EXCHANGE 2 3]`
- `e8d0` is `[EXCHANGE 1 19]`
- `e850` is `[INVALID_EXCHANGE, POP]`

### Execution
Expand Down
Loading