Try   HackMD

CREATEF

In general, replace CREATE3/CREATE4 with CREATEF, where the same executing contract is used for initcode, but a different code section other than 0 is used.

Problem

Using the factory pattern will require two levels of nesting if done in a EOF container. First there is the executing container, then there is the container that holds the exec code, then there will be the deployed contract itself.

  +-----------------------------+
  | Factory Contract            |
  | +-------------------------+ |
  | | Child contract initcode | |
  | |      +----------------+ | |
  | |      | Child Contract | | |
  | |      +----------------+ | |
  | +-------------------------+ |
  +-----------------------------+

There will be three separate EOF headers to parse. Let's not forget, this also has to be deployed, so the master deployer will have at least 3 layers of nested contracts.

  +---------------------------------+
  | Factory Contract Deployer       |
  | +-----------------------------+ |
  | | Factory Contract            | |
  | | +-------------------------+ | |
  | | | Child contract initcode | | |
  | | |      +----------------+ | | |
  | | |      | Child Contract | | | |
  | | |      +----------------+ | | |
  | | +-------------------------+ | |
  | +-----------------------------+ |
  +---------------------------------+

Solution

Instead of going to a separate EOF container that contains initcode, the current container will contain the initcode at a different code setcion than the main entry point. The CREATEF call, instead of pointing to a subcointainer, will point to a code section to perform the pre-deployment initialization.

  +--------------------------------------+
  | Factory Contract                     |
  | sections 0-n Normal factory code     |
  | section  m   Child contract initcode |
  |                   +----------------+ |
  |                   | Child Contract | |
  |                   +----------------+ |
  +--------------------------------------+

This also allows for multiple contract to re-use subroutines from other initcode and the main factory code. A single CREATEF operation replaces CREATE3/CREATE4 and two return operations replace RETURNCONTRAcT, one referencing a EOF subcontainer index and one referening a hash of a container in the transaction body of a new transaction type.

  • CREATEF Operation
    • deduct 32000 gas
    • read uint8 operand initcodesection_index
    • pops value, salt, data_offset, data_size from the stack
    • deduct 8 * ((initcontainer_size + 31) // 32) gas (EIP-3860 + hashing charge)
    • calculate new_address as keccak256(0xff || sender || salt || inicodesection_index || keccak256(container))[12:]
    • Creates a new stack frame executing under the new address, but with the existing container. Execution starts with the first byte of the referened code section
    • an unsuccesful execution of initcode results in pushing 0 onto the stack
    • set state[new_address].code to the updated container
    • push new_address onto the stack
    • RETURN and STOP are not allowed (abort execution)
    • RETF at the top of the return stack is similarly not allowed
    • deduct 200 * deployed_code_size gas
    • if initcode container or deployed container is invalid, instruction’s execution ends with the result 0 pushed on stack. The caller’s nonce remains increased and all creation gas is deducted.

Instead of two create variants there are two contract return variants

  • RETURN_CONTRACT_INDEX instruction

    • loads uint8 immediate container_index
    • exceptional halt if the container does not have a subcontainer at that index
    • exceptional halt if subcontainer code is EOF invalid (unless we settle on deep validation for containers from an external source)
    • pops two values from the stack: aux_data_offset, aux_data_size
    • Appends the aux data to the subcontainer, and re-writes the header if needed to accomodate the added data
    • cost 0 gas + 1 byte per final contract size
    • instruction exceptionally aborts if invoked not in “initcode mode”
  • RETURN_CONTRACT_HASH instruction

    • pops three values from the stack: codehash, aux_data_offset, aux_data_size
    • Searches for code with the codehash in specified locations
      • For EOF1 this will be a new transaction type that has extra "data" fields that hold containers, like CREATE4
      • Account Abstraction systems can combine multiple creat calls into one TX without concern about the transaction indexes.
      • L2s/L3s and ZK systems may want to create a "library" of know contracts by hash, that are pre-loaded and pre-compiled.
    • exceptional halt if subcontainer code is EOF invalid (validation is always performed)
    • Appends the aux data to the subcontainer, and re-writes the header if needed to accomodate the added data
    • cost 0 gas + 1 byte per final contract size
    • instruction exceptionally aborts if invoked not in “initcode mode”

The two return operations could be combined if we added a magic rule that any return value with 30 or more leading zeros refers to a container index. Or if we also refered to the subcontainers by hash.