.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/network/relay/plot_03_compact_blocks.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code or to run this example in your browser via JupyterLite. .. rst-class:: sphx-glr-example-title .. _sphx_glr_api_gallery_network_relay_plot_03_compact_blocks.py: Compact blocks: send what the peer lacks (Corallo, BIP 152, 2016) ================================================================= By the time a block is found, peers have usually already received most of its transactions as they were broadcast. Matt Corallo's compact blocks (BIP 152) send only the header and a 6-byte short ID per transaction; the receiver rebuilds the block from its mempool and asks for the few it lacks. Short IDs are salted per block, so an attacker cannot craft transactions whose IDs collide in every block. What to look for ---------------- With a full mempool a 500 kB block shrinks to about 12 kB, in a single round trip. The first missing transaction adds a second round trip, and each one must then be sent in full, so the saving shrinks linearly as the mempool's coverage falls. Shrinking the short IDs to a single byte backfires: with 2000 transactions, every ID becomes ambiguous. The history behind this experiment: :doc:`/history/network_breakthroughs`. See :doc:`/exercises/network` for a worked solution to the exercise. .. GENERATED FROM PYTHON SOURCE LINES 26-28 A 2000-transaction block ------------------------ .. GENERATED FROM PYTHON SOURCE LINES 28-43 .. code-block:: Python from random import Random import matplotlib.pyplot as plt import numpy as np import blockchainkit as bk rng = Random(1) block = [rng.randbytes(250) for _ in range(2000)] others = [rng.randbytes(250) for _ in range(3000)] # Unrelated mempool entries. full = bk.network.compact_block_relay(block, block + others) print(f"full {full.full_bytes} bytes, compact {full.compact_bytes} bytes") assert full.missing == 0 and full.round_trips == 1 assert full.compact_bytes < full.full_bytes / 40 .. rst-class:: sphx-glr-script-out .. code-block:: none full 500080 bytes, compact 12088 bytes .. GENERATED FROM PYTHON SOURCE LINES 44-46 As the mempool misses more of the block --------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 46-54 .. code-block:: Python coverage = np.linspace(1.0, 0.5, 11) sizes = [] for c in coverage: known = block[: int(c * len(block))] + others sizes.append(bk.network.compact_block_relay(block, known).compact_bytes) print([round(s / 1000) for s in sizes], "kB") assert sizes[-1] < full.full_bytes .. rst-class:: sphx-glr-script-out .. code-block:: none [12, 37, 63, 88, 113, 138, 163, 189, 214, 239, 264] kB .. GENERATED FROM PYTHON SOURCE LINES 55-57 Short-ID length --------------- .. GENERATED FROM PYTHON SOURCE LINES 57-74 .. code-block:: Python ambiguous = { width: bk.network.compact_block_relay(block, block + others, short_id_size=width).missing for width in (1, 2, 3, 4, 6) } print(ambiguous) assert ambiguous[1] > 1500 and ambiguous[6] == 0 fig, (left, right) = plt.subplots(1, 2, figsize=(10, 4)) left.plot(coverage * 100, np.array(sizes) / 1000, "o-", label="compact") left.axhline(full.full_bytes / 1000, color="black", linestyle="--", label="full block") left.invert_xaxis() left.set(xlabel="% of block in mempool", ylabel="kB sent", title="Compact block size") left.legend() right.bar([str(w) for w in ambiguous], ambiguous.values(), color="#ea580c") right.set(xlabel="short-ID bytes", ylabel="transactions re-requested", title="Collisions") fig.tight_layout() .. image-sg:: /api/gallery/network/relay/images/sphx_glr_plot_03_compact_blocks_001.png :alt: Compact block size, Collisions :srcset: /api/gallery/network/relay/images/sphx_glr_plot_03_compact_blocks_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none {1: 2000, 2: 144, 3: 1, 4: 0, 6: 0} .. GENERATED FROM PYTHON SOURCE LINES 75-80 Exercise -------- With 6-byte short IDs, 2000 block transactions and a 300,000-transaction mempool, estimate the expected number of colliding pairs. Why does BIP 152 still choose 6 bytes rather than 8? .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.425 seconds) .. _sphx_glr_download_api_gallery_network_relay_plot_03_compact_blocks.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: lite-badge .. image:: images/jupyterlite_badge_logo.svg :target: ../../../../lite/lab/index.html?path=api/gallery/network/relay/plot_03_compact_blocks.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_03_compact_blocks.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_03_compact_blocks.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_03_compact_blocks.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_