.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/consensus/nakamoto/plot_01_longest_chain.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_consensus_nakamoto_plot_01_longest_chain.py: Nakamoto consensus: a payment, a fork, and a reorganization (2008) ================================================================== This is the full teaching chain: keys authorize a transfer, a Merkle root commits to it, proof of work secures a header, and peers compare valid forks. The example uses an account ledger, not Bitcoin's UTXO model. What to look for ---------------- Follow Alice and Bob’s balances after a payment, then after a competing branch wins. The old payment’s signature can still verify even though its effect disappears from the selected ledger. Read cells in order. An ``assert`` that produces no output has passed. The final exercise asks you to change an input and explain the result. The history behind this experiment: :doc:`/history/consensus_breakthroughs`. See :doc:`/exercises/structures` for a worked solution to the exercise. .. GENERATED FROM PYTHON SOURCE LINES 24-39 .. code-block:: Python import matplotlib.pyplot as plt import blockchainkit as bk alice_private, bob_private = 7, 11 alice = bk.structures.address(bk.crypto.public_key(alice_private)) bob = bk.structures.address(bk.crypto.public_key(bob_private)) initial = bk.structures.Ledger({alice: 100}) genesis = bk.consensus.mine(bk.structures.Block(difficulty=5)).block peers = {name: bk.structures.Blockchain(genesis, initial) for name in ("west", "east")} transaction = bk.structures.Transaction(bk.crypto.public_key(alice_private), bob, 25, 0).signed( alice_private, signing_nonce=17 ) payment_block = bk.consensus.mine(bk.structures.Block(genesis.hash, (transaction,), 1, 1, 5)).block .. GENERATED FROM PYTHON SOURCE LINES 40-44 Two partitions extend the same genesis independently ---------------------------------------------------- Transport sends hash announcements; this in-memory registry supplies the corresponding immutable block objects. It is not a wire serialization layer. .. GENERATED FROM PYTHON SOURCE LINES 44-60 .. code-block:: Python alternate = bk.consensus.mine(bk.structures.Block(genesis.hash, (), 1, 2, 5)).block extension = bk.consensus.mine(bk.structures.Block(alternate.hash, (), 2, 3, 5)).block registry = {block.hash: block for block in (payment_block, alternate, extension)} def receive(delivery): peers[delivery.recipient].add(registry[delivery.payload]) network = bk.network.SimulatedNetwork(peers, on_receive=receive) network.broadcast("west", payment_block.hash) network.broadcast("east", alternate.hash) network.broadcast("east", extension.hash) before = [peers[name].state.balances.get(bob, 0) for name in peers] assert before == [25, 0] .. GENERATED FROM PYTHON SOURCE LINES 61-63 Reconnect and synchronize parent before child --------------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 63-75 .. code-block:: Python network.connect("west", "east") network.broadcast("west", payment_block.hash) network.broadcast("east", alternate.hash) network.run() network.broadcast("east", extension.hash) network.run() assert peers["west"].tip == peers["east"].tip == extension after = [peers[name].state.balances.get(bob, 0) for name in peers] assert after == [0, 0] assert peers["west"].state.nonces.get(alice, 0) == 0 print("Both peers chose the higher-work fork. Alice's payment is no longer confirmed.") .. rst-class:: sphx-glr-script-out .. code-block:: none Both peers chose the higher-work fork. Alice's payment is no longer confirmed. .. GENERATED FROM PYTHON SOURCE LINES 76-78 Inclusion remains true for the discarded block ---------------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 78-82 .. code-block:: Python tree = bk.structures.MerkleTree(tx.to_bytes() for tx in payment_block.transactions) assert bk.structures.verify_proof(transaction.to_bytes(), tree.proof(0), payment_block.merkle_root) print("The payment still has an inclusion proof in its original side-fork block.") .. rst-class:: sphx-glr-script-out .. code-block:: none The payment still has an inclusion proof in its original side-fork block. .. GENERATED FROM PYTHON SOURCE LINES 83-97 .. code-block:: Python fig, ax = plt.subplots(figsize=(7, 4)) xs = [0, 1] ax.bar([x - 0.18 for x in xs], before, 0.36, label="During partition") ax.bar([x + 0.18 for x in xs], after, 0.36, label="After synchronization") ax.set( xticks=xs, xticklabels=list(peers), ylabel="Bob's canonical balance", title="A valid signature does not guarantee finality", ylim=(0, 30), ) ax.legend() fig.tight_layout() .. image-sg:: /api/gallery/consensus/nakamoto/images/sphx_glr_plot_01_longest_chain_001.png :alt: A valid signature does not guarantee finality :srcset: /api/gallery/consensus/nakamoto/images/sphx_glr_plot_01_longest_chain_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 98-103 Exercise -------- Reinclude the payment on the winning fork, then attempt to replay it. Check that its first inclusion succeeds and its second fails on the account nonce. Change the chain ID and explain why the existing signature no longer works. .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.160 seconds) .. _sphx_glr_download_api_gallery_consensus_nakamoto_plot_01_longest_chain.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/consensus/nakamoto/plot_01_longest_chain.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_01_longest_chain.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_01_longest_chain.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_01_longest_chain.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_