changed 2 years ago
Published Linked with GitHub

Ethereum validator & builder interaction for Deneb

Background

This doc summarizes the updates that went into Deneb that require new validator and builder interactions. It assumes you have a basic understanding of today's interaction between validator and builder. We'll cover the new workflow and additional safety considerations.

What's new in Deneb? Validator signs block in addition blob sidecars.

Block now includes kzg commitment that anchors the blobsidecar.

class BeaconBlockBody(Container): execution_payload: ExecutionPayload # [Modified in Deneb] blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] # [New in Deneb]

What is a blob? It is the following in the consensus layer land for signed and unsigned version.

class SignedBlobSidecar(Container): message: BlobSidecar signature: BLSSignature class BlobSidecar(Container): block_root: Root index: BlobIndex # Index of blob in block slot: Slot block_parent_root: Root # Proposer shuffling determinant proposer_index: ValidatorIndex blob: Blob kzg_commitment: KZGCommitment kzg_proof: KZGProof # Allows for quick verification of kzg_commitment

On the execution layer land, a new type of EIP-2718 transaction in introduced, “blob transaction”, where the TransactionType is BLOB_TX_TYPE and the TransactionPayload is the following RLP value:

rlp([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, value, data, access_list, max_fee_per_data_gas, blob_versioned_hashes, y_parity, r, s])

The most important thing to note is that a Deneb block is valid. All the following three fields have to align:

  1. Block body's blob_kzg_commitments
  2. Block body's execution_payload's blob_versioned_hashes
  3. BlobSidecar's blob

Besides alignment, the BlobSidecar itself has to be valid concerning the consensus rule, but that's outside this doc's scope.

Validator & builder interaction today

Note: I am generalizing the builder here. Builder means an external party for execution block construction. It could be mev-boost, relayer, builder, or searcher. Whomever the validator interacts with and agrees to exchange block construction with.

The interaction today is simple:

  1. Validator calls getHeader to request a blind execution block to sign. (Think of it as the commit phase)
  2. Builder returns a bid that consists of execution_header. Validator signs it
  3. Validator calls submitBlindBlock alongside the signed header and rest of the consensus block contents
  4. Builder reveals the clear execution block to the rest of the network and returns it back to the validator (Think of it as the reveal phase)

The interaction is simplified. I avoided side effects like timing, attacks, circuit breaker, fail-over, etc. We'll cover them in the later section for Deneb.

Validator & builder interaction in Deneb

The interaction in Deneb brings in additional complexity, given that blobs are decoupled from the block. They are highlighted in bold:

  1. Validator calls getHeader to request a blind execution block and blind blobs bundle to sign so that validators can create signatures over the blind blobs. Blind blob utilizes blob_root instead of clear blob
class BlindedBlobsBundle(Container): commitments: List[KZGCommitment, MAX_BLOBS_PER_BLOCK] proofs: List[KZGProof, MAX_BLOBS_PER_BLOCK] blob_roots: List[Root, MAX_BLOBS_PER_BLOCK]
  1. Builder returns a bid that consists of execution_header and blinded_blobs. Validator signs it
class BuilderBid(Container):
    header: ExecutionPayloadHeader # [Modified in Deneb]
    blinded_blobs: BlindedBlobsBundle  # [New in Deneb]
    value: uint256
    pubkey: BLSPubkey
  1. Validator calls submitBlindBlock alongside the SignedBlindedBlockContents
class SignedBlindedBlobSidecar(Container): message: BlindedBlobSidecar signature: BLSSignature class SignedBlindedBlockContents(Container): signed_blinded_block: SignedBlindedBeaconBlock signed_blinded_blob_sidecars: List[SignedBlindedBlobSidecar, MAX_BLOBS_PER_BLOCK]
  1. Builder reveals the clear execution block and blob to the rest of the network and returns the execution block and blobs_bundle back to the validator. It's ExecutionPayloadAndBlobsBundle:
class ExecutionPayloadAndBlobsBundle(Container):
    execution_payload: ExecutionPayload
    blobs_bundle: BlobsBundle
  1. Validator reconstructs full beacon block using execution_payload and full blob sidecars using blobs_bundle and broadcasts them over respected gossip subnets

New safety consideration

The consensus layer client can default to local execution block production in the event it detects

  1. The builder bid contains fault
  2. The builder bid takes too long to arrive

For (1), it performs the following safety check

  • The bid has a valid format
  • The bid's version is correct
  • The bid's parent hash matches the head of the chain from CL client's pt of view
  • The bid's timestamp matches the chain's timestamp
  • The bid's builder signature

Post-deneb, the following safety check could be applied on BlindedBlobsBundle at the getHeader phase:

  • The blinded blobs bundle has a valid format
  • The proofs are valid points
  • The kzg commitments are valid points

Once the CL client gets ExecutionPayloadAndBlobsBundle at the submitBlindBlock phase, more validations can be done to broadcast the network, but this is not strictly necessary given its client's best interest to broadcast block and blobs as soon as possible to prevent reorg.

Select a repo