.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/vm/replication/plot_02_atomic_transactions.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_vm_replication_plot_02_atomic_transactions.py: Atomic transactions: all or nothing (Gray 1981) =============================================== Jim Gray defined the *transaction*: a group of actions that is atomic (either all happen or none), consistent, and durable. A bank transfer that debits one account must also credit the other, or do neither, however it fails halfway. Ethereum gives every call this property: if execution fails, every storage write it made is discarded. What to look for ---------------- The trace shows the debit already written to the *working* storage before the transfer fails. The committed storage is unchanged all the same: the failure discarded the half-done write. A successful transfer conserves the total. The history behind this experiment: :doc:`/history/vm_breakthroughs`. See :doc:`/exercises/vm` for a worked solution to the exercise. .. GENERATED FROM PYTHON SOURCE LINES 24-26 A transfer from slot 0 to slot 1 -------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 26-52 .. code-block:: Python import matplotlib.pyplot as plt import blockchainkit as bk from blockchainkit.vm.visualizers import plot_execution_trace transfer = bk.vm.assemble(""" # stack: amount LOAD 0 # amount old OVER OVER # amount old amount old SWAP SUB # amount old old-amount STORE 0 # debit first (wraps if the balance is too small) OVER # amount old amount LT # was the balance too small? (old < amount) JZ credit REVERT credit: LOAD 1 ADD STORE 1 """) accounts = {0: 100, 1: 20} ok = bk.vm.execute(transfer, arguments=(30,), storage=accounts) assert dict(ok.storage) == {0: 70, 1: 50} and sum(ok.storage.values()) == 120 .. GENERATED FROM PYTHON SOURCE LINES 53-55 Failing halfway --------------- .. GENERATED FROM PYTHON SOURCE LINES 55-68 .. code-block:: Python try: bk.vm.execute(transfer, arguments=(150,), storage=accounts, trace=True) except bk.vm.VMError as error: failed = error.trace print("reverted after", len(failed), "steps; working storage was", failed[-1].storage) debit = next(step for step in failed if step.opcode == "STORE") assert debit.storage[0] == (100 - 150) % 2**256 # The debit was written... assert accounts == {0: 100, 1: 20} # ...and never committed. fig, ax = plt.subplots(figsize=(9, 4.5)) plot_execution_trace(failed, ax=ax) fig.tight_layout() .. image-sg:: /api/gallery/vm/replication/images/sphx_glr_plot_02_atomic_transactions_001.png :alt: State after each instruction :srcset: /api/gallery/vm/replication/images/sphx_glr_plot_02_atomic_transactions_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none reverted after 9 steps; working storage was {0: 115792089237316195423570985008687907853269984665640564039457584007913129639886, 1: 20} .. GENERATED FROM PYTHON SOURCE LINES 69-75 Exercise -------- Move the balance check before the debit. Does the committed outcome change for any amount? What does atomicity let a contract get away with here, and why is the order of checks and effects still crucial once a contract calls out to another one (see the DAO example)? .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.242 seconds) .. _sphx_glr_download_api_gallery_vm_replication_plot_02_atomic_transactions.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/vm/replication/plot_02_atomic_transactions.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_02_atomic_transactions.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_02_atomic_transactions.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_02_atomic_transactions.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_