EIP-615: Subroutines and Static Jumps for the EVM

@chfast @veox @holiman @sorpaas @ajsutton @axic @expede

We’ve had a few days of discussion on this, and I think the upshot is that we need to solve the general versioning problem now. Wei Tang has a few proposals worth considering, plus the discussion so far has surfaced a number of problems and ideas.

For EIP-615 I think that the spec should just state that versioning is needed and require a wasm-style version header.

For a versioning solution I think work needs to continue on Wei Tang’s existing EIPs, or a new one that supersedes them. What do you think, @sorpass? And are people able to help?

EIP-1702: Generalized Account Versioning Scheme
EIP-1707: Use Version Byte Prefix for Contract Account Versioning
EIP-1891: Contract-based Account Versioning

I would of course prefer EIP-1891. That’s the best I can come up with so far, and what I really like about it is that it nicely solved many of the immutability / invariant issues, and in the mean time, doesn’t have all the complexity of adding another RLP field to state. I’m definitely biased so I would be really happy if someone can check whether I missed some important things.

The downside, as @gcolvin pointed out, is that only deployed contract will have versioning, while contract creation transaction will stuck at the legacy version. I don’t think this is an issue – most of contract creation transactions are just to emit the contract code. This might complicate deployment strategy (because it requires to call VCREATE and VCREATE2 instead of a plain contract creation transaction). But still, we can always introduce new transaction types in the future to make it easier.

I think I prefer a combination of 1707 and 1702. But there is too much I don’t understand about the requirements and the information available at deployment and runtime to be sure.

Personally I’d lean towards adding a field to the account state. I may be missing some complexities, but state fields were added as part of the state rent proof of concept I built and they were straight-forward to implement. The field in the account state feels like the right thing to do as it keeps all the account meta-data in one place.

The contract based versioning incurs additional overhead to walk the contract storage trie, plus the additional complexity of VCREATE & VCREATE2.

A possible problem with EIP-1702 is

When a version 0 account issues a CREATE, it always uses the newest version of the virtual machine, so it only creates version 1 new accounts.

But a version 0 contract is not likely to want to create version 1 contracts, it’s going to want to create version 0 contracts like it always did.

That’s why I’d prefer that version 0 accounts always create version 0 contracts, and later versions create the kind of contract indicated by the version header.

Yes, I’d agree with that change.

Yes @sorpaas correctly interpreted me. In a more general sense, the versioning scheme must be able to handle two different types of versionings, I’d like to call them declarations and certfications.

  • declaration: I am a contract of type X, want access to features Y,
  • certification: This contract is validated to comply with Z.

EIP-615 requires the versioning schema to handle certifications, and I assume ewasm will aswell. Whereas other new cool features may only need declarations. Declarations can be used to modify evm behaviour without breaking backward compatibility.

Regarding state field, my concern is about bloating the data size even more. Also, won’t adding a new field to the rlp require a full rehashing of the entire state trie at the fork-block?

1 Like

The declaration and certification is good description of this.
Yes, both Ewasm and EIP-615 require certification that moves some validity checks from execution time to deployment time. The code prefix with version does not work for this because you can bypass deployment-time certification.

We discussed some options internally. So far I don’t see any other promising solution than extending RLP of an account by an optional field with “code version”.

We want to do it in “dynamic” way so accounts’ RLP will contain either 4 or 5 items. For 4 items we assume code version 0. This removes the need of rehashing everything and saves some space (although I haven’t considered state size until today).

I was wanting both the version header (I am a contract of type asm.1.0.0) and the state field (I have been validated and deployed as asm.1.0.0). Is that what you had in mind @holiman?

If that’s the intention, then yes, that alleviates my concerns about malicious contracts.

However, if you want to enable 615-features without validation in a first step, then we’re back to the same problems again…(?)

If it will only be used when the certification is in place, then I guess the EIP needs a specification of the versioning scheme that it requires.

EIP-615 code has to be validated up front.

I don’t think this EIP should spec the versioning scheme, but it needs to refer to an EIP that does. From the last few messages EIP-1702 looks to be the best starting point, plus the version header taken from the Wasm spec.

Do you agree, @sorpass?

Just wonder, have you checked EIP-1891 where we can store it in contract storage?

I still hold some similar reservations as @holiman, that adding RLP item can complicate things (especially for big clients like geth and parity, where we (accidentally or on purpose) made assumptions that account RLP is 4-item). But anyway, It looks like going with an additional RLP field is the current rough consensus. I’ll try to finish updating the spec for EIP-1702 around tomorrow to fix some current issues @gcolvin and others pointed out.

@gcolvin Can you explain why you think version header is still necessary if we have RLP version field already?

So when bytecode is going onto the chain the header tells the client how to validate it, and when bytecode is off-chain the header tells tools how to handle it.

The new fields would be introduced “lazily”, i.e., the contracts that do not have the new field, are assumed pre-change. The old contracts would have 4 fields, whereas the new ones would have 5. This is my understanding

I see, but I think that’s rather up to each VM version to define how it wants to be handled. For the legacy VM version we cannot have any headers anyway, because otherwise it would be backward incompatible.

I updated EIP-1702 to include some of the above comments/suggestions: EIP-1702: Generalized Account Versioning Scheme by sorpaas · Pull Request #1702 · ethereum/EIPs · GitHub

It think it is up to the VM, and using the same scheme as Wasm makes sense to me.

This looks good, thanks. Shall I go ahead and merge it?

1 Like

The transaction would be executed in version supplied. If version
is not supported or validation does not pass, return out-of-gas.

I think the version needs to supplied by the VM during the validation phase.

I think that would still have the certification / validation issue. We may have innocent looking legacy code that just happen to have the header of a later VM. It would be better supply the version through external methods (an extra field in contract creation transaction or account state), and then in validation phrase, check whether the version provided in VM header matches.

How about this.

  • New contract creation transactions will use the new version item.
  • CREATE and CREATE2 will use the version from the caller’s state field or 0.
  • Versions above 0 are validated, which returns the version to deploy.
  • Validation may return a different version than it is given.
  • The deployed version is stored in the contract state.

So the VM should not be handed legacy code to validate, but remains free to use it’s internal versioning system as it will. If the validator does not override the input version the effect is the same as for your deployment families.

Yeah sounds like a good idea! As long as we assert that all non-legacy versions must contain a version prefix, and legacy VM can only deploy legacy version, then certification works. This will also mean that we can just make contract creation transaction always use one single version which simplifies things that need to change at that part. :slight_smile:

I added this in section “Contract Deployment” → “Alternative Design”.

1 Like