From e13a1a56b6c6743d501ed789cf0c229cc070cc68 Mon Sep 17 00:00:00 2001 From: pdobacz <5735525+pdobacz@users.noreply.github.com> Date: Thu, 18 Apr 2024 16:25:11 +0200 Subject: [PATCH] Update EIP-7620: Expand the Rationale section & clarifications Merged by EIP-Bot. --- EIPS/eip-7620.md | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/EIPS/eip-7620.md b/EIPS/eip-7620.md index 286b52c3a025b1..52ddbcdddcf72d 100644 --- a/EIPS/eip-7620.md +++ b/EIPS/eip-7620.md @@ -117,8 +117,10 @@ Details on each instruction follow in the next sections. - deduct `TX_CREATE_COST` gas - read immediate operand `initcontainer_index`, encoded as 8-bit unsigned value -- pop `value`, `salt`, `data_offset`, `data_size` from the operand stack +- pop `value`, `salt`, `input_offset`, `input_size` from the operand stack +- peform (and charge for) memory expansion using `[input_offset, input_size]` - load initcode EOF subcontainer at `initcontainer_index` in the container from which `EOFCREATE` is executed + - let `initcontainer_size` be the declared size of that EOF subcontainer in its parent container header - deduct `GAS_KECCAK256_WORD * ((initcontainer_size + 31) // 32)` gas (hashing charge) - check that current call depth is below `STACK_DEPTH_LIMIT` and that caller balance is enough to transfer `value` - in case of failure return 0 on the stack, caller's nonce is not updated and gas for initcode execution is not consumed. @@ -128,10 +130,12 @@ Details on each instruction follow in the next sections. #### `TXCREATE` - deduct `TX_CREATE_COST` gas -- pop `tx_initcode_hash`, `value`, `salt`, `data_offset`, `data_size` from the operand stack +- pop `tx_initcode_hash`, `value`, `salt`, `input_offset`, `input_size` from the operand stack +- peform (and charge for) memory expansion using `[input_offset, input_size]` - load initcode EOF container from the transaction `initcodes` array which hashes to `tx_initcode_hash` - fails (returns 0 on the stack) if such initcode does not exist in the transaction, or if called from a transaction of `TransactionType` other than `INITCODE_TX_TYPE` - caller's nonce is not updated and gas for initcode execution is not consumed. Only `TXCREATE` constant gas was consumed + - let `initcontainer_size` be the length of that EOF container in bytes - deduct `INITCODE_WORD_COST * ((initcontainer_size + 31) // 32)` gas - deduct `GAS_KECCAK256_WORD * ((initcontainer_size + 31) // 32)` gas (hashing charge) - check that current call depth is below `STACK_DEPTH_LIMIT` and that caller balance is enough to transfer `value` @@ -146,7 +150,9 @@ Details on each instruction follow in the next sections. These steps are common for `EOFCREATE` and `TXCREATE`: -- execute the container in "initcode-mode" and deduct gas for execution +- caller's memory slice [`input_offset`:`input_size`] is used as calldata +- execute the container in "initcode-mode" and deduct gas for execution. The 63/64th rule from [EIP-150](./eip-150.md) applies. +- increment `sender` account's nonce - calculate `new_address` as `keccak256(0xff || sender || salt || keccak256(initcontainer))[12:]` - an unsuccesful execution of initcode results in pushing `0` onto the stack - can populate returndata if execution `REVERT`ed @@ -157,6 +163,7 @@ These steps are common for `EOFCREATE` and `TXCREATE`: - set `state[new_address].code` to the updated deploy container - push `new_address` onto the stack - `RETURN` and `STOP` are not allowed in "initcode-mode" (abort execution) +- "initcode-mode" *is not transitive* - it is only active for the frame executing the initcontainer. If another (non-create) call is made from this frame, it *is not* executed in "initcode-mode". #### `RETURNCONTRACT` @@ -244,6 +251,8 @@ function txcreate(a, b, c, d, e) -> f { ## Rationale +### Data section appending + The data section is appended to during contract creation and also its size needs to be updated in the header. Alternative designs were considered, where: - additional section kinds for the data were introduced @@ -251,11 +260,31 @@ The data section is appended to during contract creation and also its size needs - data section would be written over as opposed to being appended to, requiring it to be filled with 0 bytes prior to deployment All of these alternatives either complicated the otherwise simple data structures or took away useful features (like the dynamically sized portion of the data section). + +### `TXCREATE` + +An alternative design was discussed, where instead of `TXCREATE`, `InitcodeTransaction` and the Creator Contract, the legacy-like creation transactions (with empty `to`) continue to be available to send EOF initcontainers in transactions and perform deployment of EOF contracts. + +This makes it impossible for smart contract wallets to deploy arbitrary contracts (only EOAs can), which is a desired feature of current legacy creation rules. A workaround where those arbitrary contracts are first "uploaded" to a factory contract, and then deployed using `EOFCREATE`, is not satisfactory. + +### `TXCREATE` failure modes `TXCREATE` has two "light" failure modes in case the initcontainer is not present and in case the EOF validation is unsuccessful. An alternative design where both cases led to a "hard" failure (consuming the entire gas available) was considered. We decided to have the more granular and forgiving failure modes in order to align the gas costs incurred to the actual work the EVM performs. +### Creator Contract + EOF contract creation requires the Creator Contract be introduced via a state change, because neither legacy contracts nor create transactions can deploy EOF code. The alternative approach which was to continue using legacy creation would still rely on fetching the *initcode* from memory and not satisfy the requirement of code non-observability. +### EOF validation checking initcode-mode + +Extra EOF validation rules were considered: + +- Each EOF subcontainer must either be referenced by an `EOFCREATE` or a `RETURNCONTRACT` instruction, but never both +- Each EOF subcontainer may either contain `RETURNCONTRACT` or `RETURN` / `STOP` instructions, but never a mix of these two kinds +- A subcontainer referenced by an `EOFCREATE` must never contain a `RETURN` / `STOP` instruction, whereas a subcontainer referenced by a `RETURNCONTRACT` must never contain a `RETURNCONTRACT` + +These rules were not adopted to avoid the extra logic and complexity (esp. the last rule causes EOF validation of subcontainers to not be self-contained). + ## Backwards Compatibility This change poses no risk to backwards compatibility, as it is introduced at the same time EIP-3540 is. The new instructions are not introduced for legacy bytecode (code which is not EOF formatted), and the contract creation options do not change for legacy bytecode.