Title: EIP_7873__EOF___TXCREATE_and_InitcodeTransaction_t
Category: EIPs

Author: gumb0
Date: 2025-02-04T11:46:34.988Z

This is the discussion topic for EIP-7873: EOF - TXCREATE and InitcodeTransaction type

Author: cameel
Date: 2025-02-05T20:39:28.551Z

There is one thing I’m missing in the EIP’s rationale - what would be the downside to having both an EOF creation transaction and InitcodeTransaction? An obvious upside I see would be that it would remove the need to have a predeployed creation contract.
Alternatively, an InitcodeTransaction transaction with empty to could be special-cased to deploy the attached initcontainer, taking salt and constructor arguments from calldata, just like a predeployed contract would, but without the awkwardness of having to assign it an address and deploy it during a network upgrade.
I actually initially expected InitcodeTransation to be a such a specialized creation transaction but after reading the EIP I see that it’s more of a generalization of the standard transaction type. It’s not even required to use TXCREATE and deploy any of its initcontainers, which means that one could use it for arbitrary calls to EOF contracts. If the requirement to carry at least one initcontainer was relaxed it could be seen simply as an “EOF transaction” with deployment being a special case.

Author: gumb0
Date: 2025-02-06T15:22:06.681Z

cameel:

Alternatively, an InitcodeTransaction transaction with empty to could be special-cased to deploy the attached initcontainer, taking salt and constructor arguments from calldata, just like a predeployed contract would, but without the awkwardness of having to assign it an address and deploy it during a network upgrade.


This is an interesting idea, the main tradeoff here would be between the complexity of predeployment (done once at fork transition), and complexity of extra feature of the transaction, that has to stay forever, and after transition is actually redundant, because the same can be achieved with non-empty-to InitcodeTransaction after Creator Contract is deployed.
Additionaly, with such transaction it still would be required to use “Nick’s method” or similar hacks to deploy the Creator Contract in a cross-chain-safe manner, but one of the goals that EOF deployment design is trying to achieve is make such hacks unnecessary.

Author: pdobacz
Date: 2025-02-20T10:53:02.815Z

Additionaly, with such transaction it still would be required to use “Nick’s method” or similar hacks to deploy the Creator Contract in a cross-chain-safe manner

I’ll add to this that it was noted in this comment, that Nick’s method doesn’t offer cross-chain deployments universally, not only is a hack.
Actually, do I understand correctly that to be cross-chain Nick’s method requires to use a pre-155 tx, thereby is not possible to use an InitcodeTransaction type at all?

Author: jochem-brouwer
Date: 2025-03-27T18:01:26.114Z

We should not use type 0x05 for this transaction type. It is used as MAGIC for signing authorities in EIP-7702: Set EOA account code. (Better be safe than sorry)
Side-note, we should maybe create an informational EIP on all the “magic” first bytes which are used within our ecosystem. There’s also 0x19 ERC-191: Signed Data Standard but it will take some time before we hit that transaction type

Author: jochem-brouwer
Date: 2025-03-27T18:38:08.845Z

I am confused by the motivation of this EIP. In the current “Mega EOF” we can create EOF contracts “normally” by providing an EOF container with valid initcode to any tx with to: null. It should RETURNCONTAINER and then deploy one of the subcontainers in the calldata - right? Why do we need a new tx type? And what features does this bring which we don’t already have?

Author: gumb0
Date: 2025-03-28T16:44:47.260Z

No, EOF Creation Transaction is not going to be part of Complete EOF and is removed in devnet-1.
TXCREATE supersedes it, it’s a cleaner solution and provides extra flexibility and features, such as determenistic deployment address (not depending on nonce), and ability for smart contract wallets to deploy contracts from initdata in transaction.
Sorry for the confusion, some adjustments in EIPs are still underway.

Author: jochem-brouwer
Date: 2025-04-01T00:30:23.414Z

I did not realize that the deployments of EOF contracts currently (without TXCREATE) does not allow contract factories, since it cannot read containers from calldata. This is solved by TXCREATE and indeed makes a lot of sense. Thanks! (Would indeed be great if this would be motivated in the EIP such that it is clear what the goal of TXCREATE is → for instance, reading containers from tx “calldata” (but yes now a new field)).
I see that the current EIP has an “irregular state transition” to create the contract factory. Because we did not do this irregular state transition for other system-like contracts I think this will get a pushback. I can understand the reasoning, we have a way to create deterministic contracts on other networks, but this is bound by gasPrice so on networks with high gas price (or more accurate: high base fee) it could be impossible to submit this tx. However I think that this is still reasonable, because this deployment is only necessary on live networks, and new networks should “just” put this address in the prestate.

Author: gumb0
Date: 2025-04-01T16:27:37.686Z

The rationale for predeploying Creator Contract is that without EOF Creation Transaction (removed from the spec) there is no other way to deploy the very first EOF contract.

Author: pdobacz
Date: 2025-04-03T08:32:12.473Z

There was a discussion during EOF Implementers call around whether the Creator Contract should be a predeploy or a precompile. Posting takeaways for visibility and record.
Predeploy seems to have lead, pros:

feels like a cleaner solution, more auditable, common EVM code for all clients
no need to derive a gas schedule - gas charged according to EVM rules
can be EXTDELEGATECALLed without exceptions to the rules
a precompile making a sub-call (to the initcode) would be something new

Cons:

clients need to find a way to introduce that account into the state at fork transition block

Author: jochem-brouwer
Date: 2025-04-03T09:25:45.424Z

I’m assuming TXCREATE is banned in legacy contracts? I was thinking along the lines “why didn’t we do this predeploy” then also for system contracts as 7002 and 7251, but this case is special since we have to deploy an EOF contract which cannot be done via txs and not be done via CREATE(2). So the choice between using a precompile (which is essentially a predeploy but now of non-EVM code) or predeploy seems rather clear to me: use the predeploy because of native EVM code (we want to move precompiles also to EVM EIP-7666: EVM-ify the identity precompile).
I would suggest in the EIP to make it very clear how to compile the solidity source code such that it stays reproducible (also in a year or two). For that, also include the resulting bytecode of the compilation (so the EOF container)

Author: pdobacz
Date: 2025-04-03T10:43:16.647Z

jochem-brouwer:

I’m assuming TXCREATE is banned in legacy contracts?


Wait, maybe I’m missing something, but this is actually a brilliant idea hidden there - allow TXCREATE in legacy contracts. This relieves us from the need for the Creator Contract and seems to have nothing blocking it (no immediates, no code-introspection). The Creator Contract can still be reasonably well deployed to chains using Nick’s method, or CreateX’s method. If desired to be introduced as a predeploy at a distinguished address, that still can be done, but isn’t necessary for EOF to bootstrap.
Let us analyze this possibility.

Author: jochem-brouwer
Date: 2025-04-03T10:57:41.775Z

I assumed that it would be banned in legacy contracts because it could technically change existing contracts, and stuff like RETURNDATALOAD is also not included in legacy contracts.
But yeah I guess this solves the “chicken and egg” problem.
Another question, why does TXCREATE pop a tx_initcode_hash from stack? I thought the idea was that we cannot do code introspection, so we need a new tx type where the tx initcode is now “hidden” from the EVM. But now it technically is not, because I can for instance create a InitcodeTransaction where the calldata equals the initicode at index 0. Now to get the initcodehash I hash the calldata and then perform a TXCREATE. If it succeeds, I know I had the right hash, and therefore I now have access to the initcode?
Why is this hash popped from the stack and not the index of the initcode I want to deploy?
Also, there is this in the abstract:

EVM Object Format (EOF) removes the possibility to create contracts using creation transactions (with an empty to field), CREATE or CREATE2 instructions.

I read this as when EOF is introduced, it is now not possible to create contracts via to: null, CREATE or CREATE2. I’m assuming this is incorrect and that this only applies to not being able to create EOF contracts? (So in the context of EIP-3541: Reject new contract code starting with the 0xEF byte ?)

Author: pdobacz
Date: 2025-04-03T11:16:10.327Z

jochem-brouwer:


EVM Object Format (EOF) removes the possibility to create contracts using creation transactions (with an empty to field), CREATE or CREATE2 instructions.

I read this as when EOF is introduced, it is now not possible to create contracts via to: null, CREATE or CREATE2. I’m assuming this is incorrect and that this only applies to not being able to create EOF contracts?


It is correct, but maybe a tiny bit of an unfortunate wording there. EOF contracts cannot have a CREATE and CREATE2 instruction, so are not able to use these to create EOF or legacy contracts alike. to: null transactions with EOF initcode used to fail on 1st byte and after EOF fork transition they will continue to fail (assuming no EIP-7698), so that also makes it impossible for such transactions to create EOF or legacy code (that’s assuming TXCREATE is banned in legacy, ofc).
Maybe the misunderstanding comes from “EOF removes” - this should be read as “EOF contracts do not have the ability to create contracts using CREATE/CREATE2, as banned by 7620, and EOF fork upholds the lack of ability of to: null transactions to create EOF contracts, as granted by EIP-3541, or run EOF initcode”. It should not be read as “At EOF fork transition, all contract creation using to: null, CREATE, CREATE2 is removed”, which it may sound like.

Author: pdobacz
Date: 2025-04-03T21:16:48.365Z

As a by-product of the above exchange of posts (kudos to Jochem again for sparking an idea), there is a proposal to significantly simplify the EIP: Update EIP-7873: unban TXCREATE in legacy EVM for bootstrapping by pdobacz · Pull Request #9593 · ethereum/EIPs · GitHub

Author: pdobacz
Date: 2025-04-08T09:49:24.107Z

jochem-brouwer:

Another question, why does TXCREATE pop a tx_initcode_hash from stack? I thought the idea was that we cannot do code introspection, so we need a new tx type where the tx initcode is now “hidden” from the EVM


Sorry about late reply. Removing code introspection is most important with regards to code which exists on chain. TXCREATE mechanism still doesn’t allow you to modify the code within the EVM. At most you could analyze it and reject it using the approach you listed, or, but that seems prohibitively expensive, supply multiple initcodes, and choose one to deploy based on some EVM logic.
So I suppose TXCREATE “hiding” of initcode could also be realized by, instead of a dedicated tx field, in a way such that initcode was pointed to by an offset and size in tx’s calldata (and a hash for trust-less deterministic setups!), but that’s just an ugly hack (what if TXCREATE happens in a nested CALL? cannot use that call’s calldata, but “origin calldata”, ugh).
Lastly, using tx_initcode_hash instead of tx_initcode_index is precisely useful for deterministic deployment setups (counterfactual deploys, AA deploys too I guess), so that they can be opt-in rather than default.

Author: frangio
Date: 2025-04-10T18:50:15.754Z

Is there a reason why this restriction shouldn’t be lifted?


InitcodeTransaction is invalid if the to is nil.


InitcodeTransactions with to: null that invoke TXCREATE and don’t deposit any code could be a good way to deploy EOF contracts. In particular, it doesn’t rely on preexisting TXCREATE factories.
We need a standard recommendation for how EOF contracts should be deployed and I don’t think it should rely on ERC factories. As it stands there is no standard deployment procedure, no standard way for tools to fetch the address of deployed contracts (contractAddress in tx receipts is no longer useful), I think this is pretty bad.

Author: shemnon
Date: 2025-04-10T19:48:14.535Z

We can look into it for sure.  Some of the deeper TXCREATE work stalled a year ago when TXCREATE and the InitcodeTransaction was removed from pectra scope. I think this was the question we were working on when it was shelved. There are some things to work out however:

Would we allow only one initcode?
If we allow multiple initcodes, would only the first be executed?

This would preclued a “all initcode must be ordered by hash” rule, but I feel all we need to avoid that is a reason why order is important, like this.


Entire TX fails if initcode[0] is invalid, otherwise validity of other initcodes doesn’t matter.

This could be viewed as a natural side effect of attempting to execute it


data will become calldata to an initcode

This preserves a EIP-7620 behavior where the data after the container became call-data



@pdobacz proposed something simple like
if tx.to is null:
  assert len(initcodes) == 1
  run(initcodes[0])

Although I might make the assert >= instead of ==, but weakly held.

Author: pdobacz
Date: 2025-04-10T20:08:02.238Z

assert len(initcodes) == 1 is just to do away with all the edge cases, especially the need to sort that list. Can be also a tx validity rule, but that needs some consideration. Yes, tx.data becomes calldata of the initcodes[0] execution. The hashing scheme would be that of legacy creation tx.
Big question then - what about TXCREATE in legacy EVM?

Author: shemnon
Date: 2025-04-10T20:18:40.890Z

pdobacz:

The hashing scheme would be that of legacy creation tx.


Meaning nonce driven address?
  contract_address = keccak256(rlp.encode([address, nonce]))[-20:]
  increment_account_nonce()

Author: pdobacz
Date: 2025-04-10T20:27:50.890Z

Yes, in absence of a non-hacky way to supply salt, unless we have an idea

Author: frangio
Date: 2025-04-10T21:24:12.925Z

Oh, implicitly executing one of the containers in the transaction is not what I had in mind.
I was just suggesting to have InitcodeTransaction with to = null behave exactly the same as the current transaction types, i.e., the data is executed as legacy EVM bytecode. This allows one to execute code that uses TXCREATE to  deploy one of the init containers included in the transaction, without returning anything so that no code is deposited (in fact, it could conclude with a call to selfdestruct ).
I’d agree that this is… ugly.
We could also do something like when to = null the transaction data is interpreted as parameters to a TXCREATE-like operation that would get implicitly executed. This way we avoid messing with legacy code, and we have a clear thing to include in contractAddress in the receipt.
So a tx with to = null, initcodes = [...], and data = <tx_initcode_hash> || <salt> || <input...>  would have the same effect as TXCREATE executed in the context of the calling account, the value parameter is taken from the transaction. (Edit: I realize now that this is very similar to what the creator contract used to do, lol.)

Author: frangio
Date: 2025-04-10T21:38:35.377Z

Separate question: Am I reading the specs right that initcode container validation on TXCREATE is not metered? That seems intuitively wrong, shouldn’t there be an additional gas cost proportional to the size of the container? (Minus data sections… perhaps the complexity of that is the reason why it isn’t charged? I could see that being charged initially and then refunded.)

Author: pdobacz
Date: 2025-04-11T07:19:40.463Z

Since the initcode needs to be paid for (at a high rate) from the intrinsic tx cost, and cannot be manipulated by the EVM, it was decided not to charge extra for simplicity, but also to reflect the notion that clients will only do that once per tx (and cache results). I’m personally not 100% sold on this, but it makes sense in a way.

Author: pdobacz
Date: 2025-04-15T08:31:16.303Z

Here is a pre-read doc concerning EOF contract creation proposals: https://notes.ethereum.org/@ipsilon/EOF-bootstrapping
Current status (EIP-7873 with legacy EVM code enabling TXCREATE opcode) is good, but there was feedback that some features would still be nice to have and there are alternatives to consider. The doc attempts to gather these in one spot and list their differences. We’ll discuss this in depth on the next EOF implementers call this Wednesday

Author: shemnon
Date: 2025-04-22T15:44:11.821Z

There is no need to change the semantics of Type 0,1, and 2 transactions to make them invalid if they start with EF.  This will cause unneeded changes to how blobk builders have to handle existing transacitons.  We should keep the existing behavior in that type 0,1, and 2 transactions never parse their bodies into EOF containers and just execute when in contract creation mode.
Here’s a PR to effect that change: Update EIP-7873: Handling of EOF containers in existing TX types. by shemnon · Pull Request #9669 · ethereum/EIPs · GitHub

Author: pdobacz
Date: 2025-04-22T15:53:09.098Z

This will cause unneeded changes to how blobk builders have to handle existing transacitons

Are we 100% sure this is an issue? This rule (invalidating to: nil & data: EF00... has been in the specs accompanying TXCREATE since a long time, but no issues were raised until now.
I suggest we start with a Rationale subsection to elaborate on the alternatives and decision taken. Somewhere else you said the main issue you see is invalidating txs which are already in the mempool - but doesn’t that happen already with other upgrades, e.g. EIP-7623?

never parse their bodies into EOF containers and just execute when in contract creation mode

If we end up with deciding that yes, that is an issue, how about an alternative that instead of proceeding to execute the 0xEF the execution just doesn’t start, leaving only the intrinsic TX gas cost consumed? I.e. like if that tx was sent to an address without code.
The currently specced mechanism aims to serve 2 purposes:
1/ stop EOF code from executing in contexts where it is invalid, and do so early on, to not have to rely on checks which run later. At one point you just want the EVM to choose legacy vs EOF path based on the 0xef00 prefix alone.
2/ not punish too hard on a common and easy to detect user mistake, which is sending valid EOF down legacy creation pipelines
The alternative rule could cater for that

Author: shemnon
Date: 2025-04-22T16:07:44.017Z

pdobacz:

Are we 100% sure this is an issue? This rule (invalidating to: nil & data: EF00... has been in the specs accompanying TXCREATE since a long time, but no issues were raised until now.


I’m sure of this. While it may have been in the spec a while, it’s impact was eclipsed by EIP-7698 where the EOF containers were parsed, and it wasn’t until fairly recently that removing EIP-7698 was part of EOFv1.  Now that we are moving into implementation we are understanding the impact in ways that were not readily apparent. We can still change the spec, it is not finalized.



 pdobacz:

I suggest we start with a Rationale subsection to elaborate on the alternatives and decision taken.


We need to move quickly on this.  Insisting on a long process will cause us to miss a key delivery window.



 pdobacz:

Somewhere else you said the main issue you see is invalidating txs which are already in the mempool - but doesn’t that happen already with other upgrades, e.g. EIP-7623?


Those changes are related to the transaction types they occur within, and TX pools already check the costing.  That EIP was just a parameter and formula change to something the TXes were doing anyway.  This change is not related to the transactions it is impacting and is only present for aesthetics.  It is unneeded and we can cut it to make block builders jobs easier.



 pdobacz:

1/ stop EOF code from executing in contexts where it is invalid, and do so early on, to not have to rely on checks which run later. At one point you just want the EVM to choose legacy vs EOF path based on the 0xef00 prefix alone.


That is why the tag starts with the “invalid” opcode.  Running it as uncontained code.  It’s not a check that runs later, it’s how the EVM works.



 pdobacz:

2/ not punish too hard on a common and easy to detect user mistake, which is sending valid EOF down legacy creation pipelines


This places a greater burden on infrastructure for things that dev tooling (like hardhat and foundry) will solve for the typical used.



 pdobacz:

The alternative rule could cater for that


Reducing the scoped of actors that need to change to handle EOF is a better rule to cater to.

Author: pdobacz
Date: 2025-04-22T16:32:43.203Z

shemnon:




 pdobacz:

I suggest we start with a Rationale subsection to elaborate on the alternatives and decision taken.


We need to move quickly on this. Insisting on a long process will cause us to miss a key delivery window.


Let’s have a Rationale section entry regardless of everything, you have the contents already, just need to put it in the PR. Avoiding the need to endlessly look for past decisions’ rationales will make us quick.



 shemnon:

That is why the tag starts with the “invalid” opcode. Running it as uncontained code. It’s not a check that runs later, it’s how the EVM works.


Before you get to the point of running into an “invalid” opcode, you need to know if the EF00... code should be parsed as EOF and executed (b/c it’s an account being called or TXCREATE initcode or EOFCREATE initcontainer) or not (b/c it’s in creation tx data or CREATE/CREATE2 initcode). At one point the EVM needs to check and decide, this way or the other.
Not that it is a blocker to your change, just flagging.