Ethereum & Merlin Differences
Last updated
Last updated
A number of technical details differ between Ethereum mainnet's EVM and Merlin's zkEVM.
For the average Solidity developer, these details won't affect your development experience.
Opcode | Status | Merlin Behavior |
---|---|---|
MCOPY
, TSTORE
, TLOAD
, BLOBHASH
and BLOBBASEFEE
are Opcodes from the Cancun upgrade. We recommend using shanghai
as your EVM target and avoiding using a Solidity version higher than 0.8.23
. Otherwise make sure you're not using those invalid opcodes.
BASEFEE
is invalid because EIP-1559 is not supported. Make sure you're not using BASEFEE
or block.basefee
in solidity.
The RIPEMD-160
(address 0x3
), blake2f
(address 0x9
) are currently not supported. Calls to unsupported precompiled contracts will revert. These precompiles are rarely used—RIPEMD-160
, for example, has been called a total of ~2,600 times since the inception of Ethereum.
The other EVM precompiles are well supported.
There are some differences between the Merlin zkEVM Merkle tree and EVM Merkle tree.
A zkEVM state is stored in the form of a Sparse Merkle Tree (SMT), which is a binary tree. Instead of Keccak-256, the POSEIDON
Hash Function is used to build the SMTs, mainly due to its STARK-friendliness.
It is important to note that unlike the EVM tree, the zkEVM SMT does not add all the parameters in one leaf of the Merkle tree.
For convenience and achieving faster computations, each of the parameters (the nonce, balance, storage root and code hash) is stored in its respective leaf.
An additional parameter called codeHashLen
is used to store the length of the Code hash. A fifth leaf-type is used for this zkEVM-specific parameter.
Also, each value in a leaf is an array of eight values, [V0,V1,V2,…,V7], where each Vi is a 32-bit element. That field is the Goldilocks prime field 𝐹𝑝 where 𝑝=2^64−2^32+1.
The 32-bit field elements are 8 in number, so as to be compatible with the 256-bit EVM words.
So although in the EVM context computation work with 256-bit words, internally the zkEVM uses 8 times 32-bit field elements.
Each of the values; V0,V1,V2,…,V7; is composed of the 32 less significant bits of the 63.99-bit Goldilocks prime field elements.
The figure below depicts the 5 leaf-types together with the corresponding keys:
Merlin aims for a constant block interval of 3 seconds. While it's 12 seconds in Ethereum under ideal conditions. Having a faster, constant block interval results in quicker feedback and a better user experience.
When the load is high, the block interval may slightly exceed 3 seconds, for example, 4 seconds.
When the last block of the previous batch contains fewer transactions, the timestamp of the next block may be the same, resulting in a block interval of 0 seconds.
Otherwise, a constant block interval of 3 seconds is ensured.
The fee structure in Merlin doesn't support EIP-1559.
In Merlin, developers had to specify a gasPrice value to send a transaction. After EIP-1559, the gasPrice parameter is replaced by maxFeePerGas and maxPriorityFeePerGas.
maxFeePerGas is the maximum amount of gas fee a user is willing to pay per unit of gas for a transaction.
maxPriorityFeePerGas is an optional fee that is set by the user. Using this variable, users may pay a premium for a high-priority transaction. Whenever a block reaches 100% capacity, this parameter determines transaction priority, the same as before EIP-1559.
Consider changing to a gasPrice
value when maxFeePerGas
and maxPriorityFeePerGas
were used.
There's no difference between Ethereum and Merlin sending native token(ETH in Ethereum or BTC in Merlin). However we strongly recommend not using some methods supported.
You can send native token to others by
transfer
(2300 gas, throws error)
send
(2300 gas, returns bool)
call
(forward all gas or set gas, returns bool)
call
in combination with re-entrancy guard is the only recommended method to use.
Though supported, transfer
and send
are not recommended to use. 2300 gas will cause serious problems like upgradeable contract cannot be receiver.
SELFDESTRUCT
Supported
Replaced by SENDALL. It sends remaining value to address, without any other status change.
EXTCODEHASH
Supported
It returns the hash of the contract bytecode from the zkEVM state tree without checking if the account is empty.
DIFFICULTY
/ PREVRANDAO
Supported
It returns "0" instead of a random number as in the EVM.
NUMBER
Supported
It returns the number of processable transactions, which is actually the number of transactions processed on the rollup, instead of current block's number.
BLOCKHASH
Supported
It is the state root at the end of a processable transaction and is stored on the system smart contract. It returns all previous block hashes instead of just the last 256 blocks.
JUMPDEST
Supported
It is allowed in PUSH bytes to avoid runtime bytecode analysis.
BASEFEE
Invalid
Disabled. If the opcode is encountered, the transaction will be reverted.
BLOBHASH
Invalid
Disabled. If the opcode is encountered, the transaction will be reverted.
BLOBBASEFEE
Invalid
Disabled. If the opcode is encountered, the transaction will be reverted.
TLOAD
Invalid
Disabled. If the opcode is encountered, the transaction will be reverted.
TSTORE
Invalid
Disabled. If the opcode is encountered, the transaction will be reverted.
MCOPY
Invalid
Disabled. If the opcode is encountered, the transaction will be reverted.