Another concern is the interaction between validated and legacy EVM. There are two orthogonal concerns that create four situations. First is does the chain support validating code and the second is does the code expect to be validated.
The first case is what we have today, neither the chain nor the compiled code expects to be validated. This is the status quo.
Next let’s consider if the chain expects to validate contracts and all code is treated the same. In this case a lot of contracts that previously were deployable will no longer be deployable because of metadata such as the swarm hash of the code that was appended to the bytecode in a code section that will never be executed. Because it’s not following the conventions marking non-executable code the contract is rejected. This is bad, it would require all users to do a co-ordinated toolchain update of their build and deployment systems. This is orders of magnitude larger and has more existential risk than an ordinary fork. Consider that there are PDP-4 and Windows XP systems still in operation providing critical infrastructure to many businesses.
To maintain community compatibility we need to provide, at least for a little time, a way to still deploy non-validated EVM. The question is then how to mark when EVM code should be validated. One alternative is to introduce a new opcode to create validated contracts. This would keep the versioning information out of the stream of code. Considering that there are proposals to fundamentally redefine opcodes, such as redefining the number of stack items consumed by CALL series operations. Keeping the versioning information out of the stream of operations could make detecting EVM opcodes targeting this proposal could lead to execution confusion. Broadening our view we need to consider that EVM is becoming an ecosystem to it’s own. Multiple hyperledger projects support EVM based contract execution. Relying on an ethereum only way to identify the versioning would then result in these clients adopting different mechanisms to identify different versions of EVM code. Based on this concern I feel in-stream versioning is superior and will result in less ecosystem confusion.
Consider also that almost all other VM systems use a magic number header byte. Java has 0xCAFEBABE, wasm has ‘\0asm’, and even LLVM, the state of the art, uses ‘llvm’ at the start of it’s bytecode. Hence a ‘\0evm’ or '\xefevm` (0xef65766d) would align with current best practices. If a contract wants to be subject to validation (and gain access to future byte codes) it can compile itself as validated and use the header bytes. Older EVM code can be oblivious to this requirement.
So for the case of the blockchain that wants EVM code that is validated gating the new features off of a header validation byte would provide a means for old and new code to be added and executed simultaneously. For users who do not update their toolchain they will operate as normal.
There is on last case, for a blockchain that does not want to or know how to validate code, when presented EVM code that claims to be validatable. What happens then? And what if the code expects new semantics such as different stack counts for CALL and DELEGATECALL? Ideally we would not want such contracts to execute unless the blockchain supports those semantics. out of stream versioning does nothing in these cases when the evm code becomes separated from it’s versioning information. The two proposed headers for validated code would, in current implementations, fail to execute because the first operation would either be 0x00 which is STOP or 0xef which is an invalid opcode.
There is also the issue of code claiming to be validated code when it was deployed prior to fork validation. This is where account versioning provides it’s value. For account code the validated opcodes would require both the header and the account version, as already mentioned in the EIP.
So to summarize: pre-fork/v0 is fine. post-fork/v0 would execute just as pre-fork with opcodes that don’t require validation. Post fork/v1 would allow the version header, would run execution, and would unlock new opcodes in the validated contracts. Pre-fork/v1 should not exist and would be a consensus failure if a v1 account existed prior to account versioning. EVM code with the header would only execute in post-fork/v1 accounts or post-fork transactions (when executed out of the transaction).