.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/channels/scaling/plot_01_plasma_exit_games.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_channels_scaling_plot_01_plasma_exit_games.py: Plasma: child chains secured by exit games (Poon and Buterin, 2017) =================================================================== Plasma runs a whole chain off chain. An operator produces its blocks and posts only their Merkle roots to a root-chain contract, which cannot check the transactions behind them. Coins stay safe because their owners can always *exit*: prove ownership on the root chain, then wait out a challenge period during which anyone can prove the exit wrong. In Plasma Cash every coin has its own slot in each block's sparse Merkle tree. An exit shows the coin's last transfer and the one before it, and is cancelled by a later transfer signed by the exiting owner (it spent the coin) or by a different transfer signed by the previous owner in between (the exiting transfer was a double spend). An exit stands only if .. math:: \text{no valid challenge arrives within the period}. .. GENERATED FROM PYTHON SOURCE LINES 23-30 .. code-block:: Python import matplotlib.pyplot as plt import blockchainkit as bk from blockchainkit.crypto import public_key ALICE, BOB, CAROL, DAVE = 7, 5, 11, 13 .. GENERATED FROM PYTHON SOURCE LINES 31-33 A coin changes hands three times -------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 33-58 .. code-block:: Python chain = bk.channels.PlasmaChain(period=7) deposit = chain.deposit(public_key(ALICE)) # Block 1. to_bob = chain.submit_block([bk.channels.sign_transfer(ALICE, 0, public_key(BOB), 1)]) to_carol = chain.submit_block([bk.channels.sign_transfer(BOB, 0, public_key(CAROL), to_bob)]) timeline = [] # Bob tries to exit the coin he already gave Carol. stale = chain.start_exit(chain.prove(0, to_bob), deposit, height=10) assert chain.challenge(stale, chain.prove(0, to_carol), height=12) timeline.append(("Bob exits a spent coin", 10, 12, "challenged")) # Alice signs the coin away a second time; a colluding operator includes it. to_dave = chain.submit_block([bk.channels.sign_transfer(ALICE, 0, public_key(DAVE), 1)]) forged = chain.start_exit(chain.prove(0, to_dave), deposit, height=20) assert chain.challenge(forged, chain.prove(0, to_bob), height=23) timeline.append(("Dave exits a double spend", 20, 23, "challenged")) # Carol, the rightful owner, exits unchallenged. rightful = chain.start_exit(chain.prove(0, to_carol), chain.prove(0, to_bob), height=30) assert not chain.challenge(rightful, chain.prove(0, to_dave), height=31) assert chain.finalize(rightful, height=37).owner == public_key(CAROL) timeline.append(("Carol exits her coin", 30, 37, "finalized")) print([status for *_, status in timeline]) .. rst-class:: sphx-glr-script-out .. code-block:: none ['challenged', 'challenged', 'finalized'] .. GENERATED FROM PYTHON SOURCE LINES 59-63 Why a withholding operator forces mass exits -------------------------------------------- If the operator stops publishing blocks, each owner must exit each coin on the root chain, within the challenge period. .. GENERATED FROM PYTHON SOURCE LINES 63-84 .. code-block:: Python coins = [1, 10, 100, 1_000, 10_000] exits_per_block = 50 # What the root chain can absorb per block, say. blocks_needed = [c / exits_per_block for c in coins] fig, (left, right) = plt.subplots(1, 2, figsize=(11, 4)) for row, (_, start, end, status) in enumerate(timeline): color = "#16a34a" if status == "finalized" else "#dc2626" left.barh(row, end - start, left=start, color=color) left.text(end + 0.5, row, status, va="center") left.set_yticks(range(len(timeline)), labels=[label for label, *_ in timeline]) left.set(xlabel="root-chain height", xlim=(0, 50), title="Three exits of one coin") right.loglog(coins, blocks_needed, "o-", color="#d97706") right.axhline(7, color="black", linestyle="--", label="challenge period") right.set(xlabel="coins on the child chain", ylabel="root-chain blocks to exit them all") right.set_title("Mass exit after the operator disappears") right.legend() fig.tight_layout() plt.show() .. image-sg:: /api/gallery/channels/scaling/images/sphx_glr_plot_01_plasma_exit_games_001.png :alt: Three exits of one coin, Mass exit after the operator disappears :srcset: /api/gallery/channels/scaling/images/sphx_glr_plot_01_plasma_exit_games_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 85-92 Exercise -------- Plasma Cash also lets a challenger accuse an exit of an *invalid history*, which the exiting owner answers with a later transfer. Sketch that third challenge on :class:`~blockchainkit.channels.systems.plasma.PlasmaChain`: what must the challenger show, and what must the owner answer with? .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.213 seconds) .. _sphx_glr_download_api_gallery_channels_scaling_plot_01_plasma_exit_games.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/channels/scaling/plot_01_plasma_exit_games.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_01_plasma_exit_games.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_01_plasma_exit_games.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_01_plasma_exit_games.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_