11. Blocks and headers
A block is the unit that consensus orders and finalizes. Its header carries the chain link and the commitments a verifier needs, and its body carries the application data those commitments cover. This chapter defines both, fixes the block hash, states the rules that bind a block's timestamp, and gives the counter widths and size limits that bound a block. Section 12 states what makes a block valid.
11.1 Block structure
A block is a header and a body. A header carries the chain link, the three authenticated database targets, the command commitment, and the profile-dependent payload hashes. A body carries the ordered commands and the profile-dependent consensus payloads. The block hash is the digest of the canonical header bytes and is the value a finalization certificate covers.
Header {
height, timestamp_ms, parent_hash, consensus_context,
active_release_digest, # release in force at this height, section 18
state_root, # canonical current root
state_target {ops_root, floor, size},
membership_target {root, floor, size},
history_target {root, size}, # block-history accumulator, section 9
command_root, command_count, # stateless BMT over Keccak256(canonical(SignedCommand))
genesis_epoch_info_hash?,
dealer_log_hash?, dkg_outcome_hash?
}
Body { commands, genesis_epoch_info?, dealer_log?, dkg_outcome? }
block_hash = Keccak256("makechain.block-header" || canonical(Header))
block_hash is the first step of the Keccak256 proof path of section 6. Simplex signs that native
32-byte digest, so a finalization certificate covers exactly this value.
The native instantiations and exact wire types are fixed by encoding section 9: MMR
with Keccak256 for all three QMDB members, a 64-byte current-state bitmap chunk, native
bmt::Builder<Keccak256> for command roots, and threshold VRF Simplex with MinSig. Native
location, proof, target, directory, and DKG codecs are the pinned library's codecs, never Makechain
replicas.
11.2 Header fields
| Field | Meaning | Derived or proposer-chosen | Hash |
|---|---|---|---|
height |
block number from genesis (section 3) | derived from the parent | Keccak256 proof path |
timestamp_ms |
consensus time of this block in Unix milliseconds (section 11.4) | proposer-chosen, bounded by section 11.4 | Keccak256 proof path |
parent_hash |
the parent's block_hash |
derived from the parent | Keccak256 proof path |
consensus_context |
the consensus round context of this block, including its epoch | derived from the consensus round and the profile's epocher (sections 5 and 13) | Keccak256 proof path |
active_release_digest |
the release in force at this height (section 18) | derived by active_release(h) from the executing parent's schedule |
BLAKE3 value, covered by block_hash |
state_root |
canonical current root of the validity state (section 9) |
derived by re-executing the block | Keccak256 proof path |
state_target {ops_root, floor, size} |
the validity state's operation target, used by sync and reconciliation | derived by re-executing the block | Keccak256 proof path |
membership_target {root, floor, size} |
the permanent membership log's root, committed inactivity floor, and size (section 9) | derived by re-executing the block | Keccak256 proof path |
history_target {root, size} |
the block-history accumulator's root and size (section 9) | derived by re-executing the block | Keccak256 proof path |
command_root |
root over the block's commands in execution order, whose leaves are the Keccak256 digests of their canonical signed envelopes | derived by re-executing the block | Keccak256 proof path |
command_count |
the number of commands in the block | derived by re-executing the block | Keccak256 proof path |
genesis_epoch_info_hash? |
BLAKE3 digest under the registered domain makechain.genesis-epoch-info, over the exact pinned native inner encoding of the genesis_epoch_info body field (section 11.3) |
derived from the body | BLAKE3 value, covered by block_hash |
dealer_log_hash? |
BLAKE3 digest under the registered domain makechain.dealer-log, over the exact pinned native inner encoding of the dealer_log body field (section 11.3) |
derived from the body | BLAKE3 value, covered by block_hash |
dkg_outcome_hash? |
BLAKE3 digest under the registered domain makechain.dkg-outcome, over the exact pinned native inner encoding of the dkg_outcome body field (section 11.3) |
derived from the body | BLAKE3 value, covered by block_hash |
The three payload-hash domains are registered in encoding section 11. Those three
digests are not on the Keccak256 proof path of section 6; each reaches the proof path only as an
opaque 32-byte header field covered by block_hash.
R-11.1. A verifier MUST re-derive every header field and MUST reject the block if any re-derived value differs from the committed value, and MUST NOT accept a header field on the ground that it is well encoded.
R-11.2. The application MUST itself reject a canonical state_root mismatch, because the glue
wrapper checks only the ops target (section 12).
R-11.3. command_root is the root of a stateless binary Merkle tree instantiated with Keccak256
whose leaf for each command, in execution order, is Keccak256(canonical(SignedCommand)) over that
command's complete signed envelope, so a verifier recomputes a leaf from the envelope bytes alone
(section 6); command_count is the number of those leaves, and command_id stays the BLAKE3
envelope identity of section 6.
INV-CONS-02. Every derived header field is re-derived and must equal the committed value.
INV-CONS-05.
command_rootbinds the complete signed envelopes in execution order; events never alter it.
11.3 Body and profile-gated fields
genesis_epoch_info contains the profile-specific epoch-zero EpochInfo of section 5, and both
consensus profiles require it. The DKG fields are separate canonical options whose admissibility is
fixed by consensus_profile.
R-11.4. genesis_epoch_info is present exactly at height zero, genesis_epoch_info_hash MUST
equal the digest of its canonical bytes under the domain of section 11.2, and every non-genesis
block requires both fields to be None.
R-11.5. Under DynamicReshareV1 the body payloads map as follows, and a block that carries both
dealer_log and dkg_outcome is invalid.
| Height | Mapping |
|---|---|
| genesis | genesis_epoch_info maps to Some(Payload::EpochInfo(genesis_epoch_info)), as the orchestrator requires, while dealer_log and dkg_outcome are both None |
| later heights | dealer_log -> Payload::DealerLog, or dkg_outcome -> Payload::EpochInfo, the two being mutually exclusive |
| later heights, neither present | None |
R-11.6. DynamicReshareV1 uses the DKG fields only under the reshare rules of section 13.
R-11.7. Under FixedEpochZeroV1, dealer_log_hash, dkg_outcome_hash, dealer_log, and
dkg_outcome MUST all encode as None in every block, including genesis, and any Some value in
those four fields is invalid, including a Some containing an empty payload.
R-11.8. An implementation MUST NOT normalize presence to absence in those fields, and MUST NOT retain profile-private block fields outside the canonical options of section 11.1.
R-11.9. The finalization certificate is never a header or body field, and it travels on the response envelope and in the store of section 17.
The FixedEpochZeroV1 assembly has no reshare wrapper and does not map its genesis artifact into a
live DKG actor.
INV-CONS-08. Under
FixedEpochZeroV1, every consensus context and ancestry relation is in epoch zero and every DKG payload option isNone; a nonzero epoch or any present payload is invalid.
11.4 Block time
Timestamps are Unix milliseconds. The clock model is partial synchrony with a bounded honest skew.
R-11.10. A proposer stamps a non-empty block
min(max(local_now, parent + 1), parent + max_block_advance_ms), and paces empty blocks by
min_empty_block_interval_ms.
R-11.11. A block is invalid if its timestamp does not exceed the parent's timestamp or exceeds
parent + max_block_advance_ms.
R-11.12. A verifier MUST wait rather than vote a block invalid when that block is stamped in the future and within range, and that wait is the only wall-clock dependence in consensus, so validity never otherwise depends on a validator's local clock.
The stamping formula lets chain time catch up over several blocks after a long pause, and the
parent-relative bound limits how far one block can move chain time. max_block_advance_ms, the
empty-block interval, the clock skew, and the collateral delay under concurrent verification are
calibration items (section 19). The companion documents refine these rules under concurrent,
cancellable verification, including the collateral-delay measurement.
INV-FAULT-02. No honest validator decides a command or block differently from another because of its wall clock.
INV-FAULT-03. An honest validator waits rather than votes on a future-stamped proposal.
11.5 Counter widths and block size
R-11.13. Heights, epochs, sequences, and counters are 64-bit, and each rejects its maximum value.
R-11.14. max_block_bytes is a chainspec validity limit under a structural ceiling, and the p2p
ceiling MUST be proven to fit the largest legal block end to end.
A chain that reaches a counter maximum has ended and requires a reset (section 5). The block byte limit and the choice between the standard and coding marshal variants of section 13 are one coupled decision.
11.6 Rationale
This subsection is informative.
The block hash is Keccak256 because it is what a contract on another chain hashes to open a certified header. The header keeps its own canonical encoding rather than an Ethereum header shape, since such a contract needs the digest, not the layout. Every header field is re-derived because a field that is merely well encoded is the one field a Byzantine proposer controls. Time is parent-relative with a bounded advance so that validity never depends on a validator's clock except through a bounded wait on a future-stamped block.