.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/channels/scaling/plot_03_zk_rollups.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_03_zk_rollups.py: zk-rollups: validity proofs for batched transactions (2018) =========================================================== A rollup runs transactions off chain but posts them, compressed, to the chain, so anyone can rebuild its state. Barry Whitehat's *roll_up* and Buterin's 2018 proposal added a succinct proof that the posted state root follows from the batch. The contract checks the proof at a fixed cost and never re-executes anything, so the gas per transaction falls toward the cost of its calldata: .. math:: g(n) = \frac{G_{\text{verify}}}{n} + 16\,b \quad\text{vs.}\quad 21\,000 \text{ for a transfer on chain}. An invalid state root cannot be posted at all, because no proof of it exists, so withdrawals are final as soon as the batch is accepted. .. GENERATED FROM PYTHON SOURCE LINES 22-28 .. code-block:: Python from random import Random import matplotlib.pyplot as plt import blockchainkit as bk .. GENERATED FROM PYTHON SOURCE LINES 29-31 A batch of transfers, proven and posted --------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 31-43 .. code-block:: Python rng = Random(11) accounts = [f"user{i}" for i in range(20)] rollup = bk.channels.ZKRollup({a: 1_000 for a in accounts}) batch = [ bk.channels.Transfer(rng.choice(accounts), rng.choice(accounts), rng.randint(1, 300)) for _ in range(200) ] gas = rollup.submit(batch, rollup.prove(batch)) print(f"200 transfers for {gas:,} gas: {gas / 200:,.0f} per transfer") assert sum(rollup.balances.values()) == 20 * 1_000 .. rst-class:: sphx-glr-script-out .. code-block:: none 200 transfers for 338,400 gas: 1,692 per transfer .. GENERATED FROM PYTHON SOURCE LINES 44-46 An operator cannot prove a false state -------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 46-53 .. code-block:: Python theft = {**rollup.balances, "operator": 5_000} try: rollup.prove(batch, claimed_root=bk.channels.state_root(theft)) except ValueError as error: print("operator's claim:", error) .. rst-class:: sphx-glr-script-out .. code-block:: none operator's claim: no proof exists for a false state transition .. GENERATED FROM PYTHON SOURCE LINES 54-56 Gas per transaction against batch size -------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 56-77 .. code-block:: Python sizes = [1, 10, 30, 100, 300, 1_000, 3_000, 10_000] per_transfer = [ bk.channels.batch_gas(n, bytes_per_transaction=12, fixed_gas=300_000) / n for n in sizes ] break_even = next(n for n, g in zip(sizes, per_transfer, strict=True) if g < 21_000) print("cheaper than on chain from", break_even, "transfers per batch") per_block = 30_000_000 // round(per_transfer[-1]) print(f"transfers per 30M-gas block: {30_000_000 // 21_000:,} on chain, {per_block:,} rolled up") fig, ax = plt.subplots(figsize=(8, 4)) ax.loglog(sizes, per_transfer, "o-", color="#2563eb", label="zk-rollup") ax.axhline(21_000, color="#dc2626", linestyle="--", label="transfer on chain") ax.axhline(12 * 16, color="#16a34a", linestyle=":", label="calldata alone (12 bytes)") ax.set(xlabel="transfers per batch", ylabel="gas per transfer") ax.set_title("The proof's cost is shared by the whole batch") ax.legend() fig.tight_layout() plt.show() .. image-sg:: /api/gallery/channels/scaling/images/sphx_glr_plot_03_zk_rollups_001.png :alt: The proof's cost is shared by the whole batch :srcset: /api/gallery/channels/scaling/images/sphx_glr_plot_03_zk_rollups_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none cheaper than on chain from 30 transfers per batch transfers per 30M-gas block: 1,428 on chain, 135,135 rolled up .. GENERATED FROM PYTHON SOURCE LINES 78-84 Exercise -------- A rollup that posts its data elsewhere (a "validium") pays only for the proof. Recompute the gas per transfer with ``bytes_per_transaction=0``, and explain what users lose if the operator then withholds the data. A worked solution is in :doc:`/exercises/channels`. .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.125 seconds) .. _sphx_glr_download_api_gallery_channels_scaling_plot_03_zk_rollups.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_03_zk_rollups.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_03_zk_rollups.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_03_zk_rollups.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_03_zk_rollups.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_