Loading .
New sharding design with tight beacon and shard block integration
Previous data shard construction: Add \(n=64\) data shards to the beacon chain. Each slot, \(n\) proposers independently propose their shard blobs, which are then confirmed by committees. Once a shard blob is confirmed (this can take several slots), it can be referenced by the execution chain.
Here is an alternative proposal: Add a new type of transaction that can contain additional sharded data as calldata. The block is then constructed by a single block builder (which can be different from the proposer using proposer builder separation), and includes normal transactions as well as transactions with sharded calldata. This is efficient because it means that tight integrations between rollups and L1 become possible, and it is expected that this “super-block-builder” strategy will emerge in practice anyway in order to maximize MEV extraction.
Advantages:
- Tighter coupling with the current Eth1 chain – rollup data is immediately visible to manager contracts
- All data is confirmed together with the rollup calls
- Do not need to wait until shard blocks are confirmed
- Do not need to worry about duplicate shard data, etc.
- Easier to reason about for developers
- Rollups do not need to implement awkward “shard scanning logic”. Data addressed to them can immediately be labeled using L1 transactions
- There is no need for a separate PBS for shards
- This will reduce the cost of market entry for builders, as they will not have to build up two different systems
- It will also mean that MEV from interactions between data and execution can be exploited by the builder risk-free, which means less builder centralization
- There is no need for a separate shard transaction payment system
- The cost of sharded calldata can be directly charged to the transaction that is using them
- We can use all existing Ethereum transaction payment infrastructure as is
- Increased bribery resistance as data can be confirmed by larger committees (1/32 of validator set)
- No separate shard block confirmation allow better transaction aggregation. We need only one committee per slot (two for PBS)
- We can add beacon and execution block immediately to the data availability set
- Sets stage for data availability+fraud proof protected light client execution as soon as verkle tries are ready
- “Eth1 as a rollup”
- Enables even lighter validators+nodes that don’t need to run a full Eth1 node
- Synchronous calls from L2 to L1 become possible with ZKRollups
- No need for applications to commit to shards that they want to use
- Total block size can be governed in a very similar way to block gas limit
- When the beacon chain becomes fraud provable, superlight clients (data availability only) will be possible.
- Current shard blob market is inefficient
- We claim 64 independent proposers. However in practice, this is impossible, as this would lead to lots of duplicates being confirmed, which in return will lead to centralization of the market
- If one requires 10 separate blobs to be confirmed, there is no efficient way to bid for all of them to be included in the same slot (all-or-nothing bid)
- Much ligher clients are possible
- Clients can do full data availability sampling with only ca. 40 kb/beacon block (2.5 kb/s), whereas ca. 1 MB/beacon block (60 kb/s) was needed in the previous construction. This is because we can immediately provide 2d sampling
Disadvantages
- Increased requirements for builders:
- Larger minimum bandwidth requirements: Need to be able to send 64 MB of data within builder deadline, and make sure it is distributed in P2P. Probably needs at least 2.5 GBit upstream
- Neither of these are crazy requirements for builders and other entry requirements arguably already set a higher bar
- More power to the builder as they serve execution + data availability
- But with PBS we need other censorship resistance methods anyway. With this system they can be treated as a separate concern. The current suggested model is for the proposer to have the power to force certain transactions to be included (https://notes.ethereum.org/Dh7NaB59TnuUW5545msDJQ)
Suggested Implementation
MAX_SHARDS = 2**8
SHARD_SIZE_FIELD_ELEMENTS = 2**12
MAX_BLOCK_SIZE = SHARD_SIZE_FIELD_ELEMENTS * MAX_SHARDS
TARGET_BLOCK_SIZE = MAX_BLOCK_SIZE // 2
- We introduce a new BlockKZGCommitment that commits to all data using a 2D KZG format. This will commit to the beacon block, the execution payload and the commitments to shard data.
class ShardedBeaconBlockCommitment(Container):
sharded_commitments: List[KZGCommitment, 2 * MAX_SHARDS]
beacon_block_commitments: uint64
degree_proof: KZGCommitment
- The
ExecutionPayload
gets new fields for the data gas market
class ExecutionPayload(Container):
parent_hash: Hash32
fee_recipient: ExecutionAddress
state_root: Bytes32
receipt_root: Bytes32
logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM]
random: Bytes32
block_number: uint64
gas_limit: uint64
gas_used: uint64
timestamp: uint64
extra_data: ByteList[MAX_EXTRA_DATA_BYTES]
base_fee_per_gas: uint256
block_hash: Hash32
transactions: List[Transaction, MAX_TRANSACTIONS_PER_PAYLOAD]
data_gas_limit: uint64
data_gas_used: uint64
data_base_fee_per_gas: uint256
- The
ShardedBeaconBlockCommitment
up to beacon_block_commitments
is the beacon block (which includes the execution payload), encoded into 31 bytes per field element
- The remainder of the data does not have any validity conditions
- Add a new transaction type 3, with the following payload specification:
@dataclass
class TransactionKZGCalldataPayload:
chain_id: int = 0
signer_nonce: int = 0
max_priority_fee_per_gas: int = 0
max_fee_per_gas: int = 0
max_priority_fee_per_data_gas: int = 0
max_fee_per_data_gas: int = 0
gas_limit: int = 0
destination: int = 0
amount: int = 0
payload: bytes = bytes()
kzg_calldata_commitments: List[KZGCommitment, MAX_SHARDS]
access_list: List[Tuple[int, List[int]]] = field(default_factory=list)
signature_y_parity: bool = False
signature_r: int = 0
signature_s: int = 0
- For each transaction of type 3, there is a validity condition that requires that all
kzg_calldata_commitments
of the transaction are included in the sharded_commitments
of the ShardedBeaconBlockCommitment
_start}x]_2)$
- Add a new opcode to the EVM,
KZGCALLDATA
, that adds the kzg_calldata_commitments
to a specified memory location
- Verify that the sharded commitments are correctly encoded
- For each commitment, there is a degree proof, proving that the degree of the commitment is
< SHARD_SIZE_FIELD_ELEMENTS
, checked via the pairing equation:
- \(e(\mathrm{degree\_proof}, [1]_2) = e(\mathrm{sharded\_commitment}, [s^{\mathrm{SETUP\_MAX\_DEGREE} - \mathrm{SHARD\_SIZE\_FIELD\_ELEMENTS}}]_2)\)
- If there are \(2N\) sharded commitments, the first \(N\) of them represent data, and the remaining \(N\) are a polynomial extension. We need to verify that the \(2N\) lie on a polynomial of degree \(N-1\).
- Standard way: Do an FFT of size \(2N\) to verify that the high order \(N\) coefficients are \(0\). This requires \(2N \log 2N\) group multiplications, which is relatively expensive
- Cheaper way: use the barycentric formula to evaluate the first \(N\) commitments on a random point in the field, and do the same for the second half. If both points are the same then they are on the same polynomial of degree \(N-1\). This only requires one MSM of size \(2N\), which takes time of ca. \(2N / \log 2N\) group multiplications.
- Add
BLS12_381
opcodes (necessary for any reasonable sharding implementation)
Sampling
- We have up to 256 sharded commitments for the original data, which are extended to up to 512 using polynomial extension
- Each sharded commitments is of degree \(2^{12}\) and extended to \(2^{13}\) field elements for sampling
- Let’s assume a sample size of \(2^{4} = 16\) field elements (512 bytes). Then we are sampling a square of 512 rows and 512 columns for a total of \(512*512 = 2^{18} = 262144\) samples per block. Any 50% of these samples are sufficient to reconstruct the whole block. Additionally, any row/column can be reconstructed from 50% of samples, which allows efficient recovery by small actors like at home validators even in the event where a block is intentionally poorly seeded
- h validator is assigned to 32 random columns, which they also have to custody in their next attestation (meaning that the attestation will custody a total of \(32\cdot32\cdot512\) samples). This has the nice side effect that each block gets set (bribing less than 1/2 of the validators attesting to one block is useless)
Block Builder Costs
Block builders get two new tasks. One is computing the KZG witnesses for the samples, and the other one is seeding the samples in the P2P network.
- Let’s start with the second one. Given that we have about 128 MB of samples, and we say want to distribute each sample to at least 5 peers for good dispersion, and all of this should happen in ~1s, the builder needs a total upstream of 640 MB/s or 5 GBit/s. This is certainly unlikely for an at-home internet connection, but easy enough in a data center
- If people really want to run a builder at home, a service can distribute the samples after they were created, reducing their own upstream requirement to 32 MB/s or 256 MBit/s which is possible in some regions
- However, the requirement that builders run in datacenters does not seem particularly limiting (they will most likely do that anyway)
- Computing the KZG proofs for all samples. This is going to take using according to my estimates (the uncertainty comes from the precise complexity of an algorithm, which is unknown). This can be distributed across many machines. In a datacenter this computing power is easily available.
- Dag Arne Osvik estimates that the witness computation can be completed in ~1s on a GPU
Sharded mempool
Rationale
The current mempool that most transactions go through on Ethereum does not scale to data transactions. Every node processes the full mempool, but with sharding the capacity of the chain increases to 1.3 MB/s, which is also the lower bound for the expected mempool bandwidth if all transactions go through it.
Clearly it makes no sense to shard data transactions on chain while requiring nodes to process the full mempool. We instead need to do data availability sampling on the mempool as well when data transactions are concerned.
Is a mempool still required?
An alternative to sending transactions to a public mempool is to send them to a block builder, which is effectively already happening now with Flashbots. The advantage is that block builders can promise not to front run transactions. If they do, then users can simply switch to another block builder.
Solana, as an example, already implements this design and by default only sends transactions to the next proposer.
It is therefore quite likely that the mempool will be much smaller in size and not even be required for the chain at all. However, we want to keep a mempool in the design for two reasons:
- The new censorship resistance design by Francesco requires a public mempool
This does not contradict the earlier point that most transactions will be sent directly to a builder first. Basically users will mostly send their transactions to builders, and only if they get censored they will escalate to the mempool; the mempool becomes a “censored pool”
- An Ethereum user with a full node should have a way of sending transactions without configuring a central provider.
I find this argument less convincing as the future will largely consist of rollups on L1, and end users using L2s. So end users should very rarely have to use the L1.
Construction
All transactions are broadcastet via a libp2p pubsub channel. For transaction type 3, the kzg_calldata_commitments
are included, but not the actual underlying data.
We construct a second set of 512 pubsub channels that are only for propagating samples of shard data transactions. When someone wants to send a type 3 transaction to the mempool, they send the 512 samples of each kzg_calldata_commitment
to these sample channels.
- Normal nodes subscribe to ~10 randomly selected channels. This is to ensure that these pubsubs are available to nodes that want to subscribe to them
- Block proposers sample a random 30 channels, and can thus determine if a data transaction is available or not, in order to be able to include them into the
crList
- Block builders subscribe to at least 256, probably all 512 channels, so that they can reconstruct any data transaction for inclusion into the block