diff --git a/README.md b/README.md index 0ab622f..67f9248 100644 --- a/README.md +++ b/README.md @@ -204,6 +204,7 @@ BRC | Standard 138 | [Single-Use Signed Proofs for Request Authentication](./peer-to-peer/0138.md) 139 | [Multicast Shard Manifest Announcement Protocol](./transactions/0139.md) 140 | [Threshold Key Sharing and Backup via Shamir's Secret Sharing Scheme](./key-derivation/0140.md) +144 | [Block Frame Format](./transactions/0144.md) ## License diff --git a/SUMMARY.md b/SUMMARY.md index a6f5c88..c754272 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -72,6 +72,7 @@ * [Multicast Anchor Transaction Frame Format](./transactions/0134.md) * [Multicast Block Header Format](./transactions/0135.md) * [Multicast Shard Manifest Announcement Protocol](./transactions/0139.md) +* [Block Frame Format](./transactions/0144.md) ## Scripts diff --git a/transactions/0144.md b/transactions/0144.md new file mode 100644 index 0000000..7c131f2 --- /dev/null +++ b/transactions/0144.md @@ -0,0 +1,117 @@ +# BRC-144: Block Frame Format + +Jeff Harris (jeff@lightweb.net) + +## Abstract + +This BRC specifies the push wire form of a **block** — the 80-byte block header, +block-level counts, the ordered list of subtree roots the block references, the +full coinbase transaction, the block height, and the coinbase merkle path — for +delivery and ingest over a byte stream. It carries everything a receiver needs to +assemble and validate the block without a follow-up fetch. All frame integers are +fixed-width big-endian; consensus-defined payloads (the header, the coinbase +transaction, the BUMP) keep their native serialisation. + +## Copyright + +This BRC is licensed under the Open BSV License. + +## Motivation + +A block commits to its transactions through a header and names the subtrees it +references in order — the block↔subtree association that binds independently +delivered subtrees ([BRC-143](./0143.md)) into a block and fixes their order for +merkle assembly. + +In an announce/pull system a node is *notified* of a block (hash, height, a fetch +URL) and then pulls the full block on demand. A **push** delivery has no fetch +URL: the block arrives whole and unsolicited, so the frame carries the complete +block body inline. Its field sequence mirrors the block serialisation a node +already ingests — header, counts, subtree roots, the full coinbase, height, and +the coinbase BUMP — with each variable-length integer replaced by a fixed-width +big-endian field. The coinbase is carried **in-band** because it cannot be +delivered as a loose transaction (a node rejects a standalone coinbase on its +transaction path) and the block assembly needs its bytes. + +## Specification + +### Frame layout + +All frame integers are big-endian. Hashes are in internal byte order. The +embedded block header, coinbase transaction, and coinbase BUMP keep their native +serialisations. + +```text +| Size | Field | Notes | +|--------|-------------------|--------------------------------------------------------------------| +| 80 | BlockHeader | Standard 80-byte block header (below). | +| 8 | TransactionCount | uint64 BE. Total transactions committed by the block. | +| 8 | SizeInBytes | uint64 BE. Total serialized block size. | +| 8 | SubtreeCount (M) | uint64 BE. Number of subtree roots that follow. | +| 32 × M | SubtreeHashes | Ordered subtree merkle roots, each 32 bytes. | +| * | Coinbase | Full coinbase transaction (BRC-12), self-delimiting by structure. | +| 8 | Height | uint64 BE. Block height. | +| 8 | CoinbaseBUMPLen | uint64 BE. Byte length of the coinbase BUMP that follows. | +| * | CoinbaseBUMP | BRC-74 merkle path of the coinbase; present only when `CoinbaseBUMPLen > 0`. | +``` + +Fixed prefix through `SubtreeCount` is **104 bytes**; `SubtreeHashes`, `Coinbase`, +and `CoinbaseBUMP` are variable. The `Coinbase` has no length prefix — it is +self-delimiting by transaction structure (version, input/output vectors, +locktime), so a reader parses it and resumes at `Height`. + +The field order and semantics mirror the block body a node serialises natively; +this frame is that body with fixed-width big-endian counts in place of variable +integers. + +### Block header (80 bytes) + +The standard block header, consensus byte layout: + +| Offset | Size | Field | Encoding | +| ------ | ---- | ------------------- | ----------------------------------------------- | +| 0 | 4 | Version | uint32 little-endian | +| 4 | 32 | Previous block hash | SHA256d, internal byte order | +| 36 | 32 | Merkle root | SHA256d of the tx tree, internal byte order | +| 68 | 4 | Timestamp | uint32 little-endian (Unix seconds) | +| 72 | 4 | nBits | uint32 little-endian (compact difficulty target)| +| 76 | 4 | Nonce | uint32 little-endian | + +`BlockHash = SHA256d(BlockHeader)` — the receiver computes it from the 80 bytes; +there is no separate block-hash field. The previous-block hash (bytes 4–35) gives +chain context intrinsically. Block height is not present in a block header (it +appears in the coinbase per BIP-34) and is carried explicitly as the `Height` +field so the receiver need not extract it. + +### Coinbase and subtree association + +`SubtreeHashes` is ordered to match the producer's subtree enumeration — the order +used to assemble the block merkle root from the subtree roots. A block's **first** +subtree ([BRC-143](./0143.md)) carries the `0xFF × 32` coinbase placeholder at its +first node; the receiver substitutes the coinbase transaction carried here into +that slot when it reconstructs the block. + +The coinbase is the full transaction, not just its identifier: a node rejects a +loose coinbase on its transaction-ingest path, so it is delivered only here, and +block assembly consumes its bytes directly. + +## Identity + +Block identity is `BlockHash = SHA256d(BlockHeader)`. The block's committed merkle +root (header bytes 36–67) is the value a receiver reproduces from the ordered +subtree roots and the coinbase; there is no separate identifier field. + +## References + +- [BRC-143: Subtree Data Frame Format](./0143.md) — the subtrees this block orders; + the block↔subtree association lives here, not in the subtree frame +- [BRC-74: BSV Unified Merkle Path (BUMP) Format](./0074.md) — the `CoinbaseBUMP` + payload +- [BRC-12: Raw Transaction Format](./0012.md) — the coinbase transaction body + +## Constants Reference + +| Name | Value | Description | +| ----------------- | ----- | ------------------------------------------------- | +| BlockFramePrefix | 104 | Header + TransactionCount + SizeInBytes + SubtreeCount, in bytes | +| BlockHeaderSize | 80 | Block header, in bytes | diff --git a/transactions/README.md b/transactions/README.md index de07c8e..23695b7 100644 --- a/transactions/README.md +++ b/transactions/README.md @@ -34,3 +34,4 @@ BRC | Standard 134 | [Multicast Anchor Transaction Frame Format](./0134.md) 135 | [Multicast Block Header Format](./0135.md) 139 | [Multicast Shard Manifest Announcement Protocol](./0139.md) +144 | [Block Frame Format](./0144.md)