Many EVM instructions require special handling by the
System Contracts. Among them are: ORIGIN
,
CALLVALUE
, BALANCE
, CREATE
, SHA3
, and others. To see the full detailed list of instructions requiring special
handling, see
the EVM instructions reference.
There are several types of System Contracts from the perspective of how they are handled by the zkSync Era compilers:
- Environmental data storage.
- KECCAK256 hash function.
- Contract deployer.
- Ether value simulator.
- Simulator of immutables.
- Event handler.
Such storage contracts are accessed with static calls in order to retrieve values for the block, transaction, and other
environmental entities: CHAINID
, DIFFICULTY
, BLOCKHASH
, etc.
One good example of such contract is SystemContext that provides the majority of the environmental data.
Since EVM is not using external calls for these instructions, we must use the auxiliary heap for their calldata.
Steps to handle such instructions:
- Store the calldata for the System Contract call on the auxiliary heap.
- Call the System Contract with a static call.
- Check the return status code of the call.
- Revert or throw if the status code is zero.
- Read the ABI data and extract the result. All such System Contracts return a single 256-bit value.
- Return the value as the result of the original instruction.
For reference, see the LLVM IR codegen source code.
Handling of this function is similar to Environmental Data Storage with one difference:
Since EVM also uses heap to store the calldata for KECCAK256
, the required memory chunk is allocated by the IR
generator, and zkSync Era compiler does not need to use the auxiliary heap.
For reference, see the LLVM IR codegen source code.
See handling CREATE and dependency code substitution instructions on zkSync Era documentation.
For reference, see LLVM IR codegen for the deployer call and CREATE-related instructions.
EraVM does not support passing Ether natively, so this is handled by a special System Contract called MsgValueSimulator.
An external call is redirected through the simulator if the following conditions are met:
- The call has the Ether value parameter.
- The Ether value is non-zero.
The call to the simulator requires extra data passed via ABI using registers:
- Ether value.
- The address of the contract to call.
- The system call bit, which is only set if a call to the ContractDeployer is being redirected,
that is
CREATE
orCREATE2
is called with non-zero Ether.
For reference, see the LLVM IR codegen source code.
See handling immutables on zkSync Era documentation.
For reference, see LLVM IR codegen for instructions for immutables and RETURN from the deploy code.
Event payloads are sent to a special System Contract called EventWriter. Like on EVM, the payload consists of topics and data:
- The topics with a length-prefix are passed via ABI using registers.
- The data is passed via the default heap, like on EVM.
For reference, see the LLVM IR codegen source code.
Both zksolc and zkvyper compilers for EraVM operate on the IR level, so they cannot control the heap memory allocator which remains a responsibility of the high-level source code compilers emitting the IRs.
However, the are several cases where EraVM needs to allocate memory on the heap and EVM does not. The auxiliary heap is used for these cases:
- Returning immutables from the constructor.
- Allocating calldata and return data for calling the System Contracts.