Design of a forward-compatible EVM that will not break contracts when applying feature upgrades.
Forward-compatible EVM proposals are based on the observations that currently most hard fork changes we want to adopt mainly results in backward compatibilty issues in two categories:
Opcode Addition: Appending a new opcode to the insturction list can break past contract’s assumption of unused/invalid opcodes.
Gas Repricing: Nearly all Ethereum contracts on-chain currently make at least some assumptions about gas costs. Gas repricing can break those assumptions.
If unused opcodes can break backward compatibility, we only need to disallow deployment of unused opcodes to ensure forward compatibility. As a result, the proposal introduce a new validation process upon any contract deployment.
Upon contract deployment, either through CREATE and CREATE2 opcode, or via contract creation transaction, run an extra validation step:
Iterate over the code bytes one by one.
If the code byte is a
PUSH(n)opcode, skip next n bytes.
If the code byte is a valid opcode or designated invalid instruction (
Otherwise, throw out-of-gas.
For any new additional opcode deployed, they should be added to the
valid opcode list, and subject to the check described in the
specification. Even if the new opcode is a multi-byte or
special-instruction opcode (for example
specification ensures that it is forward-compatible with them. In
other words, new opcodes can modify the validation step as described
in specification, while have guarantees that no past instance of the
opcode has been deployed.
Core developers have long expressed their concerns that contracts
should not make any assumptions about gas cost. As a result, the EVM
itself should not make available any observables related to gas
cost. In particular,
When deployed together with
GAS should be
subject to the unused opcode check prior to contract deployment.
|See Leaky Abstraction of Gas for rationale of this specification.|
This removes gas observables in EVM as mechanisms of execution. It also provides a better error handling model, which significantly simplifies the threat model of smart contract developers, discussed as part of Error Handling.
Change the current EVM error types into the following:
Recoverable Error: An explicit
REVERTopcode. This error will be reported back to parent execution frame. It refunds remaining gases, but revert all changes in current execution frame.
Unrecoverable Error: Fatal error. Consume all gases, revert all changes in current transaction, and exit.
When an "out-of-gas" error happens in current execution frame, treat
it as unrecoverable error. The behavior of
REVERT opcode remains
unchanged, and it remains a recoverable error.
gas parameter is removed (opcode will pop one less item from
stack). Instead, the opcode will operate as if that parameter is set
to the current available gas \(\mu_g\).
When deployed together with account versioning, the fatal error behavior should be preserved. If current execution frame has this specification applied, then "out-of-gas" should always result in full revert of current transaction, regardless of whether parent execution frame is of legacy version or not. If child execution frame is of legacy version, its out of gas error should remain the old behavior and be passed to parent execution frame.