Ethereum Block Building Workload
Background
The Ethereum Virtual Machine (EVM) is a transacton based state machine. The state of the system started with some genesis and was incrementally updated through executing transactions. The world state, , can be thought of as all state used in the virtual machine such as accounts, balances, and more. Transactions
The state transition function can be expressed as:
Where is the Ethereum state transition function. In Ethereum, , together with are considerably more powerful than any existing comparable system; allows components to carry out arbitrary computation, while allows components to store arbitrary state between transactions. Transactions are collated into blocks; blocks are chained together using a cryptographic hash as a means of reference.
Where is this block, which includes a series of transactions amongst some other components and is the block-level state-transition function for transactions. This is the basis of the blockchain paradigm, a model that forms the backbone of not only Ethereum, but all decentralised consensus-based transaction systems to date.
Data Structures
An Ethereum block is defined as a tuple of four components:
where:
- (block header): A collection of metadata and accumulators that capture the state transitions and properties of the Ethereum state machine
- (transactions): The ordered list of transactions included in this block
- (ommers): A deprecated field from pre-Paris hard fork that contained headers of blocks sharing a grandparent with the current block
- (withdrawals): A collection of validator withdrawals from the consensus layer, introduced in the Shanghai hard fork
The block header is formally defined as:
where each component is defined as:
- (parentHash): Keccak 256-bit hash of the parent block's header
- (ommersHash): Deprecated 256-bit hash field, now constant at KEC(RLP(()))
- (beneficiary): 160-bit address receiving this block's priority fees
- (stateRoot): Keccak 256-bit hash of the state trie's root node after executing all transactions and withdrawals
- (transactionsRoot): Keccak 256-bit hash of the trie's root node containing all block transactions
- (receiptsRoot): Keccak 256-bit hash of the trie's root node containing all transaction receipts
- (logsBloom): Bloom filter of indexable data (addresses and topics) from all transaction receipt logs
- (difficulty): Deprecated scalar field, now constant at 0
- (number): Scalar count of ancestor blocks (0 for genesis block)
- (gasLimit): Scalar maximum gas expenditure allowed for this block
- (gasUsed): Scalar total gas consumed by all transactions in this block
- (timestamp): Scalar Unix timestamp at block creation
- (extraData): Arbitrary byte array of block-relevant data, maximum 32 bytes
- (prevRandao): Latest RANDAO mix from the previous block's post-beacon state
- (nonce): Deprecated 64-bit field, now constant at 0x0000000000000000
- (baseFeePerGas): Scalar wei amount burned per unit of gas consumed
- (withdrawalsRoot): Keccak 256-bit hash of the trie's root node containing all consensus layer withdrawals
Block Validity
A block is valid if and only if:
A block header is considered consistent if and only if all required fields match their derived values after block execution. returns true if the following conditions hold simultaneously:
-
-
-
-
-
-
Each coniditon is explained as follows:
-
Empty ommers field
-
State Root Consistency:
- Where is the base state
- represents state after executing all transactions and withdrawals
- converts state to trie entries
- Must match final post-execution state root
-
Transaction Root Consistency:
- Each transaction is RLP encoded with its index
- Must match root of transaction trie
- Includes special handling for EIP-2718 transactions
-
Receipts Root Consistency:
- Each receipt is RLP encoded with its index
- Must match root of receipt trie
- Generated from actual transaction execution results
-
Withdrawals Root Consistency:
- Each withdrawal is RLP encoded with its index
- Must match root of withdrawals trie
- Reflects consensus layer withdrawals
-
Logs Bloom Consistency:
- Bloom filter must match union of all receipt logs
- Combines log entries from all transaction receipts
- Includes logger addresses and log topics
State Root Consistency
The state root must satisfy:
where:
- is the Merkle Patricia tree root hash of state
- is the parent block
- Values are RLP encoded
- is the state after executing all transactions and withdrawals
Execution Order Dependencies
For consistency to hold:
- All transactions must be executed in order:
- All withdrawals must be processed after transactions:
- State root () must reflect final state after both transactions and withdrawals
- Receipt root () must include results from all transaction executions
- Logs bloom () must include all logs from all receipts
Validation Process
- Execute all transactions in order
- Process all withdrawals in order
- Compute final state root
- Compute transaction trie root
- Compute receipt trie root
- Compute withdrawals trie root
- Compute logs bloom filter
- Verify all computed values match header fields
A header is consistent if and only if all computed values exactly match their corresponding header fields.
Computation
Merkle Patricia Tries
There are four Modified Merkle Patricia Tries (MPT) used in maintenance of the Ethereum World State :
- State Trie
- Transaction Trie
- Receipt Trie
- Withdrawal Trie
Transaction Execution
Symbol Key:
- = state at time
- = block-level state transition function
- = block
- = transaction
- = transaction-level state transition function
Any transactions executed first pass the initial tests of intrinsic validity. (as of October 22nd)
- The transaction is well-formed RLP, with no additional trailing bytes;
- the transaction signature is valid;
- the transaction nonce is valid (equivalent to the
sender account’s current nonce);
- the sender account has no contract code deployed
(see EIP-3607 by Feist et al. [2021]);
- the gas limit is no smaller than the intrinsic gas,
g0, used by the transaction;
- the sender account balance contains at least the
cost, v0, required in up-front payment;
- the maxFeePerGas, Tm, in the case of type 2
transactions, or gasPrice, Tp, in the case of type 0 and type 1 transactions, is greater than or equal to the block’s base fee, Hf; and
- for type 2 transactions, maxPriorityFeePerGas, Tf , must be no larger than maxFeePerGas,
Tm.
The process of finalising a block involves three stages:
- executing withdrawals;
- validate transactions;
- verify state.
Time Complexity
where:
- = number of transactions
- = accounts touched per transaction
- = height of state trie
- = signature verification cost (constant)
- = total number of accounts in state
Component Breakdown
-
State Updates:
- transactions
- accounts per tx
- trie depth
-
Signature Verifications:
- One verification per tx
- Constant time per verification
-
Merkle Tree:
- Binary tree construction
- leaf nodes
Instruction Level Analysis
Empirical Values
For typical values:
- When transactions
- accounts per tx
- accounts in state
- average transaction size = 200 bytes
The dominant term becomes:
for state updates
Field |
Symbol |
Size in Bits |
Size in Bytes |
Notes |
parentHash |
|
256 |
32 |
Keccak hash |
ommersHash |
|
256 |
32 |
Keccak hash |
beneficiary |
|
160 |
20 |
Address |
stateRoot |
|
256 |
32 |
Keccak hash |
transactionsRoot |
|
256 |
32 |
Keccak hash |
receiptsRoot |
|
256 |
32 |
Keccak hash |
logsBloom |
|
2048 |
256 |
Bloom filter |
difficulty |
|
256 |
32 |
Zero value |
number |
|
256 |
32 |
Block number |
gasLimit |
|
256 |
32 |
Gas limit |
gasUsed |
|
256 |
32 |
Gas used |
timestamp |
|
256 |
32 |
Unix timestamp |
extraData |
|
≤256 |
≤32 |
Variable, max 32 |
prevRandao |
|
256 |
32 |
RANDAO value |
nonce |
|
64 |
8 |
Zero value |
baseFeePerGas |
|
256 |
32 |
Base fee |
withdrawalsRoot |
|
256 |
32 |
Keccak hash |
Total Size
This breaks down as:
- 13 fields of 256 bits (32 bytes) each = 3328 bits (416 bytes)
- 1 field of 2048 bits (256 bytes) = 2048 bits (256 bytes)
- 1 field of 160 bits (20 bytes) = 160 bits (20 bytes)
- 1 field of 64 bits (8 bytes) = 64 bits (8 bytes)
- 1 variable field of up to 256 bits (32 bytes)
Maximum total size including variable field:
In practice, the actual size might be slightly less due to:
- extraData often being smaller than 32 bytes
- RLP encoding overhead not included in this calculation
- Some number fields potentially using fewer bytes when encoded