<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-17&#xA;📝 Original message:Implemented a few of your suggestions.&#xA;&#xA;Also opened a formal pull request for the BIP at&#xA;https://github.com/bitcoin/bips/pull/389 and the code at&#xA;https://github.com/bitcoin/bitcoin/pull/8068.&#xA;&#xA;On 05/09/16 17:06, Pieter Wuille via bitcoin-dev wrote:&#xA;&gt; On 05/03/2016 12:13 AM, lf-lists at mattcorallo.com (Matt Corallo) wrote:&#xA;&gt;&gt; Hi all,&#xA;&gt;&gt;&#xA;&gt;&gt; The following is a BIP-formatted design spec for compact block relay&#xA;&gt;&gt; designed to limit on wire bytes during block relay. You can find the&#xA;&gt;&gt; latest version of this document at&#xA;&gt;&gt; https://github.com/TheBlueMatt/bips/blob/master/bip-TODO.mediawiki.&#xA;&gt; &#xA;&gt; Hi Matt,&#xA;&gt; &#xA;&gt; thank you for working on this!&#xA;&gt; &#xA;&gt;&gt; ===New data structures===&#xA;&gt;&gt; Several new data structures are added to the P2P network to relay&#xA;&gt;&gt; compact blocks: PrefilledTransaction, HeaderAndShortIDs,&#xA;&gt;&gt; BlockTransactionsRequest, and BlockTransactions. Additionally, we&#xA;&gt;&gt; introduce a new variable-length integer encoding for use in these data&#xA;&gt;&gt; structures.&#xA;&gt;&gt;&#xA;&gt;&gt; For the purposes of this section, CompactSize refers to the&#xA;&gt;&gt; variable-length integer encoding used across the existing P2P protocol&#xA;&gt;&gt; to encode array lengths, among other things, in 1, 3, 5 or 9 bytes.&#xA;&gt; &#xA;&gt; This is a not, but I think it&#39;s a bit strange to have two separate&#xA;&gt; variable length integers in the same specification. I understand is one&#xA;&gt; is already the default for variable-length integers currently, and there&#xA;&gt; are reasons to use the other one for efficiency reasons in some places,&#xA;&gt; but perhaps we should aim to get everything using the latter?&#xA;&#xA;Fixed, the whole thing now uses New Varints.&#xA;&#xA;&gt;&gt; ====New VarInt====&#xA;&gt;&gt; Variable-length integers: bytes are a MSB base-128 encoding of the number.&#xA;&gt;&gt; The high bit in each byte signifies whether another digit follows. To make&#xA;&gt;&gt; sure the encoding is one-to-one, one is subtracted from all but the last&#xA;&gt;&gt; digit.&#xA;&gt; &#xA;&gt; Maybe it&#39;s worth mentioning that it is based on ASN.1 BER&#39;s compressed&#xA;&gt; integer format (see&#xA;&gt; https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf&#xA;&gt; section 8.1.3.5), though with a small modification to make every integer&#xA;&gt; have a single unique encoding.&#xA;&gt; &#xA;&gt;&gt; ====HeaderAndShortIDs====&#xA;&gt;&gt; A HeaderAndShortIDs structure is used to relay a block header, the short&#xA;&gt;&gt; transactions IDs used for matching already-available transactions, and a&#xA;&gt;&gt; select few transactions which we expect a peer may be missing.&#xA;&gt;&gt;&#xA;&gt;&gt; |shortids||List of uint64_ts||8*shortids_length bytes||Little&#xA;&gt;&gt; Endian||The short transaction IDs calculated from the transactions which&#xA;&gt;&gt; were not provided explicitly in prefilledtxn&#xA;&gt; &#xA;&gt; I tried to derive what length of short ids is actually necessary (some&#xA;&gt; write-up is on&#xA;&gt; https://gist.github.com/sipa/b2eb2e486156b5509ac711edd16153ed but it&#39;s&#xA;&gt; incomplete).&#xA;&gt; &#xA;&gt; For any reasonable numbers I can come up with (in a very wide range),&#xA;&gt; the number of bits needed is very well approximated by:&#xA;&gt; &#xA;&gt;   log2(#receiver_mempool_txn * #block_txn_not_in_receiver_mempool /&#xA;&gt; acceptable_per_block_failure_rate)&#xA;&gt; &#xA;&gt; For example, with 20000 mempool transactions, 2500 transactions in a&#xA;&gt; block, 95% hitrate, and a chance of 1 in 10000 blocks to fail to&#xA;&gt; reconstruct, needed_bits = log2(20000 * 2500 * (1 - 0.95) / 0.0001) =&#xA;&gt; 34.54, or 5 byte txids would suffice.&#xA;&gt; &#xA;&gt; Note that 1 in 10000 failures may sound like a lot, but this is for each&#xA;&gt; individual connection, and since every transmission uses separately&#xA;&gt; salted identifiers, occasional failures should not affect global&#xA;&gt; propagation. Given that transmission failures due to timeouts, network&#xA;&gt; connectivity, ... already occur much more frequently than once every few&#xA;&gt; gigabytes (what 10000 blocks corresponds to), that&#39;s probably already&#xA;&gt; more than enough.&#xA;&gt; &#xA;&gt; In short: I believe 5 or 6 byte txids should be enough, but perhaps it&#xA;&gt; makes sense to allow the sender to choose (so he can weigh trying&#xA;&gt; multiple nonces against increasing the short txid length).&#xA;&#xA;I switched to 6-byte short txids.&#xA;&#xA;&gt;&gt; ====Short transaction IDs====&#xA;&gt;&gt; Short transaction IDs are used to represent a transaction without&#xA;&gt;&gt; sending a full 256-bit hash. They are calculated by:&#xA;&gt;&gt; # single-SHA256 hashing the block header with the nonce appended (in&#xA;&gt;&gt; little-endian)&#xA;&gt;&gt; # XORing each 8-byte chunk of the double-SHA256 transaction hash with&#xA;&gt;&gt; each corresponding 8-byte chunk of the hash from the previous step&#xA;&gt;&gt; # Adding each of the XORed 8-byte chunks together (in little-endian)&#xA;&gt;&gt; iteratively to find the short transaction ID&#xA;&gt; &#xA;&gt; An alternative would be using SipHash-1-3 (a form of SipHash with&#xA;&gt; reduced iteration counts; the default is SipHash-2-4). SipHash was&#xA;&gt; designed as a Message Authentication Code, where the security&#xA;&gt; requirements are much stronger than in our case (in particular, we don&#39;t&#xA;&gt; care about observers being able to finding the key, as the key is just&#xA;&gt; public knowledge here). One of the designers of SipHash has commented&#xA;&gt; that SipHash-1-3 for collision resistance in hash tables may be enough:&#xA;&gt; https://github.com/rust-lang/rust/issues/29754#issuecomment-156073946&#xA;&gt; &#xA;&gt; Using SipHash-1-3 on modern hardware would take ~32 CPU cycles per txid.&#xA;&#xA;Switched to SipHash2-4.&#xA;&#xA;&gt;&gt; ===Implementation Notes===&#xA;&gt; &#xA;&gt; There are a few more heuristics that MAY be used to improve performance:&#xA;&gt; &#xA;&gt; * Receivers should treat short txids in blocks that match multiple&#xA;&gt; mempool transactions as non-matches, and request the transactions. This&#xA;&gt; significantly reduces the failure to reconstruct.&#xA;&#xA;Done.&#xA;&#xA;&gt; * When constructing a compact block to send, the sender can verify it&#xA;&gt; against its own mempool to check for collisions, and if so, choose to&#xA;&gt; either try another nonce, or increase the short txid length.&#xA;&#xA;Additionally we should compare to the orphan pool (which apparently&#xA;helps a lot).</html></oembed>