<oembed><type>rich</type><version>1.0</version><author_name>npub1e46n428mcyfwznl7nlsf6d3s7rhlwm9x3cmkuqzt3emmdpadmkaqqjxmcu</author_name><author_url>https://nostr.ae/npub1e46n428mcyfwznl7nlsf6d3s7rhlwm9x3cmkuqzt3emmdpadmkaqqjxmcu</author_url><provider_name>njump</provider_name><provider_url>https://nostr.ae</provider_url><html>📅 Original date posted:2016-05-02&#xA;📝 Original message:Hi all,&#xA;&#xA;The following is a BIP-formatted design spec for compact block relay&#xA;designed to limit on wire bytes during block relay. You can find the&#xA;latest version of this document at&#xA;https://github.com/TheBlueMatt/bips/blob/master/bip-TODO.mediawiki.&#xA;&#xA;There are several TODO items left on the document as indicated.&#xA;Additionally, the implementation linked at the bottom of the document&#xA;has a few remaining TODO items as well:&#xA;&#xA; * Only request compact-block-announcement from one or two peers at a&#xA;time, as the spec requires.&#xA; * Request new blocks using MSG_CMPCT_BLOCK where appropriate.&#xA; * Fill prefilledtxn with more than just the coinbase, as noted by the&#xA;spec, up to 10K in transactions.&#xA;&#xA;Luke (CC&#39;d): Can you assign a BIP number?&#xA;&#xA;Thanks,&#xA;Matt&#xA;&#xA;&lt;pre&gt;&#xA;  BIP: TODO&#xA;  Title: Compact block relay&#xA;  Author: Matt Corallo &lt;bip at bluematt.me&gt;&#xA;  Status: Draft&#xA;  Type: Standards Track&#xA;  Created: 2016-04-27&#xA;&lt;/pre&gt;&#xA;&#xA;==Abstract==&#xA;&#xA;Compact blocks on the wire as a way to save bandwidth for nodes on the&#xA;P2P network.&#xA;&#xA;The key words &#34;MUST&#34;, &#34;MUST NOT&#34;, &#34;REQUIRED&#34;, &#34;SHALL&#34;, &#34;SHALL NOT&#34;,&#xA;&#34;SHOULD&#34;, &#34;SHOULD NOT&#34;, &#34;RECOMMENDED&#34;, &#34;MAY&#34;, and &#34;OPTIONAL&#34; in this&#xA;document are to be interpreted as described in RFC 2119.&#xA;&#xA;==Motivation==&#xA;&#xA;Historically, the Bitcoin P2P protocol has not been very bandwidth&#xA;efficient for block relay. Every transaction in a block is included when&#xA;relayed, even though a large number of the transactions in a given block&#xA;are already available to nodes before the block is relayed. This causes&#xA;moderate inbound bandwidth spikes for nodes when receiving blocks, but&#xA;can cause very significant outbound bandwidth spikes for some nodes&#xA;which receive a block before their peers. When such spikes occur, buffer&#xA;bloat can make consumer-grade internet connections temporarily unusable,&#xA;and can delay the relay of blocks to remote peers who may choose to wait&#xA;instead of redundantly requesting the same block from other, less&#xA;congested, peers.&#xA;&#xA;Thus, decreasing the bandwidth used during block relay is very useful&#xA;for many individuals running nodes.&#xA;&#xA;While the goal of this work is explicitly not to reduce block transfer&#xA;latency, it does, as a side effect reduce block transfer latencies in&#xA;some rather significant ways. Additionally, this work forms a foundation&#xA;for future work explicitly targeting low-latency block transfer.&#xA;&#xA;==Specification==&#xA;&#xA;===Intended Protocol Flow===&#xA;TODO: Diagrams&#xA;&#xA;The protocol is intended to be used in two ways, depending on the peers&#xA;and bandwidth available, as discussed [[#Implementation_Details|later]].&#xA;The &#34;high-bandwidth&#34; mode, which nodes may only enable for a few of&#xA;their peers, is enabled by setting the first boolean to 1 in a&#xA;&#34;sendcmpct&#34; message. In this mode, peers send new block announcements&#xA;with the short transaction IDs already, possibly even before fully&#xA;validating the block. In some cases no further round-trip is needed, and&#xA;the receiver can reconstruct the block and process it as usual&#xA;immediately. When some transactions were not available from local&#xA;sources (ie mempool), a getblocktxn/blocktxn roundtrip is neccessary,&#xA;bringing the best-case latency to the same 1.5*RTT minimum time that&#xA;nodes take today, though with significantly less bandwidth usage.&#xA;&#xA;The &#34;low-bandwidth&#34; mode is enabled by setting the first boolean to 0 in&#xA;a &#34;sendcmpct&#34; message. In this mode, peers send new block announcements&#xA;with the usual inv/headers announcements (as per BIP130, and after fully&#xA;validating the block). The receiving peer may then request the block&#xA;using a MSG_CMPCT_BLOCK getdata reqeuest, which will receive a response&#xA;of the header and short transaction IDs. In some cases no further&#xA;round-trip is needed, and the receiver can reconstruct the block and&#xA;process it as usual, taking the same 1.5*RTT minimum time that nodes&#xA;take today, though with significantly less bandwidth usage. When some&#xA;transactions were not available from local sources (ie mempool), a&#xA;getblocktxn/blocktxn roundtrip is neccessary, bringing the best-case&#xA;latency to 2.5*RTT, again with significantly less bandwidth usage than&#xA;today. Because TCP often exhibits worse transfer latency for larger data&#xA;sizes (as a multiple of RTT), total latency is expected to be reduced&#xA;even when full the 2.5*RTT transfer mechanism is used.&#xA;&#xA;===New data structures===&#xA;Several new data structures are added to the P2P network to relay&#xA;compact blocks: PrefilledTransaction, HeaderAndShortIDs,&#xA;BlockTransactionsRequest, and BlockTransactions. Additionally, we&#xA;introduce a new variable-length integer encoding for use in these data&#xA;structures.&#xA;&#xA;For the purposes of this section, CompactSize refers to the&#xA;variable-length integer encoding used across the existing P2P protocol&#xA;to encode array lengths, among other things, in 1, 3, 5 or 9 bytes.&#xA;&#xA;====New VarInt====&#xA;TODO: I just copied this out of the src...Something that is&#xA;wiki-formatted and more descriptive should be used here isntead.&#xA;&#xA;Variable-length integers: bytes are a MSB base-128 encoding of the number.&#xA;The high bit in each byte signifies whether another digit follows. To make&#xA;sure the encoding is one-to-one, one is subtracted from all but the last&#xA;digit.&#xA;Thus, the byte sequence a[] with length len, where all but the last byte&#xA;has bit 128 set, encodes the number:&#xA;&#xA;(a[len-1] &amp; 0x7F) + sum(i=1..len-1, 128^i*((a[len-i-1] &amp; 0x7F)+1))&#xA;&#xA;Properties:&#xA;* Very small (0-127: 1 byte, 128-16511: 2 bytes, 16512-2113663: 3 bytes)&#xA;* Every integer has exactly one encoding&#xA;* Encoding does not depend on size of original integer type&#xA;* No redundancy: every (infinite) byte sequence corresponds to a list&#xA;  of encoded integers.&#xA;&#xA;0:         [0x00]  256:        [0x81 0x00]&#xA;1:         [0x01]  16383:      [0xFE 0x7F]&#xA;127:       [0x7F]  16384:      [0xFF 0x00]&#xA;128:  [0x80 0x00]  16511: [0x80 0xFF 0x7F]&#xA;255:  [0x80 0x7F]  65535: [0x82 0xFD 0x7F]&#xA;2^32:           [0x8E 0xFE 0xFE 0xFF 0x00]&#xA;&#xA;Several uses of New VarInts below are &#34;differentially encoded&#34;. For&#xA;these, instead of using raw indexes, the number encoded is the&#xA;difference between the current index and the previous index, minus one.&#xA;For example, a first index of 0 implies a real index of 0, a second&#xA;index of 0 thereafter refers to a real index of 1, etc.&#xA;&#xA;====PrefilledTransaction====&#xA;A PrefilledTransaction structure is used in HeaderAndShortIDs to provide&#xA;a list of a few transactions explicitly.&#xA;&#xA;{|&#xA;|Field Name||Type||Size||Encoding||Purpose&#xA;|-&#xA;|index||New VarInt||1-3 bytes||[[#New_VarInt|New VarInt]],&#xA;differentially encoded since the last PrefilledTransaction in a&#xA;list||The index into the block at which this transaction is&#xA;|-&#xA;|tx||Transaction||variable||As encoded in &#34;tx&#34; messages||The transaction&#xA;which is in the block at index index.&#xA;|}&#xA;&#xA;====HeaderAndShortIDs====&#xA;A HeaderAndShortIDs structure is used to relay a block header, the short&#xA;transactions IDs used for matching already-available transactions, and a&#xA;select few transactions which we expect a peer may be missing.&#xA;&#xA;{|&#xA;|Field Name||Type||Size||Encoding||Purpose&#xA;|-&#xA;|header||Block header||80 bytes||First 80 bytes of the block as defined&#xA;by the encoding used by &#34;block&#34; messages||The header of the block being&#xA;provided&#xA;|-&#xA;|nonce||uint64_t||8 bytes||Little Endian||A nonce for use in short&#xA;transaction ID calculations&#xA;|-&#xA;|shortids_length||CompactSize||1, 3, 5, or 9 bytes||As used elsewhere to&#xA;encode array lengths||The number of short transaction IDs in shortids&#xA;|-&#xA;|shortids||List of uint64_ts||8*shortids_length bytes||Little&#xA;Endian||The short transaction IDs calculated from the transactions which&#xA;were not provided explicitly in prefilledtxn&#xA;|-&#xA;|prefilledtxn_length||CompactSize||1, 3, 5, or 9 bytes||As used&#xA;elsewhere to encode array lengths||The number of prefilled transactions&#xA;in prefilledtxn&#xA;|-&#xA;|prefilledtxn||List of PrefilledTransactions||variable&#xA;size*prefilledtxn_length||As defined by PrefilledTransaction definition,&#xA;above||Used to provide the coinbase transaction and a select few which&#xA;we expect a peer may be missing&#xA;|}&#xA;&#xA;====BlockTransactionsRequest====&#xA;A BlockTransactionsRequest structure is used to list transaction indexes&#xA;in a block being requested.&#xA;&#xA;{|&#xA;|Field Name||Type||Size||Encoding||Purpose&#xA;|-&#xA;|blockhash||Binary blob||32 bytes||The output from a double-SHA256 of&#xA;the block header, as used elsewhere||The blockhash of the block which&#xA;the transactions being requested are in&#xA;|-&#xA;|indexes_length||New VarInt||1-3 bytes||As defined in [[#New_VarInt|New&#xA;VarInt]]||The number of transactions being requested&#xA;|-&#xA;|indexes||List of New VarInts||1-3 bytes*indexes_length||As defined in&#xA;[[#New_VarInt|New VarInt]], differentially encoded||The indexes of the&#xA;transactions being requested in the block&#xA;|}&#xA;&#xA;====BlockTransactions====&#xA;A BlockTransactions structure is used to provide some of the&#xA;transactions in a block, as requested.&#xA;&#xA;{|&#xA;|Field Name||Type||Size||Encoding||Purpose&#xA;|-&#xA;|blockhash||Binary blob||32 bytes||The output from a double-SHA256 of&#xA;the block header, as used elsewhere||The blockhash of the block which&#xA;the transactions being provided are in&#xA;|-&#xA;|transactions_length||New VarInt||1-3 bytes||As defined in&#xA;[[#New_VarInt|New VarInt]]||The number of transactions provided&#xA;|-&#xA;|transactions||List of Transactions||variable||As encoded in &#34;tx&#34;&#xA;messages||The transactions provided&#xA;|}&#xA;&#xA;====Short transaction IDs====&#xA;Short transaction IDs are used to represent a transaction without&#xA;sending a full 256-bit hash. They are calculated by:&#xA;# single-SHA256 hashing the block header with the nonce appended (in&#xA;little-endian)&#xA;# XORing each 8-byte chunk of the double-SHA256 transaction hash with&#xA;each corresponding 8-byte chunk of the hash from the previous step&#xA;# Adding each of the XORed 8-byte chunks together (in little-endian)&#xA;iteratively to find the short transaction ID&#xA;&#xA;===New messages===&#xA;A new inv type (MSG_CMPCT_BLOCK == 4) and several new protocol messages&#xA;are added: sendcmpct, cmpctblock, getblocktxn, and blocktxn.&#xA;&#xA;====sendcmpct====&#xA;# The sendcmpct message is defined as a message containing a 1-byte&#xA;integer followed by a 8-byte integer where pchCommand == &#34;sendcmpct&#34;.&#xA;# The first integer SHALL be interpreted as a boolean (and MUST have a&#xA;value of either 1 or 0)&#xA;# The second integer SHALL be interpreted as a little-endian version&#xA;number. Nodes sending a sendcmpct message MUST currently set this value&#xA;to 1.&#xA;# Upon receipt of a &#34;sendcmpct&#34; message with the first and second&#xA;integers set to 1, the node SHOULD announce new blocks by sending a&#xA;cmpctblock message.&#xA;# Upon receipt of a &#34;sendcmpct&#34; message with the first integer set to 0,&#xA;the node SHOULD NOT announce new blocks by sending a cmpctblock message,&#xA;but SHOULD announce new blocks by sending invs or headers, as defined by&#xA;BIP130.&#xA;# Upon receipt of a &#34;sendcmpct&#34; message with the second integer set to&#xA;something other than 1, nodes SHOULD treat the peer as if they had not&#xA;received the message (as it indicates the peer will provide an&#xA;unexpected encoding in cmpctblock, and/or other, messages)&#xA;# Nodes SHOULD check for a protocol version of &gt;= 70014 before sending&#xA;sendcmpct messages.&#xA;# Nodes MUST NOT send a request for a MSG_CMPCT_BLOCK object to a peer&#xA;before having received a sendcmpct message from that peer.&#xA;&#xA;====MSG_CMPCT_BLOCK====&#xA;# getdata messages may now contain requests for MSG_CMPCT_BLOCK objects.&#xA;# Upon receipt of a getdata containing a request for a MSG_CMPCT_BLOCK&#xA;object with the hash of a block which was recently announced and after&#xA;having sent the requesting peer a sendcmpct message, nodes MUST respond&#xA;with a cmpctblock message containing appropriate data representing the&#xA;block being requested.&#xA;# MSG_CMPCT_BLOCK inv objects MUST NOT appear anywhere except for in&#xA;getdata messages.&#xA;&#xA;====cmpctblock====&#xA;# The cmpctblock message is defined as as a message containing a&#xA;serialized HeaderAndShortIDs message and pchCommand == &#34;cmpctblock&#34;.&#xA;# Upon receipt of a cmpctblock message after sending a sendcmpct&#xA;message, nodes SHOULD calculate the short transaction ID for each&#xA;unconfirmed transaction they have available (ie in their mempool) and&#xA;compare each to each short transaction ID in the cmpctblock message.&#xA;# After finding already-available transactions, nodes which do not have&#xA;all transactions available to reconstruct the full block SHOULD request&#xA;the missing transactions using a getblocktxn message.&#xA;# A node MUST NOT send a cmpctblock message unless they are able to&#xA;respond to a getblocktxn message which requests every transaction in the&#xA;block.&#xA;# A node MUST NOT send a cmpctblock message without having validated&#xA;that the header properly commits to each transaction in the block, and&#xA;properly builds on top of the existing chain with a valid proof-of-work.&#xA;A node MAY send a cmpctblock before validating that each transaction in&#xA;the block validly spends existing UTXO set entries.&#xA;&#xA;====getblocktxn====&#xA;# The getblocktxn message is defined as as a message containing a&#xA;serialized BlockTransactionsRequest message and pchCommand == &#34;getblocktxn&#34;.&#xA;# Upon receipt of a properly-formatted getblocktxnmessage, nodes which&#xA;recently provided the sender of such a message a cmpctblock for the&#xA;block hash identified in this message MUST respond with an appropriate&#xA;blocktxn message. Such a blocktxn message MUST contain exactly and only&#xA;each transaction which is present in the appropriate block at the index&#xA;specified in the getblocktxn indexes list, in the order requested.&#xA;&#xA;====blocktxn====&#xA;# The blocktxn message is defined as as a message containing a&#xA;serialized BlockTransactions message and pchCommand == &#34;blocktxn&#34;.&#xA;# Upon receipt of a properly-formatted requested blocktxn message, nodes&#xA;SHOULD attempt to reconstruct the full block by:&#xA;## Taking the prefilledtxn transactions from the original cmpctblock and&#xA;placing them in the marked positions.&#xA;## For each short transaction ID from the original cmpctblock, in order,&#xA;find the corresponding transaction either from the blocktxn message or&#xA;from other sources and place it in the first available position in the&#xA;block.&#xA;# Once the block has been reconstructed, it shall be processed as&#xA;normal, keeping in mind that short transaction IDs are expected to&#xA;occasionally collide, and that nodes MUST NOT be penalized for such&#xA;collisions, wherever they appear.&#xA;&#xA;===Implementation Notes===&#xA;# For nodes which have sufficient inbound bandwidth, sending a sendcmpct&#xA;message with the first integer set to 1 to up to three peers is&#xA;RECOMMENDED. If possible, it is RECOMMENDED that those peers be selected&#xA;based on their past performance in providing blocks quickly. This will&#xA;allow them to receive some blocks in only 0.5*RTT between them and the&#xA;sending peer. It will also reduce their block transfer latency in other&#xA;cases due to the smaller amount of data transmitted. Nodes MUST NOT send&#xA;such sendcmpct messages to all peers, as it encourages wasting outbound&#xA;bandwidth across the network.&#xA;&#xA;# All nodes SHOULD send a sendcmpct message to all appropriate peers.&#xA;This will reduce their outbound bandwidth usage by allowing their peers&#xA;to request compact blocks instead of full blocks.&#xA;&#xA;# Nodes with limited inbound bandwidth SHOULD request blocks using&#xA;MSG_CMPCT_BLOCK/getblocktxn requests, when possible. While this&#xA;increases worst-case message round-trips, it is expected to reduce&#xA;overall transfer latency as TCP is more likely to exhibit poor&#xA;throughput on low-bandwidth nodes.&#xA;&#xA;# Nodes sending cmpctblock messages SHOULD make an attempt to not place&#xA;too many transactions into prefilledtxn (ie should limit prefilledtxn to&#xA;only around 10KB of transactions). When in doubt, nodes SHOULD only&#xA;include the coinbase transaction in prefilledtxn.&#xA;&#xA;# Nodes MAY pick one nonce per block they wish to send, and only build a&#xA;cmpctblock message once for all peers which they wish to send a given&#xA;block to. Nodes SHOULD NOT use the same nonce across multiple different&#xA;blocks.&#xA;&#xA;# Nodes MAY impose additional requirements on when they announce new&#xA;blocks by sending cmpctblock messages. For example, nodes with limited&#xA;outbound bandwidth MAY choose to announce new blocks using inv/header&#xA;messages (as per BIP130) to conserve outbound bandwidth.&#xA;&#xA;# Note that the MSG_CMPCT_BLOCK section does not require that nodes&#xA;respond to MSG_CMPCT_BLOCK getdata requests for blocks which they did&#xA;not recently announce. This allows nodes to calculate cmpctblock&#xA;messages at announce-time instead of at request-time. Thus, nodes MUST&#xA;NOT request blocks using MSG_CMPCT_BLOCK getdatas unless it is in&#xA;response to an inv/headers block announcement (as per BIP130), and MUST&#xA;NOT request blocks using MSG_CMPCT_BLOCK getdatas in response to headers&#xA;messages which were, themselves, responses to getheaders requests.&#xA;&#xA;# While the current version sends transactions with the same encodings&#xA;as is used in tx messages and elsewhere in the protocol, the version&#xA;field in sendcmpct is intended to allow this to change in the future.&#xA;For this reason, it is recommended that the code used to decode&#xA;PrefilledTransaction and BlockTransactions messages be prepared to take&#xA;a different transaction encoding, if and when the version field in&#xA;sendcmpct changes in a future BIP.&#xA;&#xA;==Justification==&#xA;&#xA;====Protocol design====&#xA;There have been many proposals to save wire bytes when relaying blocks.&#xA;Many of them have a two-fold goal of reducing block relay time and thus&#xA;rely on the use of significant processing power in order to avoid&#xA;introducing additional worst-case RTTs. Because this work is not focused&#xA;primarily on reducing block relay time, its design is much simpler (ie&#xA;does not rely on set reconciliation protocols). Still, in testing at the&#xA;time of writing, nodes are able to relay blocks without the extra&#xA;getblocktxn/blocktxn RTT around 90% of the time. With a smart&#xA;compact-block-announcement policy, it is thus expected that this work&#xA;might allow blocks to be relayed between nodes in 0.5*RTT instead of&#xA;1.5*RTT at least 75% of the time.&#xA;&#xA;====Use of New VarInts====&#xA;Bitcoin has long had a variable-length integer implementation (referred&#xA;to as CompactSize in this document), making a second a strange protocol&#xA;quirk. However, in this protocol most of our variable-length integers&#xA;are between 0 and 2000. For both encodings, small numbers (&lt;100) are&#xA;encoded as 1-byte. For numbers over 250, the CompactSize encoding begins&#xA;to use 3 bytes instead of 1, whereas the New VarInt encoding uses 2.&#xA;Because the primary motivation for this work is to save bytes during&#xA;block relay, the extra byte of saving per transaction-difference is&#xA;considered worth the extra design complexity.&#xA;&#xA;====Short transaction ID calculation====&#xA;The short transaction ID calculation is designed to take absolutely&#xA;minimal processing time during block compaction to avoid introducing&#xA;serious DoS vulnerabilities such as those introduced by the&#xA;bloom-filtering in BIP 37. As such, it is possible for a node to&#xA;construct one compact-block representation of a block for relay to&#xA;multiple peers. Additionally, only one cryptographic hash (2 SHA rounds)&#xA;is used when calculating the short transaction IDs for an entire block.&#xA;&#xA;The XOR-and-add method is used for calculating short transaction IDs&#xA;primarily because it is fast and is reasonably able to limit the ability&#xA;of an attacker who does not know the block hash or nonce to cause&#xA;collisions in short transaction IDs. If an attacker were able to cause&#xA;such collisions, filling mempools (and, thus, blocks) with them would&#xA;cause poor network propagation of new (or non-attacker, in the case of a&#xA;miner) blocks.&#xA;&#xA;The 8-byte nonce in short transaction ID calculation is used to&#xA;introduce additional entropy on a per-node level. While the use of 8&#xA;bytes is sufficient for an attacker to maliciously cause short&#xA;transaction ID collisions in their own block relay, this would have less&#xA;of an effect than if such an attacker were relaying headers/invs and not&#xA;responding to requests for the full block.&#xA;&#xA;==Backward compatibility==&#xA;&#xA;Older clients remain fully compatible and interoperable after this change.&#xA;&#xA;==Implementation==&#xA;&#xA;https://github.com/TheBlueMatt/bitcoin/tree/udp&#xA;&#xA;==Acknowledgements==&#xA;&#xA;Thanks to Gregory Maxwell for the initial suggestion as well as a lot of&#xA;back-and-forth design and significant testing.&#xA;&#xA;==Copyright==&#xA;&#xA;This document is placed in the public domain.</html></oembed>