2019-01-15 23:15:25 +00:00
|
|
|
---
|
2019-01-15 23:19:13 +00:00
|
|
|
eip: 1702
|
2019-01-15 23:15:25 +00:00
|
|
|
title: Generalized Account Versioning Scheme
|
|
|
|
author: Wei Tang (@sorpaas)
|
2019-01-15 23:20:02 +00:00
|
|
|
discussions-to: https://github.com/sorpaas/EIPs/issues/2
|
2019-01-15 23:15:25 +00:00
|
|
|
status: Draft
|
|
|
|
type: Standards Track
|
|
|
|
category: Core
|
|
|
|
created: 2017-12-30
|
|
|
|
---
|
|
|
|
|
2019-04-03 12:35:14 +00:00
|
|
|
## Simple Summary
|
|
|
|
|
|
|
|
Introduce account versioning for smart contracts so upgrading the VM
|
|
|
|
or introducing new VMs can be easier.
|
|
|
|
|
2019-01-15 23:15:25 +00:00
|
|
|
## Abstract
|
|
|
|
|
2019-04-02 13:35:24 +00:00
|
|
|
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.
|
2019-01-15 23:15:25 +00:00
|
|
|
|
|
|
|
## Motivation
|
|
|
|
|
2019-04-02 13:35:24 +00:00
|
|
|
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.
|
2019-01-15 23:15:25 +00:00
|
|
|
|
2019-04-02 13:35:24 +00:00
|
|
|
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.
|
2019-01-15 23:15:25 +00:00
|
|
|
|
|
|
|
## Specification
|
|
|
|
|
|
|
|
### Account State
|
|
|
|
|
2019-04-02 13:35:24 +00:00
|
|
|
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 integer. 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.
|
2019-01-15 23:15:25 +00:00
|
|
|
|
2019-04-02 13:35:24 +00:00
|
|
|
### Contract Deployment
|
2019-01-15 23:15:25 +00:00
|
|
|
|
2019-04-02 13:35:24 +00:00
|
|
|
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.
|
2019-01-15 23:15:25 +00:00
|
|
|
|
2019-04-02 13:35:24 +00:00
|
|
|
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 calling `address`.
|
2019-01-15 23:15:25 +00:00
|
|
|
|
2019-04-02 22:46:15 +00:00
|
|
|
#### Alternative Design
|
|
|
|
|
2019-04-02 22:57:08 +00:00
|
|
|
This provides an alternative design that allows `CREATE`, `CREATE2`
|
|
|
|
and contract creation transaction to deploy contract whose version are
|
|
|
|
different.
|
2019-04-02 22:46:15 +00:00
|
|
|
|
|
|
|
The client maintains a mapping `V` of currently supported version
|
|
|
|
prefix (for example, `\0asm`) to `version` number. All version
|
|
|
|
prefixes have the invariant that given any prefix in mapping `a` and
|
2019-04-02 22:57:08 +00:00
|
|
|
`b`, `a` is not `b`'s prefix. Version numbers in `V` cannot be zero.
|
|
|
|
|
|
|
|
Apply the following cause on contract deployment for all `CREATE`,
|
|
|
|
`CREATE2` and contract deployment transaction.
|
|
|
|
|
|
|
|
* If the `version` of caller (determined by `I_a`) is zero, then
|
|
|
|
`CREATE` and `CREATE2` will always deploy contract with version zero.
|
|
|
|
* If the `version` of caller (determined by `I_a`) is not zero, do the
|
|
|
|
following checks and operations, and return out-of-gas if any of it
|
|
|
|
fails:
|
|
|
|
* Check that the code starts with an prefix in `V`, with `version`
|
|
|
|
number.
|
|
|
|
* Use `version`'s validation procedure to validate the *whole* code
|
|
|
|
(with prefix).
|
|
|
|
* Deploy the contract with `version`.
|
2019-04-02 22:46:15 +00:00
|
|
|
|
2019-04-02 13:35:24 +00:00
|
|
|
### Validation
|
2019-01-15 23:15:25 +00:00
|
|
|
|
2019-04-02 13:35:24 +00:00
|
|
|
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.
|
2019-01-15 23:15:25 +00:00
|
|
|
|
2019-04-02 13:35:24 +00:00
|
|
|
If the validation phrase fails, deployment does not proceed and return
|
|
|
|
out-of-gas.
|
2019-01-15 23:15:25 +00:00
|
|
|
|
2019-04-02 13:35:24 +00:00
|
|
|
### Contract Execution
|
2019-01-15 23:15:25 +00:00
|
|
|
|
2019-04-02 13:35:24 +00:00
|
|
|
VM version used in contract execution is determined via calling
|
2019-04-02 19:29:11 +00:00
|
|
|
`address` (`I_a` in yellow paper).
|
2019-01-15 23:15:25 +00:00
|
|
|
|
2019-04-02 13:35:24 +00:00
|
|
|
### 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`. Before a contract creation transaction is executed,
|
|
|
|
run *validation* on the contract creation code. If it does not pass,
|
|
|
|
return out-of-gas.
|
|
|
|
|
2019-04-02 22:46:15 +00:00
|
|
|
#### Alternative Design
|
2019-04-02 13:35:24 +00:00
|
|
|
|
|
|
|
This provides an alternative design that allows contract to be created
|
|
|
|
in multiple versions.
|
|
|
|
|
|
|
|
Add an additional field `version` (256-bit integer) in contract
|
|
|
|
creation transaction. So it becomes `nonce`, `gasprice`, `startgas`,
|
|
|
|
`to`, `value`, `data`, `v`, `r`, `s`, `version`. When signing or
|
|
|
|
recovering, sign ten items, with `v`, `r`, `s` as defined by EIP-155.
|
|
|
|
|
|
|
|
The transaction would be executed in `version` supplied. If `version`
|
|
|
|
is not supported or *validation* does not pass, return out-of-gas.
|
2019-01-15 23:15:25 +00:00
|
|
|
|
2019-04-02 19:29:11 +00:00
|
|
|
### 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`.
|
|
|
|
|
2019-04-03 12:35:14 +00:00
|
|
|
## Rationale
|
|
|
|
|
|
|
|
This introduces account versioning via a new RLP item in account
|
|
|
|
state. The first 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 requires alternative design in contract
|
|
|
|
creation transaction section
|
|
|
|
|
|
|
|
The second design above requires new versions of VMs follow a
|
|
|
|
formatting -- that it always has a prefix. In this way, the version
|
|
|
|
can be derived from the prefix, thus allowing a contract *family* to
|
|
|
|
have multiple versions. It also makes it so that we can pin contract
|
|
|
|
creation transaction using only one VM version, and it can deploy
|
|
|
|
other VM versions.
|
|
|
|
|
|
|
|
Alternatively, account versioning can also be done through:
|
|
|
|
|
|
|
|
* **EIP-1707** and **EIP-1712**: This makes an account's versioning
|
|
|
|
soly dependent on its code header prefix. If with only EIP-1707, it
|
|
|
|
is not possible to certify any code is valid, because current VM
|
|
|
|
allows treating code as data. This can be fixed by EIP-1712, 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.
|
|
|
|
|
2019-01-15 23:15:25 +00:00
|
|
|
## Discussions
|
|
|
|
|
|
|
|
### Performance
|
|
|
|
|
2019-04-02 13:35:24 +00:00
|
|
|
Currently nearly all full node implementations uses config parameters
|
2019-05-19 06:54:10 +00:00
|
|
|
to decide which virtual machine version to use. Switching virtual
|
2019-04-02 13:35:24 +00:00
|
|
|
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.
|
2019-01-15 23:15:25 +00:00
|
|
|
|
|
|
|
### WebAssembly
|
|
|
|
|
2019-04-02 13:35:24 +00:00
|
|
|
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.
|
2019-04-03 12:35:14 +00:00
|
|
|
|
|
|
|
## Test Cases and Implementations
|
|
|
|
|
|
|
|
To be added.
|