EIPs/EIPS/eip-1702.md

247 lines
9.6 KiB
Markdown

---
eip: 1702
title: Generalized Account Versioning Scheme
author: Wei Tang (@sorpaas)
discussions-to: https://github.com/sorpaas/EIPs/issues/2
status: Draft
type: Standards Track
category: Core
created: 2017-12-30
---
## Simple Summary
Introduce account versioning for smart contracts so upgrading the VM
or introducing new VMs can be easier.
## Abstract
This defines a method of hard forking while maintaining the exact
functionality of existing account by allowing multiple versions of the
virtual machines to execute in the same block. This is also useful to
define future account state structures when we introduce the on-chain
WebAssembly virtual machine.
## Motivation
By allowing account versioning, we can execute different virtual
machine for contracts created at different times. This allows breaking
features to be implemented while making sure existing contracts work
as expected.
Note that this specification might not apply to all hard forks. We
have emergency hard forks in the past due to network attacks. Whether
they should maintain existing account compatibility should be
evaluated in individual basis. If the attack can only be executed once
against some particular contracts, then the scheme defined here might
still be applicable. Otherwise, having a plain emergency hard fork
might still be a good idea.
## Specification
### Account State
Re-define account state stored in the world state trie to have 5
items: `nonce`, `balance`, `storageRoot`, `codeHash`, and
`version`. The newly added field `version` is a 256-bit **scalar**. We
use the definition of "scalar" from Yellow Paper. Note that this is
the same type as `nonce` and `balance`, and it is equivalent to a RLP
variable-sized byte array with no leading zero, of maximum length 32.
When `version` is zero, the account is RLP-encoded with the first 4
items. When `version` is not zero, the account is RLP-encoded with 5
items.
Account versions can also optionally define additional account state
RLP fields, whose meaning are specified through its `version`
field. In those cases, the parsing strategy is defined in "Additional
Fields in Account State RLP" section.
### Contract Execution
When fetching an account code from state, we always fetch the
associated version field together. We refer to this as the *code's
version* below. The code of the account is always executed in the
*code's version*.
In particular, this means that for `DELEGATECALL` and `CALLCODE`, the
version of the execution call frame is the same as
delegating/receiving contract's version.
### Contract Deployment
In Ethereum, a contract has a deployment method, either by a contract
creation transaction, or by another contract. If we regard this
deployment method a contract's *parent*, then we find them forming a
family of contracts, with the *root* being a contract creation
transaction.
We let a family of contracts to always have the same `version`. That
is, `CREATE` and `CREATE2` will always deploy contract that has the
same `version` as the *code's version*.
In other words, `CREATE` and `CREATE2` will execute the init code
using the current *code's version*, and deploy the contract of the
current *code's version*. This holds even if the to-be-deployed code
is empty.
### Validation
A new phrase, *validation* is added to contract deployment (by
`CREATE` / `CREATE2` opcodes, or by contract creation
transaction). When `version` is `0`, the phrase does nothing and
always succeeds. Future VM versions can define additional validation
that has to be passed.
If the validation phrase fails, deployment does not proceed and return
out-of-gas.
### Contract Creation Transaction
Define `LATEST_VERSION` in a hard fork to be the latest supported VM
version. A contract creation transaction is always executed in
`LATEST_VERSION` (which means the *code's version* is
`LATEST_VERSION`), and deploys contracts of `LATEST_VERSION`. Before a
contract creation transaction is executed, run *validation* on the
contract creation code. If it does not pass, return out-of-gas.
### Precompiled Contract and Externally-owned Address
Precompiled contracts and externally-owned addresses do not have
`version`. If a message-call transaction or `CALL` / `CALLCODE` /
`STATICCALL` / `DELEGATECALL` touches a new externally-owned address
or a non-existing precompiled contract address, it is always created
with `version` field being `0`.
### Additional Fields in Account State RLP
In the future we may need to associate more information into an
account, and we already have some EIP/ECIPs that define new additional
fields in the account state RLP. In this section, we define the
parsing strategy when additional fields are added.
* Check the RLP list length, if it is 4, then set account version to
`0`, and do not parse any additional fields.
* If the RLP list length more than 4, set the account version to the
scalar at position `4` (counting from `0`).
* Check version specification for the number of additional fields
defined `N`, if the RLP list length is not equal to `5 + N`,
return parse error.
* Parse RLP position `5` to `4 + N` as the meaning specified in
additional fields.
## Extensions
In relation to the above "Specification" section, we have defined the
base account versioning layer. The base account versioning layer is
already useful by itself and can handle most EVM improvements. Below
we define two specifications that can be deployed separately, which
improves functionality of base layer account versioning.
Note that this section is provided only for documentation
purpose. When "enabling EIP-1702", those extensions should not be
enabled unless the extension specification is also included.
- [44-VERTXN: Account Versioning Extension for Contract Creation
Transaction](https://specs.that.world/44-vertxn/)
- [45-VEROP: Account Versioning Extension for CREATE and
CREATE2](https://specs.that.world/45-verop/)
## Usage Template
This section defines how other EIP/ECIPs might use this account
versioning specification. Note that currently we only define the usage
template for base layer.
Account versioning is usually applied directly to a hard fork
meta. EIP/ECIPs in the hard fork are grouped by the virtual machine
type, for example, EVM and eWASM. For each of them, we define:
* **Version**: a non-zero scalar less than `2^256` that uniquely
identifies this version. Note that it does not need to be
sequential.
* **Parent version**: the base that all new features derived
from. With parent version of `0` we define the base to be legacy
VM. Note that once a version other than `0` is defined, the legacy
VM's feature set must be frozen. When defining an entirely new VM
(such as eWASM), parent version does not apply.
* **Features**: all additional features that are enabled upon this
version.
If a meta EIP/ECIP includes EIP/ECIPs that provide additional account state RLP
fields, we also define:
* **Account fields**: all account fields up to the end of this meta
EIP, excluding the basic 5 fields (`nonce`, `balance`,
`storageRoot`, `codeHash` and `version`). If EIPs included that are
specific to modifying account fields do not modify VM execution
logic, it is recommended that we specify an additional version whose
execution logic is the same as previous version, but only the
account fields are changed.
## Rationale
This introduces account versioning via a new RLP item in account
state. The design above gets account versioning by making the contract
*family* always have the same version. In this way, versions are only
needed to be provided by contract creation transaction, and there is
no restrictions on formats of code for any version. If we want to
support multiple newest VMs (for example, EVM and WebAssembly running
together), then this will requires extensions such as 44-VERTXN and
45-VEROP.
Alternatively, account versioning can also be done through:
* **[26-VER](https://specs.that.world/26-ver/)** and
**[40-UNUSED](https://specs.that.world/40-unused/)**: This makes an
account's versioning soly dependent on its code header prefix. If
with only 26-VER, it is not possible to certify any code is valid,
because current VM allows treating code as data. This can be fixed
by 40-UNUSED, but the drawback is that it's potentially backward
incompatible.
* **EIP-1891**: Instead of writing version field into account RLP
state, we write it in a separate contract. This can accomplish the
same thing as this EIP and potentially reduces code complexity, but
the drawback is that every code execution will require an additional
trie traversal, which impacts performance.
## Backwards Compatibility
Account versioning is fully backwards compatible, and it does not
change how current contracts are executed.
## Discussions
### Performance
Currently nearly all full node implementations uses config parameters
to decide which virtual machine version to use. Switching virtual
machine version is simply an operation that changes a pointer using a
different set of config parameters. As a result, this scheme has
nearly zero impact to performance.
### WebAssembly
This scheme can also be helpful when we deploy on-chain WebAssembly
virtual machine. In that case, WASM contracts and EVM contracts can
co-exist and the execution boundary and interaction model are clearly
defined as above.
## Test Cases and Implementations
To be added.
## References
The source of this specification can be found at
[43-VER](https://specs.that.world/43-ver/). This specification is
also realized in:
* Ethereum Classic Improvement Proposals as
[ECIP-1040](https://ecips.ethereumclassic.org/ECIPs/ecip-1040).
## Copyright
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).