.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/channels/payment_channels/plot_01_spilman_channels.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_payment_channels_plot_01_spilman_channels.py: Spilman and Hearn's one-way micropayment channels (2013) ======================================================== Paying for a stream by the second on chain costs a transaction, and a fee, per payment. Jeremy Spilman's channel needs two. The payer locks the channel's capacity in a 2-of-2 output, after the payee has signed a refund that returns everything to the payer at a lock time. Each payment is a new transaction from that output, paying the payee a little more; the payer signs it and hands it over, and the payee countersigns and publishes only the last one. Mike Hearn built the scheme into bitcoinj the same year. For ``m`` payments the chain sees two transactions instead of ``m``: .. math:: \text{on-chain transactions} = 2 \quad\text{vs.}\quad m. The payee must close before the refund's lock time, or the payer takes everything back. .. GENERATED FROM PYTHON SOURCE LINES 24-28 .. code-block:: Python import matplotlib.pyplot as plt import blockchainkit as bk .. GENERATED FROM PYTHON SOURCE LINES 29-31 Streaming one coin a second for a minute ---------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 31-40 .. code-block:: Python channel = bk.channels.SpilmanChannel( "viewer", "streamer", payer_key=7, payee_key=5, capacity=100, expiry=144 ) paid = [channel.pay(1) for _ in range(60)] settlement = channel.close(height=30) print(dict(settlement.payouts)) assert dict(settlement.payouts) == {"viewer": 40, "streamer": 60} .. rst-class:: sphx-glr-script-out .. code-block:: none {'viewer': 40, 'streamer': 60} .. GENERATED FROM PYTHON SOURCE LINES 41-45 A payee who waits too long -------------------------- The refund becomes valid at height 144; the payer can then take back all 100 coins, although it signed payments worth 60. .. GENERATED FROM PYTHON SOURCE LINES 45-74 .. code-block:: Python late = bk.channels.SpilmanChannel( "viewer", "streamer", payer_key=7, payee_key=5, capacity=100, expiry=144 ) for _ in range(60): late.pay(1) try: late.refund(height=143) except ValueError as error: print("at height 143:", error) refund = late.refund(height=144) assert refund.kind == "refund" and refund.payouts["streamer"] == 0 fig, (left, right) = plt.subplots(1, 2, figsize=(11, 4)) seconds = range(1, 61) left.step(seconds, paid, where="post", color="#2563eb", label="signed off chain") left.axhline(60, color="#16a34a", linestyle="--", label="settled on chain") left.set(xlabel="second", ylabel="coins paid to the streamer") left.set_title("Each payment is a signature, not a transaction") left.legend() right.plot(seconds, seconds, color="#dc2626", label="one transaction per payment") right.plot(seconds, [2] * 60, color="#16a34a", label="channel: fund and close") right.set(xlabel="payments", ylabel="transactions on chain") right.set_title("Two transactions for any number of payments") right.legend() fig.tight_layout() plt.show() .. image-sg:: /api/gallery/channels/payment_channels/images/sphx_glr_plot_01_spilman_channels_001.png :alt: Each payment is a signature, not a transaction, Two transactions for any number of payments :srcset: /api/gallery/channels/payment_channels/images/sphx_glr_plot_01_spilman_channels_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none at height 143: the refund is locked until height 144 .. GENERATED FROM PYTHON SOURCE LINES 75-80 Exercise -------- The payer can never take back what it has paid before the lock time, because the payee holds a signed transaction for it. What stops the payee from publishing an *earlier* payment, and why would it never want to? .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.671 seconds) .. _sphx_glr_download_api_gallery_channels_payment_channels_plot_01_spilman_channels.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/payment_channels/plot_01_spilman_channels.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_01_spilman_channels.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_01_spilman_channels.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_01_spilman_channels.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_