BEDROCK-V1-1-BLOCK-CONSTRUCTION

FieldValue
NameBedrock v1.1 Block Construction, Validation and Execution Specification
Slug93
Statusraw
CategoryStandards Track
EditorMarcin Pawlowski [email protected]
ContributorsThomas Lavaur [email protected], Daniel Sanchez Quiros [email protected], David Rusu [email protected], Álvaro Castro-Castilla [email protected], Mehmet Gonen [email protected], Filip Dimitrijevic [email protected]

Timeline

  • 2026-01-19f24e567 — Chore/updates mdbook (#262)
  • 2026-01-1689f2ea8 — Chore/mdbook updates (#258)

Abstract

This specification defines the construction, validation, and execution of block proposals in the Nomos blockchain. It describes how block proposals contain references to transactions rather than complete transactions, compressing the proposal size from up to 1 MB down to 33 kB to save bandwidth necessary to broadcast new blocks.

Keywords: Bedrock, block construction, validation, execution, leader, transaction, Proof of Leadership

Semantics

The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.

Definitions

TerminologyDescription
LeaderA node elected through the leader lottery to construct a new block.
Block BuilderThe leader node that constructs a new block proposal.
Block ProposerThe leader node that shares the constructed block with other network members.
Block ProposalA message structure containing a header and references to transactions.
Proof of Leadership (PoL)A proof confirming that a node is indeed the elected leader.
Transaction MaturityThe assumption that transactions have had enough time to spread across the network.
ValidatorA node that validates and executes block proposals.

High-level Flow

This section presents a high-level description of the block lifecycle. The main focus of this section is to build an intuition on the block construction, validation, and execution.

  1. A leader is selected. The leader becomes a block builder.

  2. The block builder constructs a block proposal.

    1. The block builder selects the latest block (parent) as the reference point for the chain state update.

    2. The block builder constructs references to the deterministically generated Mantle Transactions that execute the Service Reward Distribution Protocol, if such transactions can be constructed. For example, there is no need to distribute rewards when all rewards have already been distributed.

    3. The block builder selects valid Mantle Transactions (as defined in Mantle Specification) from its mempool and includes references to them in the proposal.

    4. The block builder populates the block header of the block proposal.

  3. The block proposer sends the block proposal to the Blend network.

  4. The validators receive the block proposal.

  5. The validators validate the block proposal.

    1. They validate the block header.

    2. They verify distribution of service rewards through Mantle Transactions as specified in Service Reward Distribution Protocol. This is done by independently deriving the distribution transaction and confirming that it matches the first reference, if there are rewards to be distributed.

    3. They retrieve complete transactions from their mempool that are referred in the block.

    4. They validate each transaction included in the block.

  6. The validators execute the block proposal.

    1. They derive the new blockchain state from the previous one by executing transactions as defined in Mantle Specification.

    2. They update the different variables that need to be maintained over time.

Constructions

Hash

This specification uses two hashing algorithms that have the same output length of 256 bits (32 bytes) that are Poseidon2 and Blake2b.

Block Proposal

A block proposal, instead of containing complete Mantle Transactions of an unlimited size, contains references of fixed size to the transactions. Therefore, the size of the proposal is constant and it is 33129 bytes.

The following message structure is defined:

class Proposal:  # 33129 bytes
    header: Header              # 297 bytes
    references: References      # 32768 bytes
    signature: Ed25519Signature # 64 bytes

Where:

  • header is the header of the proposal; defined below: Header.
  • references is a set of 1024 references to transactions of a hash type; the size of the hash type is 32 bytes and is the transaction hash as defined in Mantle Specification - Mantle Transaction.
  • signature is the signature of the complete header using the leader_key from the ProofOfLeadership; the size of the Ed25519Signature type is 64 bytes.

Note: The length of the references list must be preserved to maintain the message's indistinguishability in the Blend protocol. Therefore, the list must be padded with zeros when necessary.

class Header:  # 297 bytes
    bedrock_version: byte             # 1 bytes
    parent_block: hash                # 32 bytes
    slot: SlotNumber                  # 8 bytes
    block_root: hash                  # 32 bytes
    proof_of_leadership: ProofOfLeadership  # 224 bytes

Where:

  • bedrock_version is the version of the proposal message structure that supports other protocols defined in Bedrock Specification; the size of it is 1 byte and is fixed to 0x01.
  • parent_block is the block ID (Cryptarchia v1 Protocol Specification) of the parent block, validated and accepted by the block builder. It is used for the derivation of the AgedLedger and LatestLedger values necessary for validating the PoL; the size of the hash is 32 bytes.
  • slot is the consensus slot number; the size of the SlotNumber type is 8 bytes.
  • block_root is the root of the Merkle tree constructed from transaction hashes (defined in Mantle Specification - Mantle Transaction) used for constructing the references list in the transactions; the size of the hash is 32 bytes.
  • proof_of_leadership is the proof confirming that the sender is the leader; defined below: Proof of Leadership.

Block References

class References:  # 32768 bytes
    service_reward: list[zkhash]        # 1*32 bytes
    mempool_transactions: list[zkhash]  # 1024-len(service_reward)*32 bytes

Where:

  • service_reward is a set of up to 1 reference to a reward transaction of a zkhash type; the size of the zkhash type is 32 bytes and is the transaction hash as defined in Mantle Specification - Mantle Transaction.
  • mempool_transactions is a set of up to 1024 references to transactions of a zkhash type; the size of the zkhash type is 32 bytes and is the transaction hash as defined in Mantle Specification - Mantle Transaction.

The service_reward transaction is created deterministically by the leader and is not obtained from the mempool. If this transaction were obtained from the mempool, it could expose the leader's identity as the transaction creator. To protect the leader's identity, only the service_reward reference is included in the proposal, and it is derived again by the nodes verifying the block.

The service_reward transaction is a Service Rewards Distribution Transaction that distributes service rewards. It is a Mantle Transaction with no input and up to service_count x 4 outputs, service_count being the number of services (global parameter). The outputs represent the validators rewarded (up to 4 per service).

If the service_reward transaction cannot be created, then nothing is added to the list. Therefore, the service_reward list is allowed to have a length of 0.

Proof of Leadership

class ProofOfLeadership:  # 224 bytes
    leader_voucher: RewardVoucher       # 32 bytes
    entropy_contribution: zkhash        # 32 bytes
    proof: ProofOfLeadership            # 128 bytes
    leader_key: Ed25519PublicKey        # 32 bytes

Where:

  • leader_voucher is the voucher value used for retrieving the reward by the leader for proposal; the size of the RewardVoucher is 32 bytes.
  • entropy_contribution is the output of the PoL contribution for Cryptarchia entropy; the size of the zkhash type is 32 bytes.
  • proof is the proof confirming that the proposal is constructed by the leader; the size of the ProofOfLeadership type is 128 bytes (2 compressed G1 and 1 compressed G2 BN256 elements).
  • leader_key is the one-time Ed25519PublicKey used for signing the Proposal. This binds the content of the proposal with the ProofOfLeadership; the size of the Ed25519PublicKey type is 32 bytes.

Proposal Construction

This section explains how the block proposal structure presented above is populated by the consensus leader.

The block proposal is constructed by the leader of the current slot. The node becomes a leader only after successfully generating a valid PoL for a given (Epoch, Slot).

Prerequisites

Before constructing the proposal, the block builder must:

  1. Select a valid parent block referenced by ParentBlock on which they will extend the chain.

  2. Derive the required Ledger state snapshots AgedLedger and LatestLedger from the state of the chain including the last block.

  3. Select a valid unspent note winning the PoL.

  4. Generate a valid PoL proving leadership eligibility for (Epoch, Slot) based on the selected note. Attach the PoL to a one-time Ed25519 public key used to sign the block proposal.

Only after the PoL is generated can the block proposal be constructed (see Proof of Leadership Specification).

Construction Procedure

  1. Initialize proposal metadata with the last known state of the blockchain. Set the:

    • header:
      • bedrock_version
      • parent_block
      • slot
      • block_root
      • proof_of_leadership:
        • leader_voucher
        • entropy_contribution
        • proof
        • leader_key
  2. Construct the service_reward object:

    1. If there are service rewards to be distributed, construct the transaction that distributes the service rewards from previous session and add its reference to the service_reward list. This transaction must be computed locally, do not disseminate this transaction.
  3. Construct the mempool_transactions object:

    1. Select Mantle transactions:

      • Choose up to 1024-len(service_reward) valid SignedMantleTx from the local mempool.

      • Ensure each transaction:

        • Is valid according to Mantle Specification.

        • Has no conflicts with others (e.g., two transactions trying to spend the same note).

  4. Derive references values:

    references: list[zkhash] = [mantle_txhash(tx) for tx in service_reward + mempool_transactions]
    
  5. Compute the header.block_root as the root of the Merkle tree constructed from the list(service_reward) + mempool_transactions transactions used to build references.

  6. Sign the block proposal header.

    signature = Ed25519.sign(leader_secret_key, header)
    
  7. Assemble the block proposal.

    proposal = Proposal( header, references, signature )
    

The PoL must have been generated beforehand and bound to the same Ledger view as mentioned in the Prerequisites.

The constructed proposal can now be broadcast to the network for validation.

Block Proposal Reconstruction

Given a block proposal, this specification assumes transaction maturity. This means that the block proposal must include transactions from the mempool that have had enough time to spread across the network to reach all nodes. This ensures that transactions are widely known and recognized before block reconstruction.

This transaction maturity assumption holds true because the block proposal must be sent through the Blend Network before it reaches validators and can be reconstructed. The Blend Network introduces significant delay, ensuring that transactions referenced in the proposal have reached all network participants.

This approach is crucial for maintaining smooth network operation and reducing the risk that proposals get rejected due to transactions being unavailable to some validators. Moreover, by increasing the number of nodes that have seen the transaction, anonymity is also enhanced as the set of nodes with the same view is larger. This may result in increased difficulty—or even practical prevention—of executing deanonymization attacks such as tagging attacks.

Upon receipt of a block proposal, validators must confirm the presence of all referenced transactions within their local mempool. This verification is an absolute requirement—if even a single referenced transaction is missing from the validator's mempool, the entire proposal must be rejected. This stringent validation protocol ensures only widely-distributed transactions are included in the blockchain, safeguarding against potential network state fragmentation.

The process works as follows:

  1. Transaction is added to the node mempool.

  2. Node sends the transaction to all its neighbors.

  3. Neighbors add the transaction to their own mempools and propagate it to their neighbors—transaction is gossiped throughout the network.

  4. Block builder selects a transaction from its local mempool, which is guaranteed to be propagated through the network due to steps 1-3.

  5. Block builder constructs a block proposal with references to selected transactions.

  6. Block proposal is sent through the Blend Network, which requires multiple rounds of gossiping. This introduces a delay that ensures the transaction has reached most of the network participants' mempools.

  7. Block proposal is received by validators.

  8. Validators check their local mempools for all referenced transactions from the proposal.

  9. If any transaction is missing, the entire proposal is rejected.

  10. If all transactions are present, the block proposal is reconstructed and proceeds to further validation steps.

Block Proposal Validation

This section defines the procedure followed by a Nomos node to validate a received block proposal.

Given a Proposal, a proposed block consisting of a header and references. This block proposal is considered valid if the following conditions are met:

Block Validation

The Proposal must satisfy the rules defined in Cryptarchia v1 Protocol Specification - Block Header Validation.

Block Proposal Reconstruction Validation

The references must refer to either a service_reward transaction that is locally derivable or to existing mempool_transaction entries that are retrievable from the node's local mempool.

Mempool Transactions Validation

mempool_transactions must refer to a valid sequence of Mantle Transactions from the mempool. Each transaction must be valid according to the rules defined in the Mantle Specification. In order to verify ZK proofs, they are batched for verification as explained in Batch verification of ZK proofs to get better performances.

Rewards Validation

  1. Check if the first reference matches a deterministically derived Service Rewards Distribution Transaction that distributes previous session service fees as defined in Service Reward Distribution Protocol. It should take no input and output up to service_count * 4 reward notes distributed to the correct validators.

  2. If the above rewarding transactions cannot be derived, then the first reference must refer to a mempool_transaction.

If any of the above checks fail, the block proposal must be rejected.

Block Execution

This section specifies how a Nomos node executes a valid block proposal to update its local state.

Given a ValidBlock that has successfully passed proposal validation, the node must:

  1. Append the leader_voucher contained in the block to the set of reward vouchers when the following epoch starts.

  2. Execute the Mantle Transactions included in the block sequentially, using the execution rules defined in the Mantle Specification.

Annex

Batch verification of ZK proofs

Blob Samples

  1. For each sample the verifier follows the classic cryptographic verification procedure as described in NomosDA Cryptographic Protocol - Verification except the last step, once the verifier has a single commitment C^(i), an aggregated element v^(i) at position u^(i) and one proof π^(i) for each sample.

  2. The verifier draws a random value for each sample r_i ← $F_p.

  3. The verifier computes:

    1. C' := Σ(i=1 to k) r_i · C^(i)

    2. v' := Σ(i=1 to k) r_i · v^(i)

    3. π' := Σ(i=1 to k) r_i · π^(i)

    4. u' := Σ(i=1 to k) r_i · u^(i) · π^(i)

  4. They test if e(C' - v' · G1 + u', G2) = e(π', τ · G2).

Proofs of Claim

  1. For each proof of Claim the verifier collects the classic Groth16 elements required for verification. It includes the proof π^(i), and the public values x_j^(i) for each proof of claim.

  2. The verifier draws one random value for each proof r_i ← $F_p.

  3. The verifier computes:

    1. π'_j := Σ(i=1 to k) r_i · π_j^(i) for j ∈ {A, B, C}.

    2. r' := Σ(i=1 to k) r_i

    3. IC := r' · Ψ_0 + Σ(j=1 to l) (Σ(i=1 to k) r_i · x_j^(i)) · Ψ_j

  4. They test if Σ(i=1 to k) e(r_1 · π'_A, π'_B) = e(r' · [α]_1, [β]_2) + e(IC, [γ]_2) + e(π'_C, [δ]_2).

Note: This batch verification of Groth16 proofs is the same as what is described in the Zcash paper, Appendix B.2.

ZkSignatures

The verifier follows the same procedure as in Proofs of Claim but with the Groth16 proofs of ZkSignatures.

References

Normative

Informative

Copyright and related rights waived via CC0.