Skip to content
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

Update EIP-7069: add returndataload opcode #7820

Merged
merged 2 commits into from
Feb 1, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 16 additions & 8 deletions EIPS/eip-7069.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
eip: 7069
title: Revamped CALL instructions
description: Introduce CALL2, DELEGATECALL2 and STATICCALL2 with simplified semantics
author: Alex Beregszaszi (@axic), Paweł Bylica (@chfast), Danno Ferrin (@shemnon), Andrei Maiboroda (@gumb0)
author: Alex Beregszaszi (@axic), Paweł Bylica (@chfast), Danno Ferrin (@shemnon), Andrei Maiboroda (@gumb0), Charles Cooper (@charles-cooper)
discussions-to: https://ethereum-magicians.org/t/eip-revamped-call-instructions/14432
status: Draft
type: Standards Track
Expand All @@ -13,11 +13,11 @@

## Abstract

Introduce three new call instructions, `CALL2`, `DELEGATECALL2` and `STATICCALL2`, with simplified semantics. The existing call instructions remain unchanged.
Introduce three new call instructions, `CALL2`, `DELEGATECALL2` and `STATICCALL2`, with simplified semantics. Introduce another instruction, `RETURNDATALOAD` for loading a word from return data into stack. The existing call instructions remain unchanged.

The new instructions do not allow specifying a gas limit, but rather rely on the "63/64th rule" ([EIP-150](./eip-150.md)) to limit gas. An important improvement is the rules around the "stipend" are simplified, and callers do not need to perform special calculation whether the value is sent or not.

Furthermore, the obsolete functionality of specifying output buffer address is removed in favor of using `RETURNDATACOPY` instead.
Furthermore, the obsolete functionality of specifying output buffer address is removed in favor of using `RETURNDATACOPY` instead. For cases which would previously `*CALL` output into a buffer and then `MLOAD` from the buffer, `RETURNDATALOAD` is provided instead.

Lastly, instead of returning a boolean for execution status, an extensible list of status codes is returned: `0` for success, `1` for revert, `2` for failure.

Expand All @@ -35,7 +35,7 @@

Besides the above, this change introduces a convenience feature of returning more detailed status codes: success (0), revert (1), failure (2). This moves from the boolean option to codes, which are extensible in the future.

Lastly, the introduction of the `RETURNDATA*` instructions ([EIP-211](./eip-211.md)) has obsoleted the output parameters of calls, in a large number of cases rendering them unused. Using the output buffers have caused "bugs" in the past: in the case of [ERC-20](./eip-20.md), conflicting implementations caused a lot of trouble, where some would return something, while others would not. With relying on `RETURNDATA*` instructions this is implicitly clarified.
Lastly, the introduction of the `RETURNDATA*` instructions ([EIP-211](./eip-211.md)) has obsoleted the output parameters of calls, in a large number of cases rendering them unused. Using the output buffers have caused "bugs" in the past: in the case of [ERC-20](./eip-20.md), conflicting implementations caused a lot of trouble, where some would return something, while others would not. With relying on `RETURNDATA*` instructions this is implicitly clarified. This proposal also adds the "missing" `RETURNDATALOAD` instruction to round out returndata buffer access instructions.

## Specification

Expand All @@ -48,13 +48,14 @@
| MIN_RETAINED_GAS | 5000 | |
| MIN_CALLEE_GAS | 2300 | |

We introduce three new instructions:
We introduce four new instructions:

- `CALL2` (`0xf8`) with arguments `(target_address, input_offset, input_size, value)`
- `DELEGATECALL2` (`0xf9`) with arguments `(target_address, input_offset, input_size)`
- `STATICCALL2` (`0xfb`) with arguments `(target_address, input_offset, input_size)`
- `RETURNDATALOAD` (`0xf7`) with argument `offset`

Execution semantics:
Execution semantics of `*CALL2`:

1. Charge `WARM_STORAGE_READ_COST` (100) gas.
2. Pop required arguments from stack, fail with error on stack underflow.
Expand All @@ -75,7 +76,14 @@
11c. `2` if the call has failed.
11. Gas not used by the callee is returned to the caller.

Execution semantics of `RETURNDATALOAD`:

1. Charge `G_verylow` (3) gas
2. Pop 1 item from the stack, to be referred to as `offset`
3. If `offset + 32 > len(returndata buffer)`, halt with exceptional failure.
4. Push 1 item onto the stack, the 32-byte word read from the returndata buffer starting at `offset`.

<!-- *TODO:* Clarify which side (caller/callee) is gas deducted from and where an error originates from. -->

Check warning on line 86 in EIPS/eip-7069.md

View workflow job for this annotation

GitHub Actions / EIP Walidator

HTML comments are only allowed while `status` is one of: `Draft`, `Withdrawn`

warning[markdown-html-comments]: HTML comments are only allowed while `status` is one of: `Draft`, `Withdrawn` --> EIPS/eip-7069.md | 86 | <!-- *TODO:* Clarify which side (caller/callee) is gas deducted from and where an error originates from. --> | ::: EIPS/eip-7069.md | 88 | <!-- *TODO:* Mention gas refunds? --> | ::: EIPS/eip-7069.md | 90 | <!-- *TODO:* Consider option where non-calldata value transfer is not allowed, but there's a specific `TRANSFER`/`PAY` function for that. Would simplify the logic greatly. --> | = help: see https://ethereum.github.io/eipw/markdown-html-comments/

<!-- *TODO:* Mention gas refunds? -->

Expand Down Expand Up @@ -113,7 +121,7 @@

### Output buffers

The functionality of specifying output buffer address is removed, because it is added complexity and in a large number of cases implementers prefer to use `RETURNDATACOPY` instead. Even if they rely on the output buffer (like in the case of Vyper), they would still check the length with `RETURNDATASIZE`. In Solidity one exception is the case when the expected return size is known (i.e. non-dynamic return values), in this case Solidity still uses the output buffer.
The functionality of specifying output buffer address is removed, because it is added complexity and in a large number of cases implementers prefer to use `RETURNDATACOPY` instead. Even if they rely on the output buffer (like in the case of Vyper), they would still check the length with `RETURNDATASIZE`. In Solidity one exception is the case when the expected return size is known (i.e. non-dynamic return values), in this case Solidity still uses the output buffer. For these cases, `RETURNDATALOAD` is introduced, which simplifies the workflow of copying returndata into a (known) output buffer and using `MLOAD` from there; instead, `RETURNDATALOAD` can be used directly.

### Status codes

Expand All @@ -127,7 +135,7 @@

### Opcode encoding

Instead of introducing three new opcodes we have discussed a version with an immediate configuration byte (flags). There are two main disadvantages to this:
Instead of introducing three new `*CALL2` opcodes we have discussed a version with an immediate configuration byte (flags). There are two main disadvantages to this:

1. Some combination of flags may not be useful/be invalid, and this increases the testing/implementation surface.
2. The instruction could take variable number of stack items (i.e. `value` for `CALL2`) would be a brand new concept no other instruction has.
Expand Down