Impressions on Metropolis
Sometimes I’m asked about the Metropolis release. The list of Metropolis EIPs looks stable already. I’m sharing how I read them, but I’m just rambling. For the precise understanding, please go to the EIP texts.
EIP-86 Abstraction of transaction origin and signature
Probably the deepest change in the Metropolis release is this “account abstraction”. Currently, every Ethereum transaction is signed by a private key holder of a single account. This EIP changes that. A special address 0xffffff..ff (called NULL_SENDER) will be a publicly-available transaction sender, and anybody can send a transaction from this special address without using a private key, although it’s up to miners whether they include the transaction. That’s the basic idea, but it leads to some further changes. So far Ethereum has treated nonces and balances under the assumption that accounts are held and controlled by somebody or some code, but now we have an exception (and the exception might become the norm).
Currently, every transaction contains a nonce, which must coincide with the nonce of the sender account. Whenever a transaction is in a block, the nonce of the sender account is incremented. This prevents the same transaction to be included in the block more than once or out-of-order. However, if we keep using the same mechanism for the NULL_SENDER, we would get a racing problem. Everybody trying to use NULL_SENDER would compete for the current nonce value. For preventing that, the new NULL_SENDER transactions always contain zero as the nonce.
Also, currently, the signer of the transaction always pays for the transaction. NULL_SENDER should not pay for the gas lest everybody will rush to NULL_SENDER trying to be the first to use its balance for paying for gas. For preventing that, the new NULL_SENDER transactions are required to contain zero as the gas price.
With these changes, any ETH balance on NULL_SENDER would be up-for-grabs. However, the EIP also specifies that the NULL_SENDER transactions need to specify zero as the transferred amount. So, I think there will be no way to spend the balance of NULL_SENDER (of course, except, coming up with a private key for this address). In contrast, ERC20 tokens held by NULL_SENDER would be up-for-grabs. Everybody can transfer such tokens “on behalf of” NULL_SENDER to whichever account.
Since the nonce and gas mechanisms are not available for the NULL_SENDER, the miners are incentivized not to include NULL_SENDER transactions unless there is something special about the transactions. Maybe the transactions result in balance increases of the miner, or the transactions come from friends of the miner.
The effects are profound. The disruption is already felt before a block is formed. The clients cannot rely on the sender information when they relay or drop NULL_SENDER transactions (by default, the clients are supposed to drop all NULL_SENDER transactions). There must be a mechanism to prevent a NULL_SENDER transaction to be duplicated into blocks. All of these are now off-loaded from the protocol to the client implementors and Ethereum contracts. So, when NULL_SENDER transactions occupy a considerable percentage of the Ethereum transactions, the Etheruem protocol will have successfully delegated the external user authentication to local conventions set up by some miners and some smart contract developers.
The nonce mechanism also made sure that the contracts are never deployed at the same address. Since the NULL_SENDER can send transactions with the same nonce, this mechanism cannot ensure contracts are never overwritten. So, the EIP also specifies that contract creation fails when the address already has non-empty code or non-zero nonce.
The EIP moves further in the direction of eclipsing the nonces. This EIP introduces CREATE2 instruction, whose result does not rely on the nonce of the creating contract. This EIP also changes the contract creation by private key holders. Whether from a contract or an external account, there is a way to deploy code on easily predictable addresses independent of the creator’s nonce.
I don’t know if this works out, but somebody will make a special tweak to some clients to include this kind of transactions. The first use might be a special signing scheme.
EIP-96 Blockhash refactoring
This EIP is another direction taken to offload things from the protocol to Ethereum contracts. This one is about BLOCKHASH instruction. Currently, an Etheruem Virtual Machine implementation is supposed to remember recent block hashes so that it can answer BLOCKHASH instruction. This EIP sets up a special contract whose storage remembers the recent blockhashes. After this EIP, an Ethereum Virtual Machine implementation can just look up the storage of this special contract (or even, perform a call to this particular contract) to serve BLOCKHASH instruction.
EIP-98 Removal of intermediate state roots from receipts
This is rather straight forward: removing an element from transaction receipts. The EIP has been uncontroversial except a tiny glitch caused by the two options of the EIP. Some people followed an option, and other people followed the other option, but one side conceded.
EIP-100 Change difficulty adjustment to target mean block time including uncles
This is a response to an attack scenario pointed out, but I don’t know about the attack, so I don’t have much intuition here. Maybe I should try to build some kind of physics around here.
EIP-140 REVERT instruction in the Ethereum Virtual Machine
This EIP adds an instruction called REVERT, which cancels the state-changes in the current call but outputs data to the caller. The new instruction is supposed to be useful for debugging.
One concern was raised about information leakage. Let’s say an oracle contract takes a payment and returns a useful piece of information. Now, the REVERT instruction can pass on the valuable information to the caller, and at the same time, cancel the payment to the oracle.
This changes the economics in certain ways, but is it a dangerous change? The impact is at most the cost of building a “looking-up-other-accounts’-storage” oracle. Or, building a trustless “looking-up-all-accounts’-storage” oracle? I’m not certain. REVERT instruction also preserves the remaining gas, in contrast with the other ways of reverting state-changes. So, one can encode information in the count of the remaining gas. This space looks interesting.
EIP-196 Precompiled contracts for addition and scalar multiplication on the elliptic curve alt_bn128
EIP-197 Precompiled contracts for optimal Ate pairing check on the elliptic curve alt_bn128
These EIPs enable zkSNARKs on Ethereum, I was told. This EIP has been not controversial, much less than RETURNDATACOPY, for instance. I was asking simple questions about groups. It sounds like a lot of fun reducing a Boolean circuit into a set of polynomial equations and then evaluating them on a secret position. But my main interest now is how to ensure equivalence of different implementations in C++, Go, Python and Rust. We have some number of test cases, but I think we should also be performing some coverage-aware fuzzers on these implementations. A bug in this corner would enable an attacker to create a fork or eliminate one client on the network. These would be temporal disruptions, but I don’t want to see these dozens of times.
EIP-198 Precompiled contract for bigint modular exponentiation
This introduces a new precompiled contract, which performs exponentiation modulo something. A precompiled contract is not implemented as EVM code. Ethereum clients implement the contract’s calculations natively. Recently the gas cost calculation of this precompiled contract was refined. The calculation used to count the number of bytes that each input number occupies, but now EIP seeks the most significant bit, to calculate gas.
EIP-211 New opcodes: RETURNDATASIZE and RETURNDATACOPY
This EIP allows arbitrary-length return data from message calls. Currently, the CALL instruction and its sisters specify the range of memory reserved for the output. When the callee returns a bigger portion of data, the excess is discarded. After this EIP, the virtual machine will keep the whole returned data in a special buffer, which is accessible through the two new instructions RETURNDATASIZE and RETURNDATACOPY.
There is an ongoing discussion whether to cause an exception when RETURNDATACOPY wants to read over the end of the returned bytes. The original EIP said “fill zeros” because that’s what existing instructions CALLDATACOPY and EXTCODECOPY do. There is a proposal to cause an exception because that is less error-prone. I don’t care much because one can implement the zero-filling version quite easily with the throwing version (using the zero-filling CALLDATACOPY) and the other way around easier.
EIP-214 New opcode STATICCALL
This EIP is relatively straightforward. The idea is to distinguish calls for changing states and calls for reading states. When an Ethereum contract wants to call a contract but doesn’t want any state changes during the call, STATICCALL is the solution. Private key holders do not need a separate “read-only” call because they can emulate the call off-chain.
Questions were asked around which instructions count as state-changing, but this EIP has been one of the most stable. I can come up with only one problem. Many similar variants are plausible. It’s easy to come up with situations calling for PURECALL or SELFDESTRUCT_FREE_CALL. Perhaps, we should come up with a CALL instruction with a bitfield of allowed operations. We might not need these because we can build an on-chain static analyzer that scans contracts for disallowed instructions.