Blocks described what a block does. This page describes what it is made of: two objects, one of which is a fixed list of twelve fields.
Two objects, nested
Block
├─ header → Header
│ ├─ version
│ ├─ parentsByLevel[][] → 32-byte block hashes, grouped by level
│ ├─ hashMerkleRoot
│ ├─ acceptedIdMerkleRoot
│ ├─ utxoCommitment
│ ├─ timestamp
│ ├─ bits
│ ├─ nonce
│ ├─ daaScore
│ ├─ blueScore
│ ├─ blueWork
│ └─ pruningPoint
└─ transactions[]
└─ Transaction → the object tree on Transaction Model The header holds no nested objects - twelve scalars and one array of arrays of hashes. This is what lets the header travel on its own: headers-first sync, pruning proofs, and proof-of-work checking all operate on this object without ever fetching a body.
The header
| Field | Holds | Why it exists |
|---|---|---|
version | u16 | Selects how the rest is read. |
parentsByLevel | array of arrays of 32-byte hashes | The blocks this one builds on. See below. |
hashMerkleRoot | 32 bytes | Commits to the transactions in this block’s own body. |
acceptedIdMerkleRoot | 32 bytes | Commits to the transaction ids this block accepts. |
utxoCommitment | 32 bytes | Commits to the whole UTXO set after those acceptances. |
timestamp | u64 | Milliseconds since the Unix epoch, as claimed by the miner. |
bits | u32 | The difficulty target, compactly encoded. |
nonce | u64 | What the miner varies to search for a hash under the target. |
daaScore | u64 | The blocks in this block’s past that the difficulty window counted. |
blueScore | u64 | How many blue blocks are in this block’s past. |
blueWork | 192-bit integer | The work accumulated across those blue blocks. |
pruningPoint | 32 bytes | The pruning point this block commits to. |
Three of these fields are recomputed, not trusted. daaScore, blueScore and blueWork are values the miner writes into the header. Every node recomputes all three from the DAG itself and rejects the block if its own answer differs. They are stored in the header so that a node holding only headers can still order them.
Parents are grouped by level
parentsByLevel is an array of arrays. The outer index is the block level, and only the first one is about consensus ordering.
| Level | Contains | Used for |
|---|---|---|
0 | The tips the miner had seen. At most 16. | GHOSTDAG ordering, mergeset selection, everything a node does with the DAG normally. |
1+ | Sparser links to blocks that themselves cleared a harder target. | Pruning proofs - letting a syncing node verify a long stretch of history without downloading every block in it. |
A block’s own level is not a stored field. It is derived from its hash: a block whose proof of work landed far under the required target would also have satisfied a much harder one, so it counts as a block at every level it could have cleared. These blocks form the skeleton of the pruning proof.
Two consensus limits bound what level 0 can do:
| Limit | Value |
|---|---|
| Max parents (level 0) | 16 |
| Mergeset size limit | 248 |
| GHOSTDAG k | 124 |
The three commitments
The header carries three 32-byte hashes, and the difference between them is the difference between what a block holds, what it decides, and what the ledger becomes.
| Commitment | Covers | Answers |
|---|---|---|
hashMerkleRoot | The transactions in this block’s body | “What is this block carrying?” |
acceptedIdMerkleRoot | The transaction ids this block accepts from its mergeset | “What did this block put into the ledger?” |
utxoCommitment | The full UTXO set once those acceptances are applied | “What does the ledger look like now?” |
The second commitment has no blockchain analogue. A Kaspa block accepts transactions from blocks mined in parallel with it, not only from its own body, so what a block carries and what it settles are different sets and each needs its own commitment.
The third is what makes pruning possible. Because every block commits to the resulting UTXO set, a node that discarded old block data can still prove its current state is the one the DAG arrived at - it does not need the history to re-derive it.
The body
| Field | Holds |
|---|---|
transactions | An ordered array of Transaction objects |
That is the entire body. The ordering is not incidental - the first transaction must be the coinbase, and it is the one transaction in the system with no inputs.
The coinbase’s payload is structured rather than arbitrary:
| Field | Holds |
|---|---|
blueScore | u64 - the blue score of the block carrying it |
subsidy | u64 - the per-block subsidy in sompi |
scriptPublicKey | The payout lock this block’s miner nominates |
extraData | Arbitrary bytes - where pools stamp their own identifiers |
The payout lock is not used to pay this block. It is the address recorded so that whichever later block merges this one can pay it - see rewards in a blockDAG.
What is computed rather than stored
| Value | Where it comes from |
|---|---|
| Block hash | A hash over the header. The identity of the block, the proof work was spent, and the commitment to its contents are the same 32 bytes. |
| Block level | Derived from how far under the target the proof-of-work hash landed. |
| Selected parent | The level-0 parent with the highest blueWork. GHOSTDAG picks it; no field names it. |
| Mergeset | The blocks in this block’s past that are not in its selected parent’s past. |
| Block mass | Summed from the body’s transactions, in three dimensions at once. |
The mass totals are what the block-size limits actually apply to:
| Limit | Value |
|---|---|
| Max compute mass | 500,000 grams |
| Max storage mass | 500,000 grams |
| Max transient mass | 1,000,000 grams - roughly 250 KB of block body, raised from 500,000 at Toccata |
There is no separate per-transaction ceiling in consensus. A transaction only has to fit in a block. Pricing is covered in Fees & Mass.
See Also: Blocks, Transaction Model