Bootloader
The bootloader is the component responsible for implementing the general blockchain protocol. Roughly, this means:
- Initializing the system.
- Reading the block context from the oracle.
- Reading and parsing the first transaction.
- Validating the transaction.
- Executing the transaction.
- Saving the transaction result.
- Repeat from 3 until there are no more transactions.
- Finalizing the block.
This component is, as the name suggest, the entrypoint of the system.
The function run_prepared
implements this
top-level main loop.
Configuration
The bootloader can be configured with the following parameters
(found in the BasicBootloaderExecutionConfig
struct):
ONLY_SIMULATE
: skips the validation step when processing a transaction. Used for call simulation in the node.IS_PROVING_ENVIRONMENT
: to skip some checks during sequencing.SPECIAL_ADDRESS_SPACE_BOUND
: the range of address (starting from 0) where system contracts can be deployed.AA_ENABLED
: whether native account abstraction is enabled.
In addition, the basic_bootloader
crate has the following compilation flags:
code_in_kernel_space
: to enable normal contract execution for addresses in the range[0, SPECIAL_ADDRESS_SPACE_BOUND]
.transfers_to_kernel_space
: to enable token transfers to addresses in the range[0, SPECIAL_ADDRESS_SPACE_BOUND]
. Note: the bootloader itself has a special formal address (0x8001) that is always allowed to receive token transfers. This is used to collect fees.charge_priority_fee
: to enable charging for the EIP-1559 tip (priority fee) on top of the base fee.evm-compatibility
: enables all the previous flags, needed for the EVM test suite.
Code Execution
For transaction execution, the bootloader has to execute some contract code. This contract code corresponds to one of the supported VMs, and is executed through the Execution Environment (EE) module.
A contract call is executed through an interplay between the bootloader and (potentially different) execution environments. Indeed, a contract executing in a given EE can call to contracts that run on a different EE or to a System Hook. This interplay is described under Runner Flow.
Block Header
At the end of the execution the bootloader outputs the block header.
For the block header, the Ethereum format will be used. However, some of the fields will be set differently in the first version for simplification.
The block header should determine the block fully, i.e. include all the inputs needed to execute the block.
Ethereum Field Name | Ethereum value | ZKsync OS value | Comments |
---|---|---|---|
parent_hash | previous block hash | previous block hash | |
owners_hash | 0x1dcc4de8dec75d7aab85b567 b6ccd41ad312451b948a7413f 0a142fd40d49347 (post merge) | 0x1dcc4de8dec75d7aab 85b567b6ccd41ad312451b 948a7413f0a142fd40d49347 | hash of empty RLP list |
beneficiary | block proposer | Operator (fee) address | |
state_root | state commitment | 0 | |
transactions_root | transactions trie (Patricia Merkle tree) root | transactions rolling hash | |
receipts_root | receipts trie (Patricia Merkle tree) root | 0 | |
logs_bloom | 2048-bit bloom filter over logs’ addresses and topics | 0 | |
difficulty | 0 (post merge) | 0 | |
number | block number | block number | |
gas_limit | block gas limit | constant, not defined yet, 10–15 M most likely | |
gas_used | block gas used | block gas used | TBD — with or without pubdata |
timestamp | block timestamp | block timestamp | |
extra_data | any extra data included by proposer | TBD, possibly gas_per_pubdata | |
mix_hash | beacon-chain-provided random, (post merge) | 0 | after consensus will be provided random |
nonce | 0 (post merge) | 0 | |
base_fee_per_gas | base_fee_per_gas | base_fee_per_gas |