From 3c3f198be739784e5c0b525dedbc68be1d2380e1 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Thu, 4 Apr 2024 12:06:12 -0400 Subject: [PATCH 01/10] define initcode mode, require EOFCREATE to point to initcode, and RETURNCONTRACT to point to runtime code. --- spec/eof.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/spec/eof.md b/spec/eof.md index 069bc67..62d92f4 100644 --- a/spec/eof.md +++ b/spec/eof.md @@ -213,8 +213,7 @@ The following instructions are introduced in EOF code: - if `deployed_code_size > MAX_CODE_SIZE` instruction exceptionally aborts - 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". + - `RETURN` and `STOP` are not allowed in "initcode-mode" (see validation rules) - deduct `200 * deployed_code_size` gas - `RETURNCONTRACT (0xee)` instruction - loads `uint8` immediate `deploy_container_index` @@ -223,7 +222,7 @@ The following instructions are introduced in EOF code: - ends initcode frame execution and returns control to `EOFCREATE` caller frame (unless called in the topmost frame of a creation transaction). - `deploy_container_index` and `aux_data` are used to construct deployed contract (see above) - instruction exceptionally aborts if after the appending, data section size would overflow the maximum data section size or underflow (i.e. be less than data section size declared in the header) - - instruction exceptionally aborts if invoked not in "initcode-mode" + - instruction is not allowed in regular runtime code (see validation rules) - `DATALOAD (0xd0)` instruction - deduct 4 gas - pop one value, `offset`, from the stack @@ -289,10 +288,15 @@ The following instructions are introduced in EOF code: - the first code section must have a type signature `(0, 0x80, max_stack_height)` (0 inputs non-returning function) - `EOFCREATE` `initcontainer_index` must be less than `num_container_sections` - `EOFCREATE` the subcontainer pointed to by `initcontainer_index` must have its `len(data_section)` equal `data_size`, i.e. data section content is exactly as the size declared in the header (see [Data section lifecycle](#data-section-lifecycle)) +- `EOFCREATE` the subcontainer pointed to by `initcontainer_index` must be an "initcode" subcontainer, that is, it *must* contain a `RETURNCONTRACT` instruction. - `RETURNCONTRACT` `deploy_container_index` must be less than `num_container_sections` +- `RETURNCONTRACT` the subcontainer pointed to `deploy_container_index` must not be an "initcode" subcontainer, that is, it must not contain a `RETURNCONTRACT` instruction. - `DATALOADN`'s `immediate + 32` must be within `pre_deploy_data_size` (see [Data Section Lifecycle](#data-section-lifecycle)) - the part of the data section which exceeds these bounds (the `dynamic_aux_data` portion) needs to be accessed using `DATALOAD` or `DATACOPY` - no unreachable sections are allowed, i.e. every section is referenced by at least one non-recursive `CALLF` or `JUMPF`, and section 0 is implicitly reachable. +- whether or not a container is an "initcode" container is defined by whether or not it contains a `RETURNCONTRACT` instruction. +- a container contains "runtime" code if it is not an "initcode" container. +- it is an error for an "initcode" container to contain `RETURN` or `STOP`. in other words, it is an error for a container to contain both `RETURNCONTRACT` and either of `RETURN` or `STOP`. ## Stack Validation From b0abf79a0a09570925873d1de48394b6929c8958 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Thu, 4 Apr 2024 16:30:10 -0400 Subject: [PATCH 02/10] review: remove dead execution rules --- spec/eof.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec/eof.md b/spec/eof.md index 62d92f4..3db96da 100644 --- a/spec/eof.md +++ b/spec/eof.md @@ -213,7 +213,6 @@ The following instructions are introduced in EOF code: - if `deployed_code_size > MAX_CODE_SIZE` instruction exceptionally aborts - 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" (see validation rules) - deduct `200 * deployed_code_size` gas - `RETURNCONTRACT (0xee)` instruction - loads `uint8` immediate `deploy_container_index` @@ -222,7 +221,6 @@ The following instructions are introduced in EOF code: - ends initcode frame execution and returns control to `EOFCREATE` caller frame (unless called in the topmost frame of a creation transaction). - `deploy_container_index` and `aux_data` are used to construct deployed contract (see above) - instruction exceptionally aborts if after the appending, data section size would overflow the maximum data section size or underflow (i.e. be less than data section size declared in the header) - - instruction is not allowed in regular runtime code (see validation rules) - `DATALOAD (0xd0)` instruction - deduct 4 gas - pop one value, `offset`, from the stack From a143b31058df54df1fa0b3748b621815f4b5c1c8 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Thu, 4 Apr 2024 16:37:10 -0400 Subject: [PATCH 03/10] review: remove runtime code definition --- spec/eof.md | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/eof.md b/spec/eof.md index 3db96da..ec16712 100644 --- a/spec/eof.md +++ b/spec/eof.md @@ -293,7 +293,6 @@ The following instructions are introduced in EOF code: - the part of the data section which exceeds these bounds (the `dynamic_aux_data` portion) needs to be accessed using `DATALOAD` or `DATACOPY` - no unreachable sections are allowed, i.e. every section is referenced by at least one non-recursive `CALLF` or `JUMPF`, and section 0 is implicitly reachable. - whether or not a container is an "initcode" container is defined by whether or not it contains a `RETURNCONTRACT` instruction. -- a container contains "runtime" code if it is not an "initcode" container. - it is an error for an "initcode" container to contain `RETURN` or `STOP`. in other words, it is an error for a container to contain both `RETURNCONTRACT` and either of `RETURN` or `STOP`. ## Stack Validation From 803d088df70241dfa99bdf791abe0edd2b976036 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Thu, 11 Apr 2024 11:04:52 -0400 Subject: [PATCH 04/10] clarify no-returncontract initcode handling --- spec/eof.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/eof.md b/spec/eof.md index ec16712..06c2db2 100644 --- a/spec/eof.md +++ b/spec/eof.md @@ -286,9 +286,9 @@ The following instructions are introduced in EOF code: - the first code section must have a type signature `(0, 0x80, max_stack_height)` (0 inputs non-returning function) - `EOFCREATE` `initcontainer_index` must be less than `num_container_sections` - `EOFCREATE` the subcontainer pointed to by `initcontainer_index` must have its `len(data_section)` equal `data_size`, i.e. data section content is exactly as the size declared in the header (see [Data section lifecycle](#data-section-lifecycle)) -- `EOFCREATE` the subcontainer pointed to by `initcontainer_index` must be an "initcode" subcontainer, that is, it *must* contain a `RETURNCONTRACT` instruction. +- `EOFCREATE` the subcontainer pointed to by `initcontainer_index` must be an "initcode" subcontainer, that is, it *must not* contain either a `RETURN` or `STOP` instruction. it is allowed to not contain a `RETURNCONTRACT` instruction (that is, it may be terminated by `REVERT` or `INVALID`). - `RETURNCONTRACT` `deploy_container_index` must be less than `num_container_sections` -- `RETURNCONTRACT` the subcontainer pointed to `deploy_container_index` must not be an "initcode" subcontainer, that is, it must not contain a `RETURNCONTRACT` instruction. +- `RETURNCONTRACT` the subcontainer pointed to `deploy_container_index` must not be an "initcode" subcontainer, that is, it *must not* contain a `RETURNCONTRACT` instruction. - `DATALOADN`'s `immediate + 32` must be within `pre_deploy_data_size` (see [Data Section Lifecycle](#data-section-lifecycle)) - the part of the data section which exceeds these bounds (the `dynamic_aux_data` portion) needs to be accessed using `DATALOAD` or `DATACOPY` - no unreachable sections are allowed, i.e. every section is referenced by at least one non-recursive `CALLF` or `JUMPF`, and section 0 is implicitly reachable. From c2d0548e7ce7e914e576120f128259d530d9c832 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Thu, 18 Apr 2024 07:36:50 -0400 Subject: [PATCH 05/10] review comments update TXCREATE rules massage the verbiage around runtime vs initcode mode --- spec/eof.md | 13 ++++++++----- spec/eof_future_upgrades.md | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/spec/eof.md b/spec/eof.md index 06c2db2..22c50da 100644 --- a/spec/eof.md +++ b/spec/eof.md @@ -201,7 +201,7 @@ The following instructions are introduced in EOF code: - check call depth limit and whether caller balance is enough to transfer `value` - in case of failure returns 0 on the stack, caller's nonce is not updated and gas for initcode execution is not consumed. - 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 applies. + - execute the container and deduct gas for execution - 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 @@ -286,14 +286,17 @@ The following instructions are introduced in EOF code: - the first code section must have a type signature `(0, 0x80, max_stack_height)` (0 inputs non-returning function) - `EOFCREATE` `initcontainer_index` must be less than `num_container_sections` - `EOFCREATE` the subcontainer pointed to by `initcontainer_index` must have its `len(data_section)` equal `data_size`, i.e. data section content is exactly as the size declared in the header (see [Data section lifecycle](#data-section-lifecycle)) -- `EOFCREATE` the subcontainer pointed to by `initcontainer_index` must be an "initcode" subcontainer, that is, it *must not* contain either a `RETURN` or `STOP` instruction. it is allowed to not contain a `RETURNCONTRACT` instruction (that is, it may be terminated by `REVERT` or `INVALID`). +- `EOFCREATE` the subcontainer pointed to by `initcontainer_index` must be an "initcode" subcontainer, that is, it *must not* contain either a `RETURN` or `STOP` instruction. - `RETURNCONTRACT` `deploy_container_index` must be less than `num_container_sections` -- `RETURNCONTRACT` the subcontainer pointed to `deploy_container_index` must not be an "initcode" subcontainer, that is, it *must not* contain a `RETURNCONTRACT` instruction. +- `RETURNCONTRACT` the subcontainer pointed to `deploy_container_index` must be a "runtime" subcontainer, that is, it *must not* contain a `RETURNCONTRACT` instruction. - `DATALOADN`'s `immediate + 32` must be within `pre_deploy_data_size` (see [Data Section Lifecycle](#data-section-lifecycle)) - the part of the data section which exceeds these bounds (the `dynamic_aux_data` portion) needs to be accessed using `DATALOAD` or `DATACOPY` - no unreachable sections are allowed, i.e. every section is referenced by at least one non-recursive `CALLF` or `JUMPF`, and section 0 is implicitly reachable. -- whether or not a container is an "initcode" container is defined by whether or not it contains a `RETURNCONTRACT` instruction. -- it is an error for an "initcode" container to contain `RETURN` or `STOP`. in other words, it is an error for a container to contain both `RETURNCONTRACT` and either of `RETURN` or `STOP`. +- it is an error for a container to contain both `RETURNCONTRACT` and either of `RETURN` or `STOP`. +- for terminology purposes, the following concepts are defined: + - an "initcode" container is one which does not contain `RETURN` or `STOP` + - a "runtime" container is one which does not contain `RETURNCONTRACT` + - note a container can be both "initcode" and "runtime" if it does not contain any of `RETURN`, `STOP` or `RETURNCONTRACT` (for instance, if it is only terminated with `REVERT` or `INVALID`). ## Stack Validation diff --git a/spec/eof_future_upgrades.md b/spec/eof_future_upgrades.md index ee0820b..d5d0add 100644 --- a/spec/eof_future_upgrades.md +++ b/spec/eof_future_upgrades.md @@ -56,6 +56,7 @@ The [EIP-2718](https://eips.ethereum.org/EIPS/eip-2718) `ReceiptPayload` for thi - in addition to hashing charge as in `EOFCREATE`, deducts `2 * ((initcontainer_size + 31) // 32)` gas (EIP-3860 charge) - just before executing the initcode container: - **validates the initcode container and all its subcontainers recursively** + - validation includes checking that the container is an "initcode" container as defined in the validation section, that is, it does not contain `RETURN` or `STOP` - in addition to this, checks if the initcode container has its `len(data_section)` equal to `data_size`, i.e. data section content is exactly as the size declared in the header (see [Data section lifecycle](#data-section-lifecycle)) - fails (returns 0 on the stack) if any of those was invalid - caller’s nonce is not updated and gas for initcode execution is not consumed. Only `TXCREATE` constant, EIP-3860 gas and hashing gas were consumed From 1d25ab26d3e2c8715e1754da2321268416dc63f5 Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Thu, 16 May 2024 11:35:13 +0300 Subject: [PATCH 06/10] Validate that container in creation transaction is initcontainer --- spec/eof.md | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/eof.md b/spec/eof.md index 22c50da..70d9315 100644 --- a/spec/eof.md +++ b/spec/eof.md @@ -136,6 +136,7 @@ Creation transactions (tranactions with empty `to`), with `data` containing EOF - Find `intcontainer` size by reading all section sizes from the header and adding them up with the header size to get the full container size. 3. Validate the `initcontainer` and all its subcontainers recursively. - unlike in general validation `initcontainer` is additionally required to have `data_size` declared in the header equal to actual `data_section` size. + - validation includes checking that the container is an "initcode" container as defined in the validation section, that is, it does not contain `RETURN` or `STOP` 4. If EOF header parsing or full container validation fails, transaction is considered valid and failing. Gas for initcode execution is not consumed, only intrinsic creation transaction costs are charged. 5. `calldata` part of transaction `data` that follows `initcontainer` is treated as calldata to pass into the execution frame 6. execute the container in "initcode-mode" and deduct gas for execution From 436c1864835752f360df61d3476ab93e4e580b8d Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Tue, 21 May 2024 16:57:13 +0200 Subject: [PATCH 07/10] Fix indentation --- spec/eof.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/eof.md b/spec/eof.md index 70d9315..86d0dd1 100644 --- a/spec/eof.md +++ b/spec/eof.md @@ -135,8 +135,8 @@ Creation transactions (tranactions with empty `to`), with `data` containing EOF - Parse EOF header - Find `intcontainer` size by reading all section sizes from the header and adding them up with the header size to get the full container size. 3. Validate the `initcontainer` and all its subcontainers recursively. - - unlike in general validation `initcontainer` is additionally required to have `data_size` declared in the header equal to actual `data_section` size. - - validation includes checking that the container is an "initcode" container as defined in the validation section, that is, it does not contain `RETURN` or `STOP` + - unlike in general validation `initcontainer` is additionally required to have `data_size` declared in the header equal to actual `data_section` size. + - validation includes checking that the container is an "initcode" container as defined in the validation section, that is, it does not contain `RETURN` or `STOP` 4. If EOF header parsing or full container validation fails, transaction is considered valid and failing. Gas for initcode execution is not consumed, only intrinsic creation transaction costs are charged. 5. `calldata` part of transaction `data` that follows `initcontainer` is treated as calldata to pass into the execution frame 6. execute the container in "initcode-mode" and deduct gas for execution From dd66b17b2f0bb72953c2f7d447e9ad13eadecc52 Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Tue, 21 May 2024 16:57:28 +0200 Subject: [PATCH 08/10] Restore accidentally removed 63/64th rule mention --- spec/eof.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/eof.md b/spec/eof.md index 86d0dd1..8ef8af5 100644 --- a/spec/eof.md +++ b/spec/eof.md @@ -202,7 +202,7 @@ The following instructions are introduced in EOF code: - check call depth limit and whether caller balance is enough to transfer `value` - in case of failure returns 0 on the stack, caller's nonce is not updated and gas for initcode execution is not consumed. - caller's memory slice [`input_offset`:`input_size`] is used as calldata - - execute the container and deduct gas for execution + - execute the container and deduct gas for execution. The 63/64th rule from EIP-150 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 From 1475570f8b96958311ac95d9791578cc28a241a9 Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Tue, 21 May 2024 16:58:46 +0200 Subject: [PATCH 09/10] Remove initcode-mode mention from Creation transactions spec --- spec/eof.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/eof.md b/spec/eof.md index 8ef8af5..6280576 100644 --- a/spec/eof.md +++ b/spec/eof.md @@ -139,7 +139,7 @@ Creation transactions (tranactions with empty `to`), with `data` containing EOF - validation includes checking that the container is an "initcode" container as defined in the validation section, that is, it does not contain `RETURN` or `STOP` 4. If EOF header parsing or full container validation fails, transaction is considered valid and failing. Gas for initcode execution is not consumed, only intrinsic creation transaction costs are charged. 5. `calldata` part of transaction `data` that follows `initcontainer` is treated as calldata to pass into the execution frame -6. execute the container in "initcode-mode" and deduct gas for execution +6. execute the container and deduct gas for execution 1. Calculate `new_address` as `keccak256(sender || sender_nonce)[12:]` 2. A successful execution ends with initcode executing `RETURNCONTRACT{deploy_container_index}(aux_data_offset, aux_data_size)` instruction (see below). After that: - load deploy-contract from EOF subcontainer at `deploy_container_index` in the container from which `RETURNCONTRACT` is executed @@ -147,7 +147,6 @@ Creation transactions (tranactions with empty `to`), with `data` containing EOF - let `deployed_code_size` be updated deploy container size - if `deployed_code_size > MAX_CODE_SIZE` instruction exceptionally aborts - set `state[new_address].code` to the updated deploy container - 3. `RETURN` and `STOP` are not allowed in "initcode-mode" (abort execution) 7. deduct `200 * deployed_code_size` gas **NOTE** Legacy contract and legacy creation transactions may not deploy EOF code, that is behavior from [EIP-3541](https://eips.ethereum.org/EIPS/eip-3541) is not modified. From d891258c231ac1f897e33bc9bcbe66e539da5020 Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Tue, 21 May 2024 17:00:17 +0200 Subject: [PATCH 10/10] Fix indentation consistency --- spec/eof.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/eof.md b/spec/eof.md index 6280576..7d61e67 100644 --- a/spec/eof.md +++ b/spec/eof.md @@ -294,9 +294,9 @@ The following instructions are introduced in EOF code: - no unreachable sections are allowed, i.e. every section is referenced by at least one non-recursive `CALLF` or `JUMPF`, and section 0 is implicitly reachable. - it is an error for a container to contain both `RETURNCONTRACT` and either of `RETURN` or `STOP`. - for terminology purposes, the following concepts are defined: - - an "initcode" container is one which does not contain `RETURN` or `STOP` - - a "runtime" container is one which does not contain `RETURNCONTRACT` - - note a container can be both "initcode" and "runtime" if it does not contain any of `RETURN`, `STOP` or `RETURNCONTRACT` (for instance, if it is only terminated with `REVERT` or `INVALID`). + - an "initcode" container is one which does not contain `RETURN` or `STOP` + - a "runtime" container is one which does not contain `RETURNCONTRACT` + - note a container can be both "initcode" and "runtime" if it does not contain any of `RETURN`, `STOP` or `RETURNCONTRACT` (for instance, if it is only terminated with `REVERT` or `INVALID`). ## Stack Validation