diff --git a/learn_evm/zkevm.md b/learn_evm/zkevm.md index 0f72a85c..e618ad9e 100644 --- a/learn_evm/zkevm.md +++ b/learn_evm/zkevm.md @@ -1,21 +1,21 @@ The following list presents differences between the EVM and the zkEVM implemented by zkSync Era -| EVM Opcode | Difference Description | -| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `CREATE`, `CREATE2` | On zkSync Era, contract deployment is performed using the hash of the bytecode, and the `factoryDeps` field of EIP712 transactions contains the bytecode. The actual deployment occurs by providing the contract's hash to the `ContractDeployer` system contract. See the [zkSync Era documentation](https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#evm-instructions) for more information about these differences. | -| `CALL`, `STATICCALL`, `DELEGATECALL` | For calls, you specify a memory slice to write the return data to, e.g. out and outsize arguments for call(g, a, v, in, insize, out, outsize). In EVM, if outsize != 0, the allocated memory will grow to out + outsize (rounded up to the words) regardless of the returndatasize. On zkSync Era, returndatacopy, similar to calldatacopy, is implemented as a cycle iterating over return data with a few additional checks and trigerring a panic if out + outsize > returndatasize to simulate the same behavior as in EVM. | -| `MSTORE`, `MLOAD` | Unlike EVM, where memory growth is measured in words, zkEVM measures in bytes. For instance, `mstore(100, 0)` will result in `msize` of `132` on zkEVM, while it is `160` on EVM. Also, EVM has quadratic memory growth for memory payments, but zkEVM charges fees linearly at a rate of `1` erg per byte. Our compiler optimizes unused memory reads/writes, which results in a different `msize` compared to Ethereum, since fewer bytes are allocated. This difference in memory growth may cause EVM to panic, but zkEVM will not in some cases. | -| `CALLDATALOAD`, `CALLDATACOPY` | If `offset` is over `2^32-33` when using `calldataload(offset)`, the execution will panic. The `calldatacopy(to, offset, len)` function in zkEVM contains a loop that uses the `calldataload` and `mstore` functions during each iteration. This means that if `2^32-32 + offset % 32 < offset + len`, the code will panic. | -| `RETURN` | Constructors in the zkSync Era return an array of immutable values initialized up to the point of assembly block execution, when using RETURN within the constructor. | -| `TIMESTAMP`, `NUMBER` | For more information about blocks on zkSync Era, including the differences between `block.timestamp` and `block.number`, refer to the [documentation](https://era.zksync.io/docs/reference/concepts/blocks.html#blocks-in-zksync-era). | -| `COINBASE` | This returns the address of the `Bootloader` contract, which is `0x8001` on the zkSync Era. | -| `DIFFICULTY` | Returns a constant value of `2500000000000000` on zkSync Era. | -| `BASEFEE` | This is not a constant on zkSync Era and is instead defined by the fee model. Most of the time it is 0.25 gwei, but under very high L1 gas prices it may rise. | -| `SELFDESTRUCT` | Considered harmful and deprecated in [EIP-6049](https://eips.ethereum.org/EIPS/eip-6049). Always produces a compile-time error with the zkEVM compiler. | -| `CALLCODE` | Deprecated in [EIP-2488](https://eips.ethereum.org/EIPS/eip-2488) in favor of `DELEGATECALL`. Always produces a compile-time error with the zkEVM compiler. | -| `PC` | Inaccessible in Yul and Solidity `>=0.7.0`, but accessible in Solidity `0.6`. Always produces a compile-time error with the zkEVM compiler. | -| `CODESIZE` | Yul uses a special instruction `datasize` to distinguish the contract code and constructor arguments, so we substitute `datasize` with 0 and `codesize` with `calldatasize` in zkSync Era deployment code. This way when Yul calculates the calldata size as `sub(codesize, datasize)`, the result is the size of the constructor arguments. | -| `CODECOPY` | In the context of deploy code, this copies the constructor arguments. In the context of old EVM codegen runtime code, this zeroes out memory. And in the context of new yul codegen runtime code, this produces a compile-time error. | -| `EXTCODECOPY` | Contract bytecode cannot be accessed on zkEVM architecture. Only its size is accessible with both `CODESIZE` and `EXTCODESIZE`. `EXTCODECOPY` always produces a compile-time error with the zkEVM compiler. | -| `DATASIZE`, `DATAOFFSET`, `DATACOPY` | Contract deployment is handled by two parts of the zkEVM protocol: the compiler front end and the system contract called `ContractDeployer. See the [zkSync Era documentation](https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#datasize-dataoffset-datacopy) for more information about these differences. | -| `SETIMMUTABLE`, `LOADIMMUTABLE` | zkEVM does not provide any access to the contract bytecode, so the behavior of immutable values is simulated with the system contracts. See the [zkSync Era documentation](https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#setimmutable-loadimmutable) for more information about these differences. | +| EVM Opcode | Difference Description | +| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `CREATE`, `CREATE2` | On zkSync Era, contract deployment is performed using the hash of the bytecode, and the `factoryDeps` field of EIP712 transactions contains the bytecode. The actual deployment occurs by providing the contract's hash to the `ContractDeployer` system contract. See the [zkSync Era documentation](https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#evm-instructions) for more information about these differences. | +| `CALL`, `STATICCALL`, `DELEGATECALL` | For calls, you specify a memory slice to write the return data to, e.g. out and outsize arguments for call(g, a, v, in, insize, out, outsize). In EVM, if outsize != 0, the allocated memory will grow to out + outsize (rounded up to the words) regardless of the returndatasize. On zkSync Era, returndatacopy, similar to calldatacopy, is implemented as a cycle iterating over return data with a few additional checks and trigerring a panic if out + outsize > returndatasize to simulate the same behavior as in EVM. | +| `MSTORE`, `MLOAD` | Unlike EVM, where memory growth is measured in words, zkEVM measures in bytes. For instance, `mstore(100, 0)` will result in `msize` of `132` on zkEVM, while it is `160` on EVM. Also, EVM has quadratic memory growth for memory payments, but zkEVM charges fees linearly at a rate of `1` erg per byte. Our compiler optimizes unused memory reads/writes, which results in a different `msize` compared to Ethereum, since fewer bytes are allocated. This difference in memory growth may cause EVM to panic, but zkEVM will not in some cases. | +| `CALLDATALOAD`, `CALLDATACOPY` | If `offset` is over `2^32-33` when using `calldataload(offset)`, the execution will panic. The `calldatacopy(to, offset, len)` function in zkEVM contains a loop that uses the `calldataload` and `mstore` functions during each iteration. This means that if `2^32-32 + offset % 32 < offset + len`, the code will panic. | +| `RETURN` | Constructors in the zkSync Era return an array of immutable values initialized up to the point of assembly block execution, when using RETURN within the constructor. | +| `TIMESTAMP`, `NUMBER` | For more information about blocks on zkSync Era, including the differences between `block.timestamp` and `block.number`, refer to the [documentation](https://era.zksync.io/docs/reference/concepts/blocks.html#blocks-in-zksync-era). | +| `COINBASE` | This returns the address of the `Bootloader` contract, which is `0x8001` on the zkSync Era. | +| `DIFFICULTY` | Returns a constant value of `2500000000000000` on zkSync Era. | +| `BASEFEE` | This is not a constant on zkSync Era and is instead defined by the fee model. Most of the time it is 0.25 gwei, but under very high L1 gas prices it may rise. | +| `SELFDESTRUCT` | Considered harmful and deprecated in [EIP-6049](https://eips.ethereum.org/EIPS/eip-6049). Always produces a compile-time error with the zkEVM compiler. | +| `CALLCODE` | Deprecated in [EIP-2488](https://eips.ethereum.org/EIPS/eip-2488) in favor of `DELEGATECALL`. Always produces a compile-time error with the zkEVM compiler. | +| `PC` | Inaccessible in Yul and Solidity `>=0.7.0`, but accessible in Solidity `0.6`. Always produces a compile-time error with the zkEVM compiler. | +| `CODESIZE` | Yul uses a special instruction `datasize` to distinguish the contract code and constructor arguments, so we substitute `datasize` with 0 and `codesize` with `calldatasize` in zkSync Era deployment code. This way when Yul calculates the calldata size as `sub(codesize, datasize)`, the result is the size of the constructor arguments. | +| `CODECOPY` | In the context of deploy code, this copies the constructor arguments. In the context of old EVM codegen runtime code, this zeroes out memory. And in the context of new yul codegen runtime code, this produces a compile-time error. | +| `EXTCODECOPY` | Contract bytecode cannot be accessed on zkEVM architecture. Only its size is accessible with both `CODESIZE` and `EXTCODESIZE`. `EXTCODECOPY` always produces a compile-time error with the zkEVM compiler. | +| `DATASIZE`, `DATAOFFSET`, `DATACOPY` | Contract deployment is handled by two parts of the zkEVM protocol: the compiler front end and the system contract called `ContractDeployer. See the [zkSync Era documentation](https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#datasize-dataoffset-datacopy) for more information about these differences. | +| `SETIMMUTABLE`, `LOADIMMUTABLE` | zkEVM does not provide any access to the contract bytecode, so the behavior of immutable values is simulated with the system contracts. See the [zkSync Era documentation](https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#setimmutable-loadimmutable) for more information about these differences. |