<oembed><type>rich</type><version>1.0</version><author_name>npub12jllrss5nmygfhg7j9ztk2te80t96kumx7cllfc29skut6phqh5qfhfxgj</author_name><author_url>https://nostr.ae/npub12jllrss5nmygfhg7j9ztk2te80t96kumx7cllfc29skut6phqh5qfhfxgj</author_url><provider_name>njump</provider_name><provider_url>https://nostr.ae</provider_url><html>📅 Original date posted:2020-05-11&#xA;📝 Original message:Thanks for resurrecting this idea for discussion Will.&#xA;&#xA;I see three reasons for reducing block header bandwidth:&#xA;&#xA; 1. support for long range block header broadcast via alternative&#xA;communication modalities like radio where every byte counts&#xA; 2. where repurposed mobile devices with SPV wallets are used because&#xA;metered bandwidth and hardware costs are high relative to income&#xA; 3. full nodes could potentially support twice as many header only peers&#xA;(is that a thing?) for better eclipse protection&#xA;&#xA;Nodes could also run an additional daemon (eg. electrs) that serves&#xA;compressed block headers to light clients, but then it would be less likely&#xA;to see widespread use to reduce bandwidth between full nodes.&#xA;&#xA;What are the negatives?&#xA; - higher computation? probably minimal compared to serving the same&#xA;uncompressed headers.&#xA; - memory for caching the last few versions? bounded to last seven, so not&#xA;too large.&#xA; - complexity/bugs? minor and opt in for node operators, though you could&#xA;argue the gain isn&#39;t worth any kind of change for nodes with high bandwidth&#xA;connections.&#xA; - use of low-bandwidth light clients should not be encouraged? that is a&#xA;separate discussion, but I do not currently see any proposals to remove&#xA;light client support.&#xA;&#xA;I&#39;m curious what other people think. Are the motivations enough to justify&#xA;a change to the protocol that produces a high percentage (but low absolute)&#xA;bandwidth reduction for transmitting block headers?&#xA;&#xA;  -- Richard&#xA;&#xA;On Fri, May 8, 2020 at 3:34 PM Will Clark via bitcoin-dev &lt;&#xA;bitcoin-dev at lists.linuxfoundation.org&gt; wrote:&#xA;&#xA;&gt; Hello list,&#xA;&gt;&#xA;&gt; I would like to propose a compressed block header scheme for IBD and block&#xA;&gt; announcements. This proposal is derivative of previous proposals found on&#xA;&gt; this list (see links in spec below) with some modifications and&#xA;&gt; clarifications.&#xA;&gt;&#xA;&gt; The below specification (also found at&#xA;&gt; https://github.com/willcl-ark/compressed-block-headers/blob/v1.0/compressed-block-headers.adoc&#xA;&gt; ) details the compression recommended along with the generated bandwidth&#xA;&gt; savings in the best-case scenario.&#xA;&gt;&#xA;&gt; I look forward to any feedback anyone has to offer on the specification&#xA;&gt; itself, as well as any additions or objections to the motivation.&#xA;&gt;&#xA;&gt; Cheers,&#xA;&gt; Will&#xA;&gt;&#xA;&gt;&#xA;&gt; = Compressed block headers&#xA;&gt; Will Clark &lt;will8clark at gmail.com&gt;&#xA;&gt; v1.0, May 2020:&#xA;&gt; :toc: preamble&#xA;&gt; :toclevels: 4&#xA;&gt;&#xA;&gt;&#xA;&gt; This work is a derivation of these mailing list posts:&#xA;&gt;&#xA;&gt; 1.&#xA;&gt; https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2017-August/014876.html[bitcoin-dev:&#xA;&gt; &#34;Compressed&#34; headers stream - 2017] (with resurrection&#xA;&gt; https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2017-December/015385.html[here]&#xA;&gt; )&#xA;&gt;&#xA;&gt; 2.&#xA;&gt; https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-March/015851.html[bitcoin-dev:&#xA;&gt; Optimized Header Sync]&#xA;&gt;&#xA;&gt; &#39;&#39;&#39;&#xA;&gt;&#xA;&gt; == Motivation&#xA;&gt;&#xA;&gt; Block headers as exchanged by nodes over the p2p network are currently 81&#xA;&gt; bytes each.&#xA;&gt;&#xA;&gt; For low bandwidth nodes who are doing a headers-only sync, reducing the&#xA;&gt; size of the headers can provide a significant bandwidth saving. Also, nodes&#xA;&gt; can support more header-only peers for IBD and protection against eclipse&#xA;&gt; attacks if header bandwidth is reduced.&#xA;&gt;&#xA;&gt; === Background&#xA;&gt;&#xA;&gt; Currently headers are sent over the p2p network as a vector of&#xA;&gt; `block_headers`, which are composed of the following sized fields:&#xA;&gt;&#xA;&gt; [cols=&#34;&lt;,&gt;&#34;]&#xA;&gt; |===&#xA;&gt; |Field               |Size&#xA;&gt;&#xA;&gt; |Version             |4 bytes&#xA;&gt; |Previous block hash |32 bytes&#xA;&gt; |Merkle root hash    |32 bytes&#xA;&gt; |Time                |4 bytes&#xA;&gt; |nBits               |4 bytes&#xA;&gt; |nonce               |4 bytes&#xA;&gt; |txn_count           |1 byte&#xA;&gt; |*Total*             |81 bytes&#xA;&gt; |===&#xA;&gt;&#xA;&gt; Some fields can be removed completely, others can be compressed under&#xA;&gt; certain conditions.&#xA;&gt;&#xA;&gt; == Proposed specification&#xA;&gt;&#xA;&gt; === block_header2 data type&#xA;&gt;&#xA;&gt; The following table illustrates the proposed `block_header2` data type&#xA;&gt; specification.&#xA;&gt;&#xA;&gt; [cols=&#34;&lt;,&gt;,&gt;&#34;]&#xA;&gt; |===&#xA;&gt; |Field               |Size     |Compressed&#xA;&gt;&#xA;&gt; |Bitfield            |1 byte   | 1 byte&#xA;&gt; |Version             |4 bytes  |0 \| 4 bytes&#xA;&gt; |Previous block hash |32 bytes |0 \| 32 bytes&#xA;&gt; |Merkle root hash    |32 bytes |32 bytes&#xA;&gt; |Time                |4 bytes  |2 \| 4 bytes&#xA;&gt; |nBits               |4 bytes  |0 \| 4 bytes&#xA;&gt; |nonce               |4 bytes  |4 bytes&#xA;&gt; |*Total*             |81 bytes |range: 39 - 81 bytes&#xA;&gt; |===&#xA;&gt;&#xA;&gt; This compression results in a maximum reduction from an 81 byte header to&#xA;&gt; best-case 39 byte header. With 629,474 blocks in the current blockchain, a&#xA;&gt; continuous header sync from genesis (requiring a single full 81 byte header&#xA;&gt; followed by only compressed `block_header2`) has been tested to have its&#xA;&gt; required bandwidth reduced from 50.98MB down to 25.86MB, a saving of 49%.&#xA;&gt;&#xA;&gt; ==== Bitfield&#xA;&gt;&#xA;&gt; To make parsing of header messages easier and further increase header&#xA;&gt; compression, a single byte bitfield was suggested by gmaxwell footnote:[&#xA;&gt; https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2017-December/015397.html].&#xA;&gt; We propose the following amended bitfield meanings (bits re-ordered to&#xA;&gt; match `headers2` field order):&#xA;&gt;&#xA;&gt; [cols=&#34;&lt;,&lt;&#34;]&#xA;&gt; |===&#xA;&gt; |Bit |Meaning + field size to read&#xA;&gt;&#xA;&gt; |0 +&#xA;&gt; 1 +&#xA;&gt; 2    |version: same as the last *distinct* value 1st ... 7th (0 byte&#xA;&gt; field) or a new 32bit distinct value (4 byte field).&#xA;&gt; |3   |prev_block_hash: is omitted (0 byte field) or included (32 byte&#xA;&gt; field)&#xA;&gt; |4   |timestamp: as small offset (2 byte field) or full (4 byte field).&#xA;&gt; |5   |nbits: same as last header (0 byte field) or new (4 byte field).&#xA;&gt; |6   |possibly to signal &#34;more headers follow&#34; to make the encoding&#xA;&gt; self-delimiting.&#xA;&gt; |7   |currently undefined&#xA;&gt; |===&#xA;&gt;&#xA;&gt; This bitfield adds 1 byte for every block in the chain, for a current&#xA;&gt; total increase of 629,474B.&#xA;&gt;&#xA;&gt; ==== Version&#xA;&gt;&#xA;&gt; In most cases the Version field will be identical to one referenced in one&#xA;&gt; of the previous 7 unique versions, as indicated by bits 0,1,2 of the&#xA;&gt; Bitfield.&#xA;&gt;&#xA;&gt; To block 629,474 there were 616,137 blocks whose version was in the&#xA;&gt; previous 7 distinct versions, and only 13,338 blocks whose version was not,&#xA;&gt; this includes any version bit manipulation done via overt ASIC boost.&#xA;&gt;&#xA;&gt; [cols=&#34;&gt;,&gt;,&gt;,&gt;&#34;]&#xA;&gt; |===&#xA;&gt; |Genesis to block |Current (B) |Compressed (B) |Saving (%)&#xA;&gt;&#xA;&gt; |629,474          |2,517,896   |53,352         |98&#xA;&gt; |===&#xA;&gt;&#xA;&gt; ==== Previous block hash&#xA;&gt;&#xA;&gt; The previous block hash will always be the&#xA;&gt; `SHA256(SHA256(&lt;previous_header&gt;))` so is redundant, presuming you have&#xA;&gt; the previous header in the chain.&#xA;&gt;&#xA;&gt; [cols=&#34;&gt;,&gt;,&gt;,&gt;&#34;]&#xA;&gt; |===&#xA;&gt; |Genesis to block |Current (B) |Compressed (B) |Saving (%)&#xA;&gt;&#xA;&gt; |629,474          |20,143,168  |0              |100&#xA;&gt; |===&#xA;&gt;&#xA;&gt; ==== Time&#xA;&gt;&#xA;&gt; The timestamp (in seconds) is consensus bound, based both on the time in&#xA;&gt; the previous&#xA;&gt; header: `MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60 = 7200`, and being greater&#xA;&gt; than the `MedianTimePast` of the previous 11 blocks. Therefore this can be&#xA;&gt; safely represented as an offset from the previous headers&#39; timestamp using&#xA;&gt; a 2 byte `signed short int`.&#xA;&gt;&#xA;&gt; [cols=&#34;&gt;,&gt;,&gt;,&gt;&#34;]&#xA;&gt; |===&#xA;&gt; |Genesis to block |Current (B) |Compressed (B) |Saving (%)&#xA;&gt;&#xA;&gt; |629,474          |2,517,896   |1,258,952      |50&#xA;&gt; |===&#xA;&gt;&#xA;&gt; ==== nBits&#xA;&gt;&#xA;&gt; nBits currently changes once every 2016 blocks. It could be entirely&#xA;&gt; calculated by the client from the timestamps of the previous 2015 blocks&#xA;&gt; footnote:[2015 blocks are used in the adjustment calculation due to an&#xA;&gt; off-by-one error:&#xA;&gt; https://bitcointalk.org/index.php?topic=43692.msg521772#msg521772&#34;].&#xA;&gt;&#xA;&gt; To simplify &#39;light&#39; client implementations which would otherwise require&#xA;&gt; consensus-valid calculation of the adjustments, we propose to transmit this&#xA;&gt; according to the &lt;&lt;Bitfield&gt;&gt; specification above.&#xA;&gt;&#xA;&gt; To block 629,474 there have been 298 nBits adjustments (vs an expected 311&#xA;&gt; -- there was none before block 32,256).&#xA;&gt;&#xA;&gt; [cols=&#34;&gt;,&gt;,&gt;,&gt;&#34;]&#xA;&gt; |===&#xA;&gt; |Genesis to block |Current (B) |Compressed (B) |Saving (%)&#xA;&gt;&#xA;&gt; |629,474          |2,517,896   |1,196          |99.6&#xA;&gt; |===&#xA;&gt;&#xA;&gt; ==== txn_count&#xA;&gt;&#xA;&gt; txn_count is included to make parsing of these messages compatible with&#xA;&gt; parsing of `block` messages footnote:[&#xA;&gt; https://bitcoin.stackexchange.com/questions/2104/why-is-the-block-header-txn-count-field-always-zero].&#xA;&gt; Therefore this field and its associated byte can be removed for&#xA;&gt; transmission of compact headers.&#xA;&gt;&#xA;&gt; [cols=&#34;&gt;,&gt;,&gt;,&gt;&#34;]&#xA;&gt; |===&#xA;&gt; |Genesis to block |Current (B) |Compressed (B) |Saving (%)&#xA;&gt;&#xA;&gt; |629,474          |629,474     |0              |100&#xA;&gt; |===&#xA;&gt;&#xA;&gt; === Service Bit&#xA;&gt;&#xA;&gt; A new service bit would be required so that the nodes can advertise their&#xA;&gt; ability to supply compact headers.&#xA;&gt;&#xA;&gt; === P2P Messages&#xA;&gt;&#xA;&gt; Three new messages would be used by nodes that enable compact block header&#xA;&gt; support, two query messages: `getheaders2` and `sendheaders2` and one&#xA;&gt; response: `headers2`.&#xA;&gt;&#xA;&gt; ==== `getheaders2` -- Requesting compact headers&#xA;&gt;&#xA;&gt; The new p2p message required to request compact block headers would&#xA;&gt; require the same fields as the current `getheaders` message:&#xA;&gt;&#xA;&gt; [cols=&#34;&gt;,&lt;,&lt;,&lt;&#34;]&#xA;&gt; |===&#xA;&gt; |Field Size |Description          |Data type |Comments&#xA;&gt;&#xA;&gt; |4          |version              |uint32_t  |the protocol version&#xA;&gt; |1+         |hash count           |var_int   |number of block locator hash&#xA;&gt; entries&#xA;&gt; |32+        |block locator hashes |char[32]  |block locator object; newest&#xA;&gt; back to genesis block (dense to start, but then sparse)&#xA;&gt; |32         |hash_stop            |char[32]  |hash of the last desired&#xA;&gt; block header; set to zero to get as many blocks as possible (2000)&#xA;&gt; |===&#xA;&gt;&#xA;&gt; ==== `sendheaders2` -- Request compact header announcements&#xA;&gt;&#xA;&gt; Since&#xA;&gt; https://github.com/bitcoin/bips/blob/master/bip-0130.mediawiki[BIP-130],&#xA;&gt; nodes have been able to request to receive new headers directly in&#xA;&gt; `headers` messages, rather than via an `inv` of the new block hash and&#xA;&gt; subsequent `getheader` request and `headers` response (followed by a final&#xA;&gt; `getdata` to get the tip block itself, if desired). This is requested by&#xA;&gt; transmitting an empty `sendheaders` message after the version handshake is&#xA;&gt; complete.]&#xA;&gt;&#xA;&gt; Upon receipt of this message, the node is permitted, but not required, to&#xA;&gt; preemptively announce new headers with the `headers2` message (instead of&#xA;&gt; `inv`). Preemptive header announcement is supported by the protocol version&#xA;&gt; ≥ 70012 | Bitcoin Core version ≥ 0.12.0.&#xA;&gt;&#xA;&gt; For the motivational use-case it makes sense to also update this mechanism&#xA;&gt; to support sending header updates using compact headers using a new message.&#xA;&gt;&#xA;&gt; ==== `headers2` -- Receiving compact headers&#xA;&gt;&#xA;&gt; A `headers2` message is returned in response to `getheaders2` or at new&#xA;&gt; header announcement following a `sendheaders2` request. It contains both&#xA;&gt; `length` and `headers` fields. The `headers` field contains a variable&#xA;&gt; length vector of `block_header2`:&#xA;&gt;&#xA;&gt; |===&#xA;&gt; |Field Size |Description |Data type       |Comments&#xA;&gt;&#xA;&gt; |1+         |length      |var_int         |Length of `headers`&#xA;&gt; |39-81x?    |headers     |block_header2[] |Compressed block headers in&#xA;&gt; &lt;&lt;block_header2 data type&gt;&gt; format&#xA;&gt; |===&#xA;&gt;&#xA;&gt; === Implementation&#xA;&gt;&#xA;&gt; * The first header in the first `block_header2[]` vector to a&#xA;&gt; newly-connected client MUST contain the full nBits`, `timestamp`, `version`&#xA;&gt; and `prev_block_hash` fields, along with a correctly populated `bitfield`&#xA;&gt; byte.&#xA;&gt; * Subsequent headers in a contiguous vector SHOULD follow the compressed&#xA;&gt; &lt;&lt;block_header2 data type&gt;&gt; format.&#xA;&gt; * Subsequent compressed headers supplied to an already-connected client&#xA;&gt; (requesting compressed headers), SHOULD follow the compressed&#xA;&gt; &lt;&lt;block_header2 data type&gt;&gt; format.&#xA;&gt;&#xA;&gt;&#xA;&gt;&#xA;&gt;&#xA;&gt;&#xA;&gt; _______________________________________________&#xA;&gt; bitcoin-dev mailing list&#xA;&gt; bitcoin-dev at lists.linuxfoundation.org&#xA;&gt; https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev&#xA;&gt;&#xA;&#xA;&#xA;-- &#xA;Richard Myers&#xA;Decentralized Applications Engineer, goTenna&#xA;gotenna.com&#xA;@gotenna&#xA;-------------- next part --------------&#xA;An HTML attachment was scrubbed...&#xA;URL: &lt;http://lists.linuxfoundation.org/pipermail/bitcoin-dev/attachments/20200511/dc570025/attachment-0001.html&gt;</html></oembed>