From 7eac96257b0a16280e3040550018980c0cb2df30 Mon Sep 17 00:00:00 2001 From: "shafu.eth" Date: Thu, 29 Feb 2024 14:25:02 +0100 Subject: [PATCH] all files --- .DS_Store | Bin 6148 -> 14340 bytes 04_storage.ipynb | 235 +++++++++++++ 05_1_state.ipynb | 224 +++++++++++++ 05_opcodes.ipynb | 495 ++++++++++++++++++++++++++++ 06_stop.ipynb | 52 +++ 07_math.ipynb | 290 ++++++++++++++++ 08_comparisions.ipynb | 188 +++++++++++ 09_logic.ipynb | 129 ++++++++ 10_bit.ipynb | 249 ++++++++++++++ 11_misc.ipynb | 142 ++++++++ 12_environment.ipynb | 478 +++++++++++++++++++++++++++ 13_pop.ipynb | 38 +++ 14_memory.ipynb | 78 +++++ 15_storage.ipynb | 69 ++++ 16_jump.ipynb | 95 ++++++ 17_push.ipynb | 43 +++ 18_dup.ipynb | 41 +++ 19_swap.ipynb | 41 +++ 20_log.ipynb | 160 +++++++++ 21_contract.ipynb | 42 +++ 24_evm.ipynb | 136 ++++++++ 25_bytecode.ipynb | 144 ++++++++ 26_run.ipynb | 109 ++++++ 99_conclusion.ipynb | 58 ++++ _build/.doctrees/environment.pickle | Bin 40070 -> 87504 bytes _build/html/objects.inv | 7 +- _build/html/searchindex.js | 2 +- _toc.yml | 1 + 28 files changed, 3543 insertions(+), 3 deletions(-) create mode 100644 04_storage.ipynb create mode 100644 05_1_state.ipynb create mode 100644 05_opcodes.ipynb create mode 100644 06_stop.ipynb create mode 100644 07_math.ipynb create mode 100644 08_comparisions.ipynb create mode 100644 09_logic.ipynb create mode 100644 10_bit.ipynb create mode 100644 11_misc.ipynb create mode 100644 12_environment.ipynb create mode 100644 13_pop.ipynb create mode 100644 14_memory.ipynb create mode 100644 15_storage.ipynb create mode 100644 16_jump.ipynb create mode 100644 17_push.ipynb create mode 100644 18_dup.ipynb create mode 100644 19_swap.ipynb create mode 100644 20_log.ipynb create mode 100644 21_contract.ipynb create mode 100644 24_evm.ipynb create mode 100644 25_bytecode.ipynb create mode 100644 26_run.ipynb create mode 100644 99_conclusion.ipynb diff --git a/.DS_Store b/.DS_Store index b0b95da84f150eb15c5600a3533dcd3e1be49d45..c0ea106b307fa36277543184f0ab6153497a9045 100644 GIT binary patch literal 14340 zcmeHO%Wl&^6upLmBK1LdEs-Lz?jr?C*@dbskPw>+wxxFZf}{zJQ|K;x{()cM`&hv_ z^Jo(%V>=7vQJImPvB&qi=iEDE&%HAhk!WYwZi;M(NDT+;`VyLP(Lg<3c%R2qxs8?x z#}*Ep*G2Z_P|oB+PUU<`+P{WdfJFQYI37t;HYf1+z@)4Aq_PG^eYr$S+)v|o!$C@Z zTe63?fuxY?%DQ}%o^)iWv^*6z}W{#9l|DT9momVjv%*=whKtF;_4i_JR3-Y zbLu6KTa_5?J^2FJ6gBT0Lu(SxdxNJAH$DdkBAO`+%#?Wn8TdYwV1ZzPV1ZzP|I`Bf z_My}kbsc_#1%d^F1+FZ>_d^2*>z1iUx>m0a{BR1*`tM-jfit5}SvI5`Hp{e-2e>YS>lV0vRv8>$`e{BY%P&XDFng)S-%w?rCbLIXjX+{{ zqZ()CkODJ~&}}el!)LyDEDw`q<&-hrdZotPH)Q*KVMTAbQCVI&Qp#JK$Ug2PN7_Rc z(~n-bgsiU%lV#5u51#ap3zKE% zlrdi9cP>UgpV@qRvptn(uj)-nzZ9dhJWEI$FY;@5jyLC-C%u&(a$&OUoHF3_5N{~H zqx4uz)LP5{D>odOe)QAw2rb`|8eo4{_1_`*cBK8b(@Ww`FGf29;@3FV{-}a8k;N-3 z9YLP&;!Dh8I~lEC8Lb+$xU!VYmXDrf{Q<|A^U* zYMhxv3d|nk8I0c9H@oPg2l&>V!h?Fo=1WhV52a;3hZZcc0!wh_sw3l5HN)~@losK# zY;)znkNFNp*_`|M5*z1Xvb>x!YFsu|5aG?xwT|9gXw%(4If1~Cp)f(3#FvKELIcK3F7&}#P9 zW$&x4dJVLGGIuC9x;|H1@zAEW;^Bf@@wUxvRpDNXC#Xld<`a0WR8i|)eE)nC;Qaq} pGjEo{&Lcwne-#bG(at!!!l)__ll7ug2ApzY=n7foqq4jp^%so5R)GKj delta 155 zcmZoEXfcprU|?W$DortDU=RQ@Ie-{MGjUEV6q~3gIoZI3MH0woU;|=Cuv`v9if2xK za#Buy(q=)X<&2DMlP^h6-E1m*jcKz2(*&l)>>M0|%pg5L<=jBR6=WPx>38PI{3ezP aKvRGS0)Pw_5Q_<7GsrOvo8x)rFarS3rWY;% diff --git a/04_storage.ipynb b/04_storage.ipynb new file mode 100644 index 0000000..94a742b --- /dev/null +++ b/04_storage.ipynb @@ -0,0 +1,235 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "b52d942c", + "metadata": {}, + "source": [ + "# Storage" + ] + }, + { + "cell_type": "markdown", + "id": "6b581368", + "metadata": {}, + "source": [ + "The storage is a mapping from a `key` to a `value`. The number of keys is for all practical purposes infinite. The value can be up to 32 bytes. Every value is initialized with a 0.\n", + "\n", + "This is like the SSD in your computer. Storage is non-volatile." + ] + }, + { + "cell_type": "markdown", + "id": "2a9d3e0b", + "metadata": {}, + "source": [ + "![title](static/storage.png)" + ] + }, + { + "cell_type": "markdown", + "id": "f0d8d8db", + "metadata": {}, + "source": [ + "source: https://docs.alchemy.com/docs/smart-contract-storage-layout" + ] + }, + { + "cell_type": "markdown", + "id": "0672532a", + "metadata": {}, + "source": [ + "We will represent the storage as a dictionary." + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "c5b98bfc", + "metadata": {}, + "outputs": [], + "source": [ + "class KeyValue:\n", + " def __init__(self): self.storage = {}\n", + " \n", + " def load (self, key) : return self.storage[key]\n", + " def store(self, key, value): self.storage[key] = value" + ] + }, + { + "cell_type": "markdown", + "id": "2e60b878", + "metadata": {}, + "source": [ + "### Warm/Cold" + ] + }, + { + "cell_type": "markdown", + "id": "d7515c89", + "metadata": {}, + "source": [ + "It costs different amount of gas whether we access a warm or cold storage slot. \n", + "A slot is said to be `warm` if it was access before. Otherwise it is `cold`.\n", + "Accessing a slot that is `cold` costs more gas than accessing a `warm` slot.\n", + "\n", + "We implement that logic by keeping track of a `cache`. When we load a storage slot we save its key in that `cache`. If a key is in that `cache` it is said to be warm." + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "4d35c9ac", + "metadata": {}, + "outputs": [], + "source": [ + "class Storage(KeyValue):\n", + " def __init__(self):\n", + " super().__init__()\n", + " self.cache = []\n", + " \n", + " def load(self, key):\n", + " warm = True if key in self.cache else False\n", + " if not warm: self.cache.append(key)\n", + " if key not in self.storage: return 0x00\n", + " return warm, super().load(key)" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "c9cba219", + "metadata": {}, + "outputs": [], + "source": [ + "storage = Storage()" + ] + }, + { + "cell_type": "markdown", + "id": "352aa83d", + "metadata": {}, + "source": [ + "We store `420` in storage slot `1`" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "4ff21851", + "metadata": {}, + "outputs": [], + "source": [ + "storage.store(1, 420)" + ] + }, + { + "cell_type": "markdown", + "id": "037c7a05", + "metadata": {}, + "source": [ + "Notice how the first time retrieving something from storage slot `1` its `cold`" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "7e3f84c7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(False, 420)" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "storage.load(1)" + ] + }, + { + "cell_type": "markdown", + "id": "80e548e3", + "metadata": {}, + "source": [ + "Now storage slot `1` is `warm`" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "6c25d6ff", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(True, 420)" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "storage.load(1)" + ] + }, + { + "cell_type": "markdown", + "id": "257055b8", + "metadata": {}, + "source": [ + "Reading a random storage that was not set to any value will return 0 and **not** throw an exception." + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "id": "bc839596", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "storage.load(42069)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/05_1_state.ipynb b/05_1_state.ipynb new file mode 100644 index 0000000..8ad004a --- /dev/null +++ b/05_1_state.ipynb @@ -0,0 +1,224 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "973f8632", + "metadata": {}, + "source": [ + "# EVM State" + ] + }, + { + "cell_type": "markdown", + "id": "784a59d7", + "metadata": {}, + "source": [ + "The EVM is a state machine. A valid Ethereum program or valid bytecode can manipulate that state." + ] + }, + { + "cell_type": "markdown", + "id": "200c45d3", + "metadata": {}, + "source": [ + "A specific opcode is an operation that manipulates that state." + ] + }, + { + "cell_type": "markdown", + "id": "36a04101", + "metadata": {}, + "source": [ + "### Program Counter (pc)" + ] + }, + { + "cell_type": "markdown", + "id": "ce9fe248", + "metadata": {}, + "source": [ + "The program counter points to the next opcode that the EVM is going to execute." + ] + }, + { + "cell_type": "markdown", + "id": "8bd37067", + "metadata": {}, + "source": [ + "### Stack / Memory / Storage" + ] + }, + { + "cell_type": "markdown", + "id": "a8d57b1b", + "metadata": {}, + "source": [ + "All of them are part of the EVM state. And are the areas where the EVM manipulates and stores data." + ] + }, + { + "cell_type": "markdown", + "id": "19633bd5", + "metadata": {}, + "source": [ + "### Program" + ] + }, + { + "cell_type": "markdown", + "id": "05ec82bf", + "metadata": {}, + "source": [ + "This is where we store the bytecode of the current program. It can not change during execution, which makes it immutable." + ] + }, + { + "cell_type": "markdown", + "id": "e07bf794", + "metadata": {}, + "source": [ + "### Gas" + ] + }, + { + "cell_type": "markdown", + "id": "6c61487c", + "metadata": {}, + "source": [ + "We need to keep track how much gas we currently have and how much we already consumed. Most opcodes make the gas counter go down." + ] + }, + { + "cell_type": "markdown", + "id": "8b45b305", + "metadata": {}, + "source": [ + "### Value" + ] + }, + { + "cell_type": "markdown", + "id": "a52bd4e8", + "metadata": {}, + "source": [ + "How much Ether (wei) this current execution can consume." + ] + }, + { + "cell_type": "markdown", + "id": "5abc90e8", + "metadata": {}, + "source": [ + "### Calldata" + ] + }, + { + "cell_type": "markdown", + "id": "0d427d61", + "metadata": {}, + "source": [ + "Is the input to our program." + ] + }, + { + "cell_type": "markdown", + "id": "85538f4f", + "metadata": {}, + "source": [ + "### Flags" + ] + }, + { + "cell_type": "markdown", + "id": "38d9e555", + "metadata": {}, + "source": [ + "We are going to keep track of two flags. The `stop_flag` and `revert_flag`. If one of them is `True` the current execution is going to stop." + ] + }, + { + "cell_type": "markdown", + "id": "446fb931", + "metadata": {}, + "source": [ + "### Returndata" + ] + }, + { + "cell_type": "markdown", + "id": "d39d4223", + "metadata": {}, + "source": [ + "The EVM can return data after execution. We store this data in `return`." + ] + }, + { + "cell_type": "markdown", + "id": "0f5076db", + "metadata": {}, + "source": [ + "### Logs" + ] + }, + { + "cell_type": "markdown", + "id": "e90bba27", + "metadata": {}, + "source": [ + "There are several opcodes that emit logs when executed. The result of these logs is saved here." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "ac69f3ea", + "metadata": {}, + "outputs": [], + "source": [ + "class State:\n", + " def __init__(self,\n", + " program,\n", + " gas,\n", + " value,\n", + " calldata=[]):\n", + " self.pc = 0\n", + " \n", + " self.stack = Stack()\n", + " self.memory = Memory()\n", + " self.storage = Storage()\n", + " \n", + " self.program = program\n", + " self.gas = gas\n", + " self.value = value\n", + " self.calldata = calldata\n", + " \n", + " self.stop_flag = False\n", + " self.revert_flag = False\n", + " \n", + " self.returndata = []\n", + " self.logs = []" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/05_opcodes.ipynb b/05_opcodes.ipynb new file mode 100644 index 0000000..5c3acc5 --- /dev/null +++ b/05_opcodes.ipynb @@ -0,0 +1,495 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "93683266", + "metadata": {}, + "source": [ + "# Opcodes" + ] + }, + { + "cell_type": "markdown", + "id": "8d84263e", + "metadata": {}, + "source": [ + "Opcodes are the insturctions that the EVM can execute. There are different categories of opcodes. Some of them are arithmetic or logic operations. Others deal with memory, storage and the stack." + ] + }, + { + "cell_type": "markdown", + "id": "34539b2f", + "metadata": {}, + "source": [ + "## Implementation" + ] + }, + { + "cell_type": "markdown", + "id": "0a2fe40b", + "metadata": {}, + "source": [ + "In the following notebooks we will implement most of these opcodes. \n", + "All opcodes have one thing in common. They manipulate the current state of the EVM. That is why we will create a function for each of them, that takes an EVM instance as parameter.\n", + "\n", + "Every opcode function will be structured like this.\n", + "\n", + "```\n", + "def opcode(evm):\n", + " # manipulate the evm\n", + " # ...\n", + "``` " + ] + }, + { + "cell_type": "markdown", + "id": "d7f6e940", + "metadata": {}, + "source": [ + "# List " + ] + }, + { + "cell_type": "markdown", + "id": "2b2a981a", + "metadata": {}, + "source": [ + "Each opcode has a unique identifier. A number that represents that opcode. Because all opcodes are not larger than 1 byte it is very convinient to denote them in hexadecimal." + ] + }, + { + "cell_type": "markdown", + "id": "70e5a1cf", + "metadata": {}, + "source": [ + "To make it easier for us to deal with opcodes we give them a short descriptive name. All opcodes can be found here." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "83170f18", + "metadata": {}, + "outputs": [], + "source": [ + "STOP = 0x0" + ] + }, + { + "cell_type": "markdown", + "id": "7b2875e6", + "metadata": {}, + "source": [ + "## Math" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0ecad830", + "metadata": {}, + "outputs": [], + "source": [ + "ADD = 0x1\n", + "MUL = 0x2\n", + "SUB = 0x3\n", + "DIV = 0x4\n", + "SDIV = 0x5\n", + "MOD = 0x6\n", + "SMOD = 0x7\n", + "ADDMOD = 0x8\n", + "MULMOD = 0x9\n", + "EXP = 0xA\n", + "SIGNEXTEND = 0xB" + ] + }, + { + "cell_type": "markdown", + "id": "78df0426", + "metadata": {}, + "source": [ + "## Comparisons" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4ea12852", + "metadata": {}, + "outputs": [], + "source": [ + "LT = 0x10\n", + "GT = 0x11\n", + "SLT = 0x12\n", + "SGT = 0x13\n", + "EQ = 0x14\n", + "ISZERO = 0x15" + ] + }, + { + "cell_type": "markdown", + "id": "d5f18901", + "metadata": {}, + "source": [ + "## Logic" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "ffe7e2a1", + "metadata": {}, + "outputs": [], + "source": [ + "AND = 0x16\n", + "OR = 0x17\n", + "XOR = 0x18\n", + "NOT = 0x19" + ] + }, + { + "cell_type": "markdown", + "id": "07a82493", + "metadata": {}, + "source": [ + "## Bit Ops" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9a732b20", + "metadata": {}, + "outputs": [], + "source": [ + "BYTE = 0x1A\n", + "SHL = 0x1B\n", + "SHR = 0x1C\n", + "SAR = 0x1D" + ] + }, + { + "cell_type": "markdown", + "id": "c9a71e0d", + "metadata": {}, + "source": [ + "## Misc" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "d820a0e6", + "metadata": {}, + "outputs": [], + "source": [ + "SHA3 = 0x20" + ] + }, + { + "cell_type": "markdown", + "id": "816d1246", + "metadata": {}, + "source": [ + "## Ethereum State" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "77c3d31c", + "metadata": {}, + "outputs": [], + "source": [ + "ADDRESS = 0x30\n", + "BALANCE = 0x31\n", + "ORIGIN = 0x32\n", + "CALLER = 0x33\n", + "CALLVALUE = 0x34\n", + "CALLDATALOAD = 0x35\n", + "CALLDATASIZE = 0x36\n", + "CALLDATACOPY = 0x37\n", + "CODESIZE = 0x38\n", + "CODECOPY = 0x39\n", + "GASPRICE = 0x3A\n", + "EXTCODESIZE = 0x3B\n", + "EXTCODECOPY = 0x3C\n", + "RETURNDATASIZE = 0x3D\n", + "RETURNDATACOPY = 0x3E\n", + "EXTCODEHASH = 0x3F\n", + "BLOCKHASH = 0x40\n", + "COINBASE = 0x41\n", + "TIMESTAMP = 0x42\n", + "NUMBER = 0x43\n", + "DIFFICULTY = 0x44\n", + "GASLIMIT = 0x45\n", + "CHAINID = 0x46\n", + "SELFBALANCE = 0x47\n", + "BASEFEE = 0x48" + ] + }, + { + "cell_type": "markdown", + "id": "c6967f86", + "metadata": {}, + "source": [ + "## Pop" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "5d439c18", + "metadata": {}, + "outputs": [], + "source": [ + "POP = 0x50" + ] + }, + { + "cell_type": "markdown", + "id": "6c60105e", + "metadata": {}, + "source": [ + "## Memory" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "880d1492", + "metadata": {}, + "outputs": [], + "source": [ + "MLOAD = 0x51\n", + "MSTORE = 0x52\n", + "MSTORE8 = 0x53" + ] + }, + { + "cell_type": "markdown", + "id": "216248bd", + "metadata": {}, + "source": [ + "## Storage" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cc1d9107", + "metadata": {}, + "outputs": [], + "source": [ + "SLOAD = 0x54\n", + "SSTORE = 0x55" + ] + }, + { + "cell_type": "markdown", + "id": "86bf3932", + "metadata": {}, + "source": [ + "## Jump" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "df3f3876", + "metadata": {}, + "outputs": [], + "source": [ + "JUMP = 0x56\n", + "JUMPI = 0x57\n", + "PC = 0x58\n", + "JUMPDEST = 0x5B" + ] + }, + { + "cell_type": "markdown", + "id": "5f4b87bb", + "metadata": {}, + "source": [ + "## Push" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "b9dda488", + "metadata": {}, + "outputs": [], + "source": [ + "PUSH1 = 0x60\n", + "PUSH2 = 0x61\n", + "PUSH3 = 0x62\n", + "PUSH4 = 0x63\n", + "PUSH5 = 0x64\n", + "PUSH6 = 0x65\n", + "PUSH7 = 0x66\n", + "PUSH8 = 0x67\n", + "PUSH9 = 0x68\n", + "PUSH10 = 0x69\n", + "PUSH11 = 0x6A\n", + "PUSH12 = 0x6B\n", + "PUSH13 = 0x6C\n", + "PUSH14 = 0x6D\n", + "PUSH15 = 0x6E\n", + "PUSH16 = 0x6F\n", + "PUSH17 = 0x70\n", + "PUSH18 = 0x71\n", + "PUSH19 = 0x72\n", + "PUSH20 = 0x73\n", + "PUSH21 = 0x74\n", + "PUSH22 = 0x75\n", + "PUSH23 = 0x76\n", + "PUSH24 = 0x77\n", + "PUSH25 = 0x78\n", + "PUSH26 = 0x79\n", + "PUSH27 = 0x7A\n", + "PUSH28 = 0x7B\n", + "PUSH29 = 0x7C\n", + "PUSH30 = 0x7D\n", + "PUSH31 = 0x7E\n", + "PUSH32 = 0x7F" + ] + }, + { + "cell_type": "markdown", + "id": "6652ada9", + "metadata": {}, + "source": [ + "## Dup" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "18c6e09b", + "metadata": {}, + "outputs": [], + "source": [ + "DUP1 = 0x80\n", + "DUP2 = 0x81\n", + "DUP3 = 0x82\n", + "DUP4 = 0x83\n", + "DUP5 = 0x84\n", + "DUP6 = 0x85\n", + "DUP7 = 0x86\n", + "DUP8 = 0x87\n", + "DUP9 = 0x88\n", + "DUP10 = 0x89\n", + "DUP11 = 0x8A\n", + "DUP12 = 0x8B\n", + "DUP13 = 0x8C\n", + "DUP14 = 0x8D\n", + "DUP15 = 0x8E\n", + "DUP16 = 0x8F" + ] + }, + { + "cell_type": "markdown", + "id": "921973a3", + "metadata": {}, + "source": [ + "## Swap" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "48a81485", + "metadata": {}, + "outputs": [], + "source": [ + "SWAP1 = 0x90\n", + "SWAP2 = 0x91\n", + "SWAP3 = 0x92\n", + "SWAP4 = 0x93\n", + "SWAP5 = 0x94\n", + "SWAP6 = 0x95\n", + "SWAP7 = 0x96\n", + "SWAP8 = 0x97\n", + "SWAP9 = 0x98\n", + "SWAP10 = 0x99\n", + "SWAP11 = 0x9A\n", + "SWAP12 = 0x9B\n", + "SWAP13 = 0x9C\n", + "SWAP14 = 0x9D\n", + "SWAP15 = 0x9E\n", + "SWAP16 = 0x9F" + ] + }, + { + "cell_type": "markdown", + "id": "e43b1018", + "metadata": {}, + "source": [ + "## Log" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "3004b2f2", + "metadata": {}, + "outputs": [], + "source": [ + "LOG0 = 0xA0\n", + "LOG1 = 0xA1\n", + "LOG2 = 0xA2\n", + "LOG3 = 0xA3\n", + "LOG4 = 0xA4" + ] + }, + { + "cell_type": "markdown", + "id": "dd2d5f7c", + "metadata": {}, + "source": [ + "## Contract" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "897e4fc5", + "metadata": {}, + "outputs": [], + "source": [ + "CREATE = 0xF0\n", + "CALL = 0xF1\n", + "CALLCODE = 0xF2 # legacy NOT supported by us, fixed by DELEGATECALL\n", + "RETURN = 0xF3\n", + "DELEGATECALL = 0xF4\n", + "CREATE2 = 0xF5\n", + "STATICCALL = 0xFA\n", + "REVERT = 0xFD\n", + "INVALID = 0xFE\n", + "SELFDESTRUCT = 0xFF" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/06_stop.ipynb b/06_stop.ipynb new file mode 100644 index 0000000..21453d0 --- /dev/null +++ b/06_stop.ipynb @@ -0,0 +1,52 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "32d03134", + "metadata": {}, + "source": [ + "# Stop" + ] + }, + { + "cell_type": "markdown", + "id": "896304a5", + "metadata": {}, + "source": [ + "Our first opcode! Stop is a very simple. All it does is it halts execution by setting the `stop_flag` to `True`." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "4409f5b8", + "metadata": {}, + "outputs": [], + "source": [ + "def stop(evm):\n", + " evm.stop_flag = True" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/07_math.ipynb b/07_math.ipynb new file mode 100644 index 0000000..8252506 --- /dev/null +++ b/07_math.ipynb @@ -0,0 +1,290 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a73f6343", + "metadata": {}, + "source": [ + "# Math" + ] + }, + { + "cell_type": "markdown", + "id": "577d70ee", + "metadata": {}, + "source": [ + "We are going to implement all arithmetic operations here. These are the first opcodes that actually manipulate the stack and consume some gas." + ] + }, + { + "cell_type": "markdown", + "id": "18e71195", + "metadata": {}, + "source": [ + "Lets see how `add` works. We are going to `pop` 2 values from the stack add them and `push` back the result on the stack.\n", + "\n", + "We also need to increment the `program counter (pc)` by one. In the end we need to deduct 3 gas for executing the `add` operation." + ] + }, + { + "cell_type": "markdown", + "id": "234e88d3", + "metadata": {}, + "source": [ + "Most arithmetic opcodes work like this." + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "id": "f4c2d206", + "metadata": {}, + "outputs": [], + "source": [ + "def add(evm):\n", + " a, b = evm.stack.pop(), evm.stack.pop()\n", + " evm.stack.push(a+b)\n", + " evm.pc += 1\n", + " evm.gas_dec(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "4e87de0f", + "metadata": {}, + "outputs": [], + "source": [ + "def mul(evm):\n", + " a, b = evm.stack.pop(), evm.stack.pop()\n", + " evm.stack.push(a*b)\n", + " evm.pc += 1\n", + " evm.gas_dec(5)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "b327519b", + "metadata": {}, + "outputs": [], + "source": [ + "def sub(evm):\n", + " a, b = evm.stack.pop(), evm.stack.pop()\n", + " evm.stack.push(a-b)\n", + " evm.pc += 1\n", + " evm.gas_dec(3)" + ] + }, + { + "cell_type": "markdown", + "id": "2302c413", + "metadata": {}, + "source": [ + "One interesting note about how the EVM handles division by 0. Most other systems would throw an exception if you try to divide by 0. Not the EVM. It just returns 0.\n", + "\n", + "Division by 0 are not directly handled by the EVM and are mostly a feature of the programming language like Solidity." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "931677f6", + "metadata": {}, + "outputs": [], + "source": [ + "def div(evm):\n", + " a, b = evm.stack.pop(), evm.stack.pop()\n", + " evm.stack.push(0 if b == 0 else a // b)\n", + " evm.pc += 1\n", + " evm.gas_dec(5)" + ] + }, + { + "cell_type": "markdown", + "id": "823e5b6f", + "metadata": {}, + "source": [ + "Exactly like div but we use the absolute value for the both the denominator and numerator." + ] + }, + { + "cell_type": "markdown", + "id": "2d541e0f", + "metadata": {}, + "source": [ + "Small little helper function to determine the sign of a number." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "a311e719", + "metadata": {}, + "outputs": [], + "source": [ + "pos_or_neg = lambda number: -1 if value < 0 else 1" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "19fc082e", + "metadata": {}, + "outputs": [], + "source": [ + "def sdiv(evm):\n", + " a, b = evm.stack.pop(), evm.stack.pop()\n", + " sign = pos_or_neg(a*b)\n", + " evm.stack.push(0 if b == 0 else sign * (abs(a) // abs(b)))\n", + " evm.pc += 1\n", + " evm.gas_dec(5)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "b7cc3fc1", + "metadata": {}, + "outputs": [], + "source": [ + "def mod(evm):\n", + " a, b = evm.stack.pop(), evm.stack.pop()\n", + " evm.stack.push(0 if b == 0 else a % b)\n", + " evm.pc += 1\n", + " evm.gas_dec(5)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "b7932479", + "metadata": {}, + "outputs": [], + "source": [ + "def smod(evm):\n", + " a, b = evm.stack.pop(), evm.stack.pop()\n", + " sign = pos_or_neg(a*b)\n", + " evm.stack.push(0 if b == 0 else abs(a) % abs(b) * sign)\n", + " evm.pc += 1\n", + " evm.gas_dec(5)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "88d178c1", + "metadata": {}, + "outputs": [], + "source": [ + "def addmod(evm):\n", + " a, b = evm.stack.pop(), evm.stack.pop()\n", + " N = evm.stack.pop()\n", + " evm.stack.push((a + b) % N)\n", + " evm.pc += 1\n", + " evm.gas_dec(8)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "e6703ad1", + "metadata": {}, + "outputs": [], + "source": [ + "def mulmod(evm):\n", + " a, b = evm.stack.pop(), evm.stack.pop()\n", + " N = evm.stack.pop()\n", + " evm.stack.push((a + b) * N)\n", + " evm.pc += 1\n", + " evm.gas_dec(8)" + ] + }, + { + "cell_type": "markdown", + "id": "779a1bff", + "metadata": {}, + "source": [ + "The gas cost for exp is dynamic. It is a function of how many bytes we need to represent the exponent in binary. This helper function calculates this." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "91a5c8eb", + "metadata": {}, + "outputs": [], + "source": [ + "def size_in_bytes(number):\n", + " import math\n", + " if number == 0: return 1\n", + " bits_needed = math.ceil(math.log2(abs(number) + 1))\n", + " return math.ceil(bits_needed / 8)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "8f49f2f2", + "metadata": {}, + "outputs": [], + "source": [ + "def exp(evm):\n", + " a, exponent = evm.stack.pop(), evm.stack.pop()\n", + " evm.stack.push(a ** exponent)\n", + " evm.pc += 1\n", + " evm.gas_dec(10 + (50 * size_in_bytes(exponent)))" + ] + }, + { + "cell_type": "markdown", + "id": "e095fb09", + "metadata": {}, + "source": [ + "More informations about this rarely used opcode `signextend` [here](https://ethereum.stackexchange.com/questions/63062/evm-signextend-opcode-explanation)." + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "e79c3c18", + "metadata": {}, + "outputs": [], + "source": [ + "def signextend(evm):\n", + " b, x = evm.stack.pop(), evm.stack.pop()\n", + " if b <= 31:\n", + " testbit = b * 8 + 7\n", + " sign_bit = 1 << testbit\n", + " if x & sign_bit: result = x | (2**256 - sign_bit)\n", + " else : result = x & (sign_bit - 1)\n", + " else: result = x\n", + " \n", + " evm.stack.push(result)\n", + " evm.pc += 1\n", + " evm.gas_dec(5)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/08_comparisions.ipynb b/08_comparisions.ipynb new file mode 100644 index 0000000..7a92477 --- /dev/null +++ b/08_comparisions.ipynb @@ -0,0 +1,188 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 12, + "id": "2d075d2b", + "metadata": {}, + "outputs": [], + "source": [ + "%%capture\n", + "%run utils.ipynb" + ] + }, + { + "cell_type": "markdown", + "id": "1bf359dc", + "metadata": {}, + "source": [ + "# Comparisons" + ] + }, + { + "cell_type": "markdown", + "id": "7253af6f", + "metadata": {}, + "source": [ + "Very similar to the arithmetic opcodes. But rather than adding or subtracting values we compare them." + ] + }, + { + "cell_type": "markdown", + "id": "a5612231", + "metadata": {}, + "source": [ + "#### Less than" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "a222fba0", + "metadata": {}, + "outputs": [], + "source": [ + "def lt(evm):\n", + " a, b = evm.stack.pop(), evm.stack.pop()\n", + " evm.stack.push(1 if a < b else 0)\n", + " evm.pc += 1\n", + " evm.gas_dec(3)" + ] + }, + { + "cell_type": "markdown", + "id": "0d96a314", + "metadata": {}, + "source": [ + "#### Signed Less than" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "e626f7af", + "metadata": {}, + "outputs": [], + "source": [ + "def slt(evm): # signed less than\n", + " a, b = evm.stack.pop(), evm.stack.pop()\n", + " a = unsigned_to_signed(a)\n", + " b = unsigned_to_signed(b)\n", + " evm.stack.push(1 if a < b else 0)\n", + " evm.pc += 1\n", + " evm.gas_dec(3)" + ] + }, + { + "cell_type": "markdown", + "id": "83a96c2f", + "metadata": {}, + "source": [ + "#### Greater than" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "cd80ba41", + "metadata": {}, + "outputs": [], + "source": [ + "def gt(evm): # greater than\n", + " a, b = evm.stack.pop(), evm.stack.pop()\n", + " evm.stack.push(1 if a > b else 0)\n", + " evm.pc += 1\n", + " evm.gas_dec(3)" + ] + }, + { + "cell_type": "markdown", + "id": "c58b9332", + "metadata": {}, + "source": [ + "#### Signed Greater than" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "8d564d7d", + "metadata": {}, + "outputs": [], + "source": [ + "def sgt(evm):\n", + " a, b = evm.stack.pop(), evm.stack.pop()\n", + " a = unsigned_to_signed(a)\n", + " b = unsigned_to_signed(b)\n", + " evm.stack.push(1 if a > b else 0)\n", + " evm.pc += 1\n", + " evm.gas_dec(3)" + ] + }, + { + "cell_type": "markdown", + "id": "101de0f3", + "metadata": {}, + "source": [ + "#### Equal" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "311a0d2a", + "metadata": {}, + "outputs": [], + "source": [ + "def eq(evm):\n", + " a, b = cpu.stack.pop(), cpu.stack.pop()\n", + " cpu.stack.push(1 if a == b else 0)\n", + " cpu.pc += 1\n", + " cpu.gas_dec(3)" + ] + }, + { + "cell_type": "markdown", + "id": "24e94e14", + "metadata": {}, + "source": [ + "#### Is Zero" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "9ac8ac44", + "metadata": {}, + "outputs": [], + "source": [ + "def iszero(evm):\n", + " a = evm.stack.pop()\n", + " evm.stack.push(1 if a == 0 else 0)\n", + " evm.pc += 1\n", + " evm.gas_dec(3)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/09_logic.ipynb b/09_logic.ipynb new file mode 100644 index 0000000..2f342c6 --- /dev/null +++ b/09_logic.ipynb @@ -0,0 +1,129 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "d9c52e04", + "metadata": {}, + "source": [ + "# Logic" + ] + }, + { + "cell_type": "markdown", + "id": "c0d9f8f4", + "metadata": {}, + "source": [ + "You are very familiar with this now. Same concept, different operations." + ] + }, + { + "cell_type": "markdown", + "id": "08c1bffd", + "metadata": {}, + "source": [ + "#### And" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "68766f90", + "metadata": {}, + "outputs": [], + "source": [ + "def _and(evm):\n", + " a, b = evm.stack.pop(), evm.stack.pop()\n", + " evm.stack.push(a & b)\n", + " evm.pc += 1\n", + " evm.gas_dec(3)" + ] + }, + { + "cell_type": "markdown", + "id": "d1198500", + "metadata": {}, + "source": [ + "#### Or" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9a909b61", + "metadata": {}, + "outputs": [], + "source": [ + "def _or(evm): \n", + " a, b = evm.stack.pop(), evm.stack.pop()\n", + " evm.stack.push(a | b)\n", + " evm.pc += 1\n", + " evm.gas_dec(3)" + ] + }, + { + "cell_type": "markdown", + "id": "c22ed407", + "metadata": {}, + "source": [ + "#### Xor" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c95f5b28", + "metadata": {}, + "outputs": [], + "source": [ + "def _xor(evm): \n", + " a, b = evm.stack.pop(), evm.stack.pop()\n", + " evm.stack.push(a ^ b)\n", + " evm.pc += 1\n", + " evm.gas_dec(3)" + ] + }, + { + "cell_type": "markdown", + "id": "8d004584", + "metadata": {}, + "source": [ + "#### Not" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b4592b76", + "metadata": {}, + "outputs": [], + "source": [ + "def _not(evm): \n", + " a = evm.stack.pop()\n", + " evm.stack.push(~a)\n", + " evm.pc += 1\n", + " evm.gas_dec(3)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/10_bit.ipynb b/10_bit.ipynb new file mode 100644 index 0000000..045fb60 --- /dev/null +++ b/10_bit.ipynb @@ -0,0 +1,249 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 10, + "id": "95b550aa", + "metadata": {}, + "outputs": [], + "source": [ + "%%capture\n", + "%run utils.ipynb" + ] + }, + { + "cell_type": "markdown", + "id": "a809800a", + "metadata": {}, + "source": [ + "# Bit" + ] + }, + { + "cell_type": "markdown", + "id": "1530d6d5", + "metadata": {}, + "source": [ + "Again, same concept but for bit operations." + ] + }, + { + "cell_type": "markdown", + "id": "01e1ac2e", + "metadata": {}, + "source": [ + "#### Byte" + ] + }, + { + "cell_type": "markdown", + "id": "6b6227a2", + "metadata": {}, + "source": [ + "Get one byte from a word (32 bytes)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "444c69ad", + "metadata": {}, + "outputs": [], + "source": [ + "def byte(evm):\n", + " i, x = evm.stack.pop(), evm.stack.pop()\n", + " if i >= 32: result = 0\n", + " else : result = (x // pow(256, 31 - i)) % 256\n", + " evm.pc += 1\n", + " evm.gas_dec(3)" + ] + }, + { + "cell_type": "markdown", + "id": "5b300560", + "metadata": {}, + "source": [ + "## Bit shifts" + ] + }, + { + "cell_type": "markdown", + "id": "d6e4bc31", + "metadata": {}, + "source": [ + "Lets see what a bit shift operation looks like" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "df3b7125", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'0b10110'" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bin(22) # binary of 22" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "a53d8eb3", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'0b1011000'" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bin(22 << 2) # bit shift by 2 to the left" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "07ef38cc", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'0b101'" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bin(22 >> 2) # bit shift by 2 to the right" + ] + }, + { + "cell_type": "markdown", + "id": "63e6072a", + "metadata": {}, + "source": [ + "#### Bit Shift left" + ] + }, + { + "cell_type": "markdown", + "id": "8f7b1248", + "metadata": {}, + "source": [ + "`1010` bit shifted left by `2` positions becomes `101000`" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "7c02c981", + "metadata": {}, + "outputs": [], + "source": [ + "def shl(evm): \n", + " shift, value = cpu.stack.pop(), cpu.stack.pop()\n", + " evm.stack.push(value << shift)\n", + " evm.pc += 1\n", + " evm.gas_dec(3)" + ] + }, + { + "cell_type": "markdown", + "id": "0177d01b", + "metadata": {}, + "source": [ + "#### Bit Shift right" + ] + }, + { + "cell_type": "markdown", + "id": "2f549a05", + "metadata": {}, + "source": [ + "`1010` bit shifted left by `2` positions becomes `10`" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "2089a68a", + "metadata": {}, + "outputs": [], + "source": [ + "def shr(evm): \n", + " shift, value = evm.stack.pop(), evm.stack.pop()\n", + " evm.stack.push(value >> shift)\n", + " evm.pc += 1\n", + " evm.gas_dec(3)" + ] + }, + { + "cell_type": "markdown", + "id": "b7f6579f", + "metadata": {}, + "source": [ + "#### Signed Shift right" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "e23f78a5", + "metadata": {}, + "outputs": [], + "source": [ + "def sar(evm):\n", + " shift, value = evm.stack.pop(), evm.stack.pop()\n", + " if shift >= 256:\n", + " result = 0 if value >= 0 else UINT_255_NEGATIVE_ONE\n", + " else:\n", + " result = (value >> shift) & UINT_256_MAX\n", + " \n", + " evm.stack.push(result)\n", + " evm.pc += 1\n", + " evm.gas_dec(3)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/11_misc.ipynb b/11_misc.ipynb new file mode 100644 index 0000000..92d1604 --- /dev/null +++ b/11_misc.ipynb @@ -0,0 +1,142 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "03255559", + "metadata": {}, + "source": [ + "# Misc" + ] + }, + { + "cell_type": "markdown", + "id": "1fa2b79c", + "metadata": {}, + "source": [ + "This one was hard to classify" + ] + }, + { + "cell_type": "markdown", + "id": "5a83e2c5", + "metadata": {}, + "source": [ + "## Precompiles" + ] + }, + { + "cell_type": "markdown", + "id": "c35282b3", + "metadata": {}, + "source": [ + "Precompiles in Ethereum are programs that the EVM can execute directly. They are currently 9 of them.\n", + "\n", + "Implementing these functions in EVM bytecode would be very gas inefficient. So it was decided to include them in the EVM itself." + ] + }, + { + "cell_type": "markdown", + "id": "bab834a0", + "metadata": {}, + "source": [ + "![title](static/precompiles.png)" + ] + }, + { + "cell_type": "markdown", + "id": "61cbd5fe", + "metadata": {}, + "source": [ + "[source](https://www.evm.codes/precompiled)" + ] + }, + { + "cell_type": "markdown", + "id": "df67ab16", + "metadata": {}, + "source": [ + "## Opcode vs Precompile" + ] + }, + { + "cell_type": "markdown", + "id": "9b86e635", + "metadata": {}, + "source": [ + "The `sha3` could have easily been a precompile. Weather an operation should be a opcode or a precomiple is a matter of debate in the Ethereum community." + ] + }, + { + "cell_type": "markdown", + "id": "46c90997", + "metadata": {}, + "source": [ + "#### Hash Function" + ] + }, + { + "cell_type": "markdown", + "id": "59d14529", + "metadata": {}, + "source": [ + "A hash function is one of the most important cryptographic primitives. It has the following characteristics:\n", + "\n", + "- fixed sized: every input (also called message) creates a hash value of fixed size.\n", + "- deterministic: the same input will produce the same output every time.\n", + "- one-way: its practically infeasible to invert.\n", + "- chaotic: if only one bit changes the whole hash changes in a toatlly chaotic and random way." + ] + }, + { + "cell_type": "markdown", + "id": "b9bd4491", + "metadata": {}, + "source": [ + "Note that we are using the Python built-in `hash` function, so we do not have to import any external library. \n", + "\n", + "The EVM uses the Keccak-256 function. " + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "4c317dc4", + "metadata": {}, + "outputs": [], + "source": [ + "def sha3(evm):\n", + " offset, size = evm.stack.pop(), evm.stack.pop()\n", + " value = evm.memory.access(offset, size)\n", + " evm.stack.push(hash(str(value)))\n", + "\n", + " evm.pc += 1\n", + "\n", + " # calculate gas\n", + " minimum_word_size = (size + 31) / 32\n", + " dynamic_gas = 6 * minimum_word_size # TODO: + memory_expansion_cost\n", + " evm.gas_dec(30 + dynamic_gas)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/12_environment.ipynb b/12_environment.ipynb new file mode 100644 index 0000000..ca575e3 --- /dev/null +++ b/12_environment.ipynb @@ -0,0 +1,478 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "03255559", + "metadata": {}, + "source": [ + "# Environment" + ] + }, + { + "cell_type": "markdown", + "id": "1fa2b79c", + "metadata": {}, + "source": [ + "These opcodes give you access to the Ethereum environment" + ] + }, + { + "cell_type": "markdown", + "id": "451ec894", + "metadata": {}, + "source": [ + "#### Address" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "e957a322", + "metadata": {}, + "outputs": [], + "source": [ + "def address(evm):\n", + " evm.stack.push(\"0x414b60745072088d013721b4a28a0559b1A9d213\")\n", + " evm.pc += 1\n", + " evm.gas_dec(3)" + ] + }, + { + "cell_type": "markdown", + "id": "c773cc1b", + "metadata": {}, + "source": [ + "#### Balance" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "2a4f4184", + "metadata": {}, + "outputs": [], + "source": [ + "def balance(evm):\n", + " address = cpu.stack.pop()\n", + " evm.stack.push(99999999999)\n", + "\n", + " evm.pc += 1\n", + " evm.gas_dec(2600) # 100 if warm" + ] + }, + { + "cell_type": "markdown", + "id": "e3d1f582", + "metadata": {}, + "source": [ + "#### Origin" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "184910fc", + "metadata": {}, + "outputs": [], + "source": [ + "def origin(evm):\n", + " evm.stack.push(\"0x414b60745072088d013721b4a28a0559b1A9d213\")\n", + " evm.pc += 1\n", + " evm.gas_dec(2)" + ] + }, + { + "cell_type": "markdown", + "id": "1420754f", + "metadata": {}, + "source": [ + "#### Caller" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "7e6253d7", + "metadata": {}, + "outputs": [], + "source": [ + "def caller(evm):\n", + " evm.stack.push(\"0x414b60745072088d013721b4a28a0559b1A9d213\")\n", + " evm.pc += 1\n", + " evm.gas_dec(2)" + ] + }, + { + "cell_type": "markdown", + "id": "8a5c3ddc", + "metadata": {}, + "source": [ + "#### Callvalue" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "ed2ce73a", + "metadata": {}, + "outputs": [], + "source": [ + "def callvalue(evm):\n", + " evm.stack.push(evm.value)\n", + " evm.pc += 1\n", + " evm.gas_dec(2)" + ] + }, + { + "cell_type": "markdown", + "id": "10e433b9", + "metadata": {}, + "source": [ + "#### Calldataload" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5e50b0a6", + "metadata": {}, + "outputs": [], + "source": [ + "def calldataload(evm):\n", + " i = evm.stack.pop()\n", + "\n", + " delta = 0\n", + " if i+32 > len(evm.calldata):\n", + " delta = i+32 - len(evm.calldata)\n", + "\n", + " # always has to be 32 bytes\n", + " # if its not we append 0x00 bytes until it is\n", + " calldata = evm.calldata[i:i+32-delta]\n", + " calldata += 0x00*delta\n", + "\n", + " evm.stack.push(calldata)\n", + " evm.pc += 1\n", + " evm.gas_dec(3)" + ] + }, + { + "cell_type": "markdown", + "id": "f51d42de", + "metadata": {}, + "source": [ + "#### Calldatasize" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "f113ad83", + "metadata": {}, + "outputs": [], + "source": [ + "def calldatasize(evm):\n", + " evm.stack.push(len(evm.calldata))\n", + " evm.pc += 1\n", + " evm.gas_dec(2)" + ] + }, + { + "cell_type": "markdown", + "id": "cc2b23e4", + "metadata": {}, + "source": [ + "#### Calldatacopy" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "fad6dc1e", + "metadata": {}, + "outputs": [], + "source": [ + "def calldatacopy(evm):\n", + " destOffset = cpu.stack.pop()\n", + " offset = evm.stack.pop()\n", + " size = evm.stack.pop()\n", + "\n", + " calldata = evm.calldata[offset:offset+size]\n", + " memory_expansion_cost = evm.memory.store(destOffset, calldata)\n", + "\n", + " static_gas = 3\n", + " minimum_word_size = (size + 31) // 32\n", + " dynamic_gas = 3 * minimum_word_size + memory_expansion_cost\n", + "\n", + " evm.gas_dec(static_gas + dynamic_gas)\n", + " evm.pc += 1" + ] + }, + { + "cell_type": "markdown", + "id": "e4198cdc", + "metadata": {}, + "source": [ + "#### Codesize" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "3722d443", + "metadata": {}, + "outputs": [], + "source": [ + "def codesize(evm):\n", + " evm.stack.push(len(evm.program))\n", + " evm.pc += 1\n", + " evm.gas_dec(2)" + ] + }, + { + "cell_type": "markdown", + "id": "3ec39a93", + "metadata": {}, + "source": [ + "#### Codecopy" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "9c145044", + "metadata": {}, + "outputs": [], + "source": [ + "def codecopy(evm):\n", + " destOffset = evm.stack.pop()\n", + " offset = evm.stack.pop()\n", + " size = evm.stack.pop()\n", + "\n", + " code = evm.program[offset:offset+size]\n", + " memory_expansion_cost = evm.memory.store(destOffset, code)\n", + "\n", + " static_gas = 3\n", + " minimum_word_size = (size + 31) / 32\n", + " dynamic_gas = 3 * minimum_word_size + memory_expansion_cost\n", + "\n", + " evm.gas_dec(static_gas + dynamic_gas)\n", + " evm.pc += 1" + ] + }, + { + "cell_type": "markdown", + "id": "6b2e5e49", + "metadata": {}, + "source": [ + "#### Gas Price" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "f11fcf1b", + "metadata": {}, + "outputs": [], + "source": [ + "def gasprice(evm):\n", + " evm.stack.push(0x00)\n", + " evm.pc += 1\n", + " evm.gas_dec(2)" + ] + }, + { + "cell_type": "markdown", + "id": "bbf3852f", + "metadata": {}, + "source": [ + "#### External Code Size" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "12b53b96", + "metadata": {}, + "outputs": [], + "source": [ + "def extcodesize(evm):\n", + " address = evm.stack.pop()\n", + " evm.stack.push(0x00)\n", + " evm.gas_dec(2600) # 100 if warm\n", + " evm.pc += 1" + ] + }, + { + "cell_type": "markdown", + "id": "5c234854", + "metadata": {}, + "source": [ + "#### External Code Copy" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "934ca4f6", + "metadata": {}, + "outputs": [], + "source": [ + "def extcodecopy(evm):\n", + " address = evm.stack.pop()\n", + " destOffset = evm.stack.pop()\n", + " offset = evm.stack.pop()\n", + " size = evm.stack.pop()\n", + "\n", + " extcode = [] # no external code\n", + " memory_expansion_cost = evm.memory.store(destOffset, extcode)\n", + "\n", + " # refactor this in seperate method\n", + " minimum_word_size = (size + 31) / 32\n", + " dynamic_gas = 3 * minimum_word_size + memory_expansion_cost\n", + " address_access_cost = 100 if warm else 2600\n", + "\n", + " evm.gas_dec(dynamic_gas + address_access_cost)\n", + " evm.pc += 1" + ] + }, + { + "cell_type": "markdown", + "id": "93e06567", + "metadata": {}, + "source": [ + "#### Return Data Size" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "f9dce9b3", + "metadata": {}, + "outputs": [], + "source": [ + "def returndatasize(evm):\n", + " evm.stack.push(0x00) # no return data\n", + " evm.pc += 1\n", + " evm.gas_dec(2)" + ] + }, + { + "cell_type": "markdown", + "id": "af214873", + "metadata": {}, + "source": [ + "#### Return Data Copy" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "ec3f21e0", + "metadata": {}, + "outputs": [], + "source": [ + "def returndatacopy(evm):\n", + " destOffset = evm.stack.pop()\n", + " offset = evm.stack.pop()\n", + " size = evm.stack.pop()\n", + "\n", + " returndata = evm.program[offset:offset+size]\n", + " memory_expansion_cost = evm.memory.store(destOffset, returndata)\n", + "\n", + " minimum_word_size = (size + 31) / 32\n", + " dynamic_gas = 3 * minimum_word_size + memory_expansion_cost\n", + "\n", + " evm.gas_dec(3 + dynamic_gas)\n", + " evm.pc += 1" + ] + }, + { + "cell_type": "markdown", + "id": "429ca19e", + "metadata": {}, + "source": [ + "#### External Code Hash" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0501762f", + "metadata": {}, + "outputs": [], + "source": [ + "def extcodehash(evm):\n", + " address = evm.stack.pop()\n", + " evm.stack.push(0x00) # no code\n", + "\n", + " evm.gas_dec(2600) # 100 if warm\n", + " evm.pc += 1" + ] + }, + { + "cell_type": "markdown", + "id": "8ccb0b87", + "metadata": {}, + "source": [ + "#### Block Hash" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a8bc2485", + "metadata": {}, + "outputs": [], + "source": [ + "def blockhash(evm):\n", + " blockNumber = evm.stack.pop()\n", + " if blockNumber > 256: raise Exception(\"Only last 256 blocks can be accessed\")\n", + " evm.stack.push(0x1cbcfa1ffb1ca1ca8397d4f490194db5fc0543089b9dee43f76cf3f962a185e8)\n", + " evm.pc += 1\n", + " evm.gas_dec(20)" + ] + }, + { + "cell_type": "markdown", + "id": "94fd73fd", + "metadata": {}, + "source": [ + "#### Coinbase" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7808257e", + "metadata": {}, + "outputs": [], + "source": [ + "def coinbase(evm):\n", + " evm.stack.push(0x1cbcfa1ffb1ca1ca8397d4f490194db5fc0543089b9dee43f76cf3f962a185e8)\n", + " evm.pc += 1\n", + " evm.gas_dec(2)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/13_pop.ipynb b/13_pop.ipynb new file mode 100644 index 0000000..3e193c4 --- /dev/null +++ b/13_pop.ipynb @@ -0,0 +1,38 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "c6946ddc", + "metadata": {}, + "outputs": [], + "source": [ + "def _pop(evm, n):\n", + " evm.pc += 2\n", + " evm.gas_dec(2)\n", + " evm.stack.pop(n)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/14_memory.ipynb b/14_memory.ipynb new file mode 100644 index 0000000..fee837c --- /dev/null +++ b/14_memory.ipynb @@ -0,0 +1,78 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "7ed46c5f", + "metadata": {}, + "source": [ + "There are three memory opcodes that are important for us. One for loading and two for storing.\n", + "\n", + "`MLOAD` lets us load one `word` specified by an offset. A word is 32 bytes. \n", + "\n", + "`MSTORE` allows us to save one word to memory and `MSTORE8` allows us to save one byte to memory." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "6138c94e", + "metadata": {}, + "outputs": [], + "source": [ + "def mload(evm): \n", + " offset = evm.stack.pop()\n", + " value = evm.memory.load(offset)\n", + " evm.stack.push(value)\n", + " evm.pc += 1" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "424c7048", + "metadata": {}, + "outputs": [], + "source": [ + "def mstore(evm): \n", + " # TODO: should be right aligned\n", + " offset, value = evm.stack.pop(), cpu.stack.pop()\n", + " evm.memory.store(offset, value)\n", + " evm.pc += 1" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "210cabec", + "metadata": {}, + "outputs": [], + "source": [ + "def mstore8(evm): \n", + " offset, value = evm.stack.pop(), evm.stack.pop()\n", + " evm.memory.store(offset, value)\n", + " evm.pc += 1" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/15_storage.ipynb b/15_storage.ipynb new file mode 100644 index 0000000..3510b40 --- /dev/null +++ b/15_storage.ipynb @@ -0,0 +1,69 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "id": "ae2ab819", + "metadata": {}, + "outputs": [], + "source": [ + "def sload(evm): \n", + " key = evm.stack.pop().value\n", + " warm, value = evm.storage.load(key)\n", + " evm.stack.push(value)\n", + "\n", + " evm.gas_dec(2100) # 100 if warm\n", + " evm.pc += 1" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "69b473ab", + "metadata": {}, + "outputs": [], + "source": [ + "def sstore(evm): \n", + " key, value = evm.stack.pop(), evm.stack.pop()\n", + " warm, old_value = evm.storage.store(key, value)\n", + "\n", + " base_dynamic_gas = 0\n", + "\n", + " # TODO: test\n", + " if value != old_value:\n", + " if old_value == 0:\n", + " base_dynamic_gas = 20000\n", + " else:\n", + " base_dynamic_gas = 2900\n", + "\n", + " access_cost = 100 if warm else 2100\n", + " evm.gas_dec(base_dynamic_gas + access_cost)\n", + "\n", + " evm.pc += 1\n", + "\n", + " # TODO: do refunds" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/16_jump.ipynb b/16_jump.ipynb new file mode 100644 index 0000000..edbe5ac --- /dev/null +++ b/16_jump.ipynb @@ -0,0 +1,95 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "1918e1c6", + "metadata": {}, + "outputs": [], + "source": [ + "%%capture\n", + "%run 05_opcodes.ipynb" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "bb5677c7", + "metadata": {}, + "outputs": [], + "source": [ + "def jump(evm):\n", + " counter = evm.stack.pop()\n", + "\n", + " # make sure that we jump to an JUMPDEST opcode\n", + " if not evm.program[counter] == JUMPDEST:\n", + " raise Exception(\"Can only jump to JUMPDEST\")\n", + "\n", + " evm.pc = counter\n", + " evm.gas_dec(8)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "d8d64ef0", + "metadata": {}, + "outputs": [], + "source": [ + "def jumpi(evm):\n", + " counter, b = evm.stack.pop(), evm.stack.pop()\n", + "\n", + " if b != 0: evm.pc = counter\n", + " else : evm.pc += 1\n", + " \n", + " evm.gas_dec(10)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "8c881ffe", + "metadata": {}, + "outputs": [], + "source": [ + "def pc(evm):\n", + " evm.stack.push(cpu.pc)\n", + " evm.pc += 1\n", + " evm.gas_dec(2)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "4619b73f", + "metadata": {}, + "outputs": [], + "source": [ + "def jumpdest(evm):\n", + " evm.pc += 1\n", + " evm.gas_dec(1)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/17_push.ipynb b/17_push.ipynb new file mode 100644 index 0000000..bc36f73 --- /dev/null +++ b/17_push.ipynb @@ -0,0 +1,43 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 6, + "id": "b80b0357", + "metadata": {}, + "outputs": [], + "source": [ + "def _push(evm, n):\n", + " evm.pc += 1\n", + " evm.gas_dec(3)\n", + " \n", + " value = []\n", + " for _ in range(n):\n", + " value.append(evm.peek())\n", + " evm.pc += 1\n", + " evm.stack.push(int(''.join(map(str, value))))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/18_dup.ipynb b/18_dup.ipynb new file mode 100644 index 0000000..0385423 --- /dev/null +++ b/18_dup.ipynb @@ -0,0 +1,41 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "id": "bbba6da5", + "metadata": {}, + "outputs": [], + "source": [ + "def _dup(evm, n):\n", + " # make sure stack is big enough!\n", + " value = evm.stack[n]\n", + " evm.stack.push(value)\n", + "\n", + " evm.pc += 1\n", + " evm.gas_dec(3)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/19_swap.ipynb b/19_swap.ipynb new file mode 100644 index 0000000..fde75d4 --- /dev/null +++ b/19_swap.ipynb @@ -0,0 +1,41 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "d0c26d81", + "metadata": {}, + "outputs": [], + "source": [ + "def _swap(evm, n):\n", + " value1, value2 = evm.stack.get(0), evm.stack.get(n+1)\n", + " evm.stack.set(0, value2)\n", + " evm.stack.set(n+1, value1)\n", + "\n", + " evm.pc += 1\n", + " evm.gas_dec(3)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/20_log.ipynb b/20_log.ipynb new file mode 100644 index 0000000..8f46f15 --- /dev/null +++ b/20_log.ipynb @@ -0,0 +1,160 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "id": "e64eb222", + "metadata": {}, + "outputs": [], + "source": [ + "class Log:\n", + " def __init__(self,\n", + " data,\n", + " topic1=None,\n", + " topic2=None,\n", + " topic3=None,\n", + " topic4=None):\n", + " \n", + " self.data = data\n", + " self.topic1 = topic1\n", + " self.topic2 = topic2\n", + " self.topic3 = topic3\n", + " self.topic4 = topic4\n", + "\n", + " def __str__(self): return f\"Log: {self.data}\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "4d252a12", + "metadata": {}, + "outputs": [], + "source": [ + "def calc_gas(topic_count, size, memory_expansion_cost=0):\n", + " # 375 := static_gas\n", + " return 375 * topic_count + 8 * size + memory_expansion_cost" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "0f387cf1", + "metadata": {}, + "outputs": [], + "source": [ + "def log0(evm):\n", + " offset, size = evm.stack.pop(), evm.stack.pop()\n", + "\n", + " data = evm.memory.access(offset, size)\n", + " log = Log(data)\n", + " evm.append_log(log)\n", + "\n", + " evm.pc += 1\n", + " evm.gas_dec(calc_gas(0, size)) # TODO: memeory expansion cost" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "2cf8b1a5", + "metadata": {}, + "outputs": [], + "source": [ + "def log1(evm):\n", + " offset, size = evm.stack.pop(), evm.stack.pop()\n", + " topic = evm.stack.pop().value\n", + "\n", + " data = evm.memory.access(offset, size)\n", + " log = Log(data, topic)\n", + " evm.append_log(log)\n", + "\n", + " evm.pc += 1\n", + " evm.gas_dec(calc_gas(1, size)) # TODO: memeory expansion cost\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "b6bc3b7f", + "metadata": {}, + "outputs": [], + "source": [ + "def log2(evm):\n", + " offset, size = evm.stack.pop(), evm.stack.pop()\n", + " topic1, topic2 = evm.stack.pop(), evm.stack.pop()\n", + "\n", + " data = evm.memory.access(offset, size)\n", + " log = Log(data, topic1, topic2)\n", + " evm.append_log(log)\n", + "\n", + " evm.pc += 1\n", + " evm.gas_dec(calc_gas(2, size)) # TODO: memeory expansion cost" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "47084c53", + "metadata": {}, + "outputs": [], + "source": [ + "def log3(evm):\n", + " offset, size = evm.stack.pop(), evm.stack.pop()\n", + " topic1 = evm.stack.pop()\n", + " topic2 = evm.stack.pop()\n", + " topic3 = evm.stack.pop()\n", + "\n", + " data = evm.memory.access(offset, size)\n", + " log = Log(data, topic1, topic2, topic3)\n", + " evm.append_log(log)\n", + "\n", + " evm.pc += 1\n", + " evm.gas_dec(calc_gas(3, size)) # TODO: memeory expansion cost\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "8332ffe1", + "metadata": {}, + "outputs": [], + "source": [ + "def log4(cpu):\n", + " offset, size = evm.stack.pop(), evm.stack.pop()\n", + " topic1 = evm.stack.pop()\n", + " topic2 = evm.stack.pop()\n", + " topic3 = evm.stack.pop()\n", + " topic4 = evm.stack.pop()\n", + "\n", + " data = evm.memory.access(offset, size)\n", + " log = Log(data, topic1, topic2, topic3, topic4)\n", + " evm.append_log(log)\n", + "\n", + " evm.pc += 1\n", + " evm.gas_dec(calc_gas(4, size)) # TODO: memeory expansion cost" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/21_contract.ipynb b/21_contract.ipynb new file mode 100644 index 0000000..0f79773 --- /dev/null +++ b/21_contract.ipynb @@ -0,0 +1,42 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "dbd20aa5", + "metadata": {}, + "outputs": [], + "source": [ + "def revert(evm):\n", + " offset, size = evm.stack.pop(), evm.stack.pop()\n", + " evm.returndata = evm.memory.access(offset, size)\n", + "\n", + " evm.stop_flag = True\n", + " evm.revert_flag = True\n", + " evm.pc += 1\n", + " evm.gas_dec(0)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/24_evm.ipynb b/24_evm.ipynb new file mode 100644 index 0000000..6766f45 --- /dev/null +++ b/24_evm.ipynb @@ -0,0 +1,136 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 45, + "id": "554af289", + "metadata": {}, + "outputs": [], + "source": [ + "%%capture\n", + "%run 02_stack.ipynb\n", + "%run 03_memory.ipynb\n", + "%run 04_storage.ipynb\n", + "%run 05_opcodes.ipynb\n", + "%run 06_stop.ipynb\n", + "%run 07_math.ipynb\n", + "%run push.ipynb" + ] + }, + { + "cell_type": "markdown", + "id": "8a939971", + "metadata": {}, + "source": [ + "# EVM" + ] + }, + { + "cell_type": "markdown", + "id": "4a9a06a9", + "metadata": {}, + "source": [ + "Now we are going to put everything together." + ] + }, + { + "cell_type": "markdown", + "id": "565cc202", + "metadata": {}, + "source": [ + "### Program Counter" + ] + }, + { + "cell_type": "markdown", + "id": "695c62f1", + "metadata": {}, + "source": [ + "The program counter indexes into the bytecode. It tells the EVM which opcode to execute next" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "67ef5ff6", + "metadata": {}, + "outputs": [], + "source": [ + "class EVM:\n", + " def __init__(self,\n", + " program,\n", + " gas,\n", + " value,\n", + " calldata=[]):\n", + " self.pc = 0\n", + " self.stack = Stack()\n", + " self.memory = Memory()\n", + " self.storage = Storage()\n", + " \n", + " self.program = program\n", + " self.gas = gas\n", + " self.value = value\n", + " self.calldata = calldata\n", + " \n", + " self.stop_flag = False\n", + " self.revert_flag = False\n", + " \n", + " self.returndata = []\n", + " self.logs = []\n", + " \n", + " def peek(self): return self.program[self.pc]\n", + " \n", + " def gas_dec(self, amount):\n", + " if self.gas - amount < 0: \n", + " raise Exception(\"out of gas\")\n", + " self.gas -= amount\n", + "\n", + " \n", + " def should_execute_next_opcode(self):\n", + " if self.pc > len(self.program)-1: return False\n", + " if self.stop_flag : return False\n", + " if self.revert_flag : return False\n", + " \n", + " return True\n", + " \n", + " def run(self):\n", + " while self.should_execute_next_opcode():\n", + " op = self.program[self.pc]\n", + " \n", + " if op == STOP: stop(self)\n", + " \n", + " if op == ADD: add(self)\n", + "\n", + " \n", + " if op == PUSH1: _push(self, 1)\n", + " \n", + " def reset(self):\n", + " self.pc = 0\n", + " self.stack = Stack()\n", + " self.memory = Memory()\n", + " self.storage = Storage()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/25_bytecode.ipynb b/25_bytecode.ipynb new file mode 100644 index 0000000..8445cc3 --- /dev/null +++ b/25_bytecode.ipynb @@ -0,0 +1,144 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "dc9ace8b", + "metadata": {}, + "source": [ + "# Bytecode" + ] + }, + { + "cell_type": "markdown", + "id": "389b791e", + "metadata": {}, + "source": [ + "Now that we have the EVM we can talk a little more about the Bytecode. Bytecode is executed by the EVM." + ] + }, + { + "cell_type": "markdown", + "id": "6114cfac", + "metadata": {}, + "source": [ + "Valid Bytecode is simply a list of valid opcodes and their operands.\n", + "We call a list of opcodes and their operands a `program`." + ] + }, + { + "cell_type": "markdown", + "id": "b7808406", + "metadata": {}, + "source": [ + "## Simple Push" + ] + }, + { + "cell_type": "markdown", + "id": "16994d42", + "metadata": {}, + "source": [ + "The program that pushes `0x42` on the stack would look like this." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "4450aec6", + "metadata": {}, + "outputs": [], + "source": [ + "SIMPLE_PUSH = [0x60, 0x42]" + ] + }, + { + "cell_type": "markdown", + "id": "fcf88cd0", + "metadata": {}, + "source": [ + "or simply: `0x6042`" + ] + }, + { + "cell_type": "markdown", + "id": "7426f37d", + "metadata": {}, + "source": [ + "## Instructions and Data" + ] + }, + { + "cell_type": "markdown", + "id": "4c8f610f", + "metadata": {}, + "source": [ + "As you can see, the bytecode consists of both instructions **and** data. It is up to the program writer to make sure that data and instructions are not mixed up.\n", + "\n", + "This is what we call the `von Neumann architecture`." + ] + }, + { + "cell_type": "markdown", + "id": "41e5bc83", + "metadata": {}, + "source": [ + "## Simple Add" + ] + }, + { + "cell_type": "markdown", + "id": "932d9ed8", + "metadata": {}, + "source": [ + "Another simple program could look like this. Here we push `0x42` and `0xFF` on the stack and add them together and put the result back onto the stack." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "54d5943c", + "metadata": {}, + "outputs": [], + "source": [ + "SIMPLE_ADD = [0x60, 0x42, 0x60, 0xFF, 0x01]" + ] + }, + { + "cell_type": "markdown", + "id": "cdf9846a", + "metadata": {}, + "source": [ + "After executing this we should have a stack with exactly one element `321` on it." + ] + }, + { + "cell_type": "markdown", + "id": "a155489e", + "metadata": {}, + "source": [ + "In the next step we will use the EVM that we built to actually execute these programs." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/26_run.ipynb b/26_run.ipynb new file mode 100644 index 0000000..57a683f --- /dev/null +++ b/26_run.ipynb @@ -0,0 +1,109 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 128, + "id": "3e486478", + "metadata": {}, + "outputs": [], + "source": [ + "%%capture\n", + "%run evm.ipynb\n", + "%run bytecode.ipynb" + ] + }, + { + "cell_type": "code", + "execution_count": 129, + "id": "d2f28323", + "metadata": {}, + "outputs": [], + "source": [ + "GAS = 21_000" + ] + }, + { + "cell_type": "markdown", + "id": "22a5936c", + "metadata": {}, + "source": [ + "Set up the EVM" + ] + }, + { + "cell_type": "code", + "execution_count": 130, + "id": "ecb05fe2", + "metadata": {}, + "outputs": [], + "source": [ + "evm = EVM(SIMPLE_ADD, GAS)" + ] + }, + { + "cell_type": "markdown", + "id": "42b8dd02", + "metadata": {}, + "source": [ + "Run it!" + ] + }, + { + "cell_type": "code", + "execution_count": 131, + "id": "329276d5", + "metadata": {}, + "outputs": [], + "source": [ + "evm.run()" + ] + }, + { + "cell_type": "markdown", + "id": "eee75486", + "metadata": {}, + "source": [ + "Take a look at the result" + ] + }, + { + "cell_type": "code", + "execution_count": 132, + "id": "b6b6da94", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "321\n" + ] + } + ], + "source": [ + "print(evm.stack)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/99_conclusion.ipynb b/99_conclusion.ipynb new file mode 100644 index 0000000..a2512ac --- /dev/null +++ b/99_conclusion.ipynb @@ -0,0 +1,58 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "f48af006", + "metadata": {}, + "source": [ + "Things we are not considering:\n", + "\n", + "- under/over-flow protection\n", + "- state access warm/cold like extcodesize\n", + "- no proof of stake opcodes\n", + "- gas refund\n", + "- static call\n", + "- delegate call" + ] + }, + { + "cell_type": "markdown", + "id": "40a332e8", + "metadata": {}, + "source": [ + "## Resources" + ] + }, + { + "cell_type": "markdown", + "id": "66ce841f", + "metadata": {}, + "source": [ + "If you are looking for a understandable reference implemenation I highly recommend [Py-EVM](https://github.com/ethereum/py-evm).\n", + "\n", + "[evm.codes](https://www.evm.codes/) is the best reference for looking opcodes and what they do." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/_build/.doctrees/environment.pickle b/_build/.doctrees/environment.pickle index d6ce590e61d951238aedd6cf26b5459f6429d079..2f2a801e1fdd235a77dd49afbccb37d4ffeed193 100644 GIT binary patch literal 87504 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 M-(7?XqChhL8yo=+C;$Ke delta 10178 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 diff --git a/_build/html/objects.inv b/_build/html/objects.inv index 1900e07..69b158e 100644 --- a/_build/html/objects.inv +++ b/_build/html/objects.inv @@ -2,5 +2,8 @@ # Project: Python # Version: # The remainder of this file is compressed using zlib. -xڅK -0EYE6P:s@(LI0i"s/!h$<ÞT!eeV[d<2K'6XkDN;hhQ/)췃4cţX/~L>ւ:MKT0s RH$} \ No newline at end of file +xڅQo Mfi*jI{Èep_Ϧ-(|Csa -).<!2g + F78C0rL&Qr: B +_O !nS_(ϰ tv +h9@7"+Fs FxsD@%** FA/:Ƹ5*5F\W=:kP< iuMСW \H\h]'OV0y +{Mi&M`P4ǵ YF!+YdիAv&7A-?JÎ .SVqͤ{OfzPMQYm;7T2SRHt[`6bM2qݕfNɏ*W)U{%Fy…O/PӜ \ No newline at end of file diff --git a/_build/html/searchindex.js b/_build/html/searchindex.js index c19e1dd..29197bd 100644 --- a/_build/html/searchindex.js +++ b/_build/html/searchindex.js @@ -1 +1 @@ -Search.setIndex({"docnames": ["02_a_gas", "02_stack", "03_memory", "intro"], "filenames": ["02_a_gas.ipynb", "02_stack.ipynb", "03_memory.ipynb", "intro.ipynb"], "titles": ["Gas", "Stack", "Memory", "Introduction"], "terms": {"The": [1, 2, 3], "veri": [0, 1, 3], "simpl": [1, 2, 3], "data": 1, "structur": 1, "It": [0, 1, 2, 3], "list": [1, 2, 3], "one": 1, "restrction": 1, "you": [0, 1, 3], "can": [1, 2, 3], "onli": [1, 3], "directli": [1, 3], "interact": [1, 3], "top": 1, "push": 1, "new": [1, 3], "valu": [0, 1, 2], "pop": 1, "an": [0, 1, 2, 3], "alreadi": [1, 3], "exist": 1, "from": [1, 2, 3], "A": [1, 2, 3], "plate": 1, "good": [1, 3], "metaphor": 1, "add": [1, 2, 3], "remov": 1, "work": [0, 1, 3], "exact": 1, "same": 1, "wai": [1, 2], "evm": 1, "ha": [0, 1, 3], "maximum": 1, "capac": 1, "1024": 1, "item": 1, "everi": [1, 3], "max": 1, "256": 1, "bit": [1, 2], "32": [1, 2], "byte": [1, 2], "maximum_stack_s": 1, "we": [0, 1, 2, 3], "also": [1, 2, 3], "throw": 1, "except": 1, "try": 1, "empti": [1, 2], "class": [1, 2], "def": [1, 2], "__init__": [1, 2], "self": [1, 2], "__str__": 1, "return": [1, 2], "n": 1, "join": 1, "map": 1, "str": 1, "1": [1, 2], "len": [1, 2], "rais": 1, "overflow": 1, "append": [1, 2], "0": [1, 2], "underflow": 1, "del": 1, "creat": [1, 2, 3], "3": [1, 2], "2": [1, 2], "4": [1, 2], "print": 1, "typeerror": 1, "traceback": 1, "most": [1, 3], "recent": 1, "call": [1, 3], "last": 1, "var": 1, "folder": 1, "08": 1, "q0syv9y576b_rnls32m9d3nr0000gn": 1, "t": [1, 3], "ipykernel_13808": [], "1192403925": 1, "py": 1, "cell": [1, 2], "line": 1, "miss": 1, "requir": 1, "posit": 1, "argument": 1, "now": 1, "ar": [0, 1, 3], "left": 1, "each": 2, "access": 2, "individu": 2, "similar": 2, "ram": 2, "start": [2, 3], "being": 2, "complet": [2, 3], "volatil": 2, "which": [2, 3], "mean": [2, 3], "after": [2, 3], "execut": [0, 2, 3], "reset": 2, "hold": 2, "8": 2, "number": [2, 3], "between": 2, "255": 2, "repres": 2, "index": 2, "offset": 2, "would": [2, 3], "get": 2, "store": [0, 2], "combin": [2, 3], "size": [0, 2], "block": [2, 3], "5": 2, "7": 2, "simplememori": 2, "load": 2, "expand": [0, 2], "consum": 2, "ga": [2, 3], "non": 2, "linearli": 2, "make": [2, 3], "more": 2, "costli": 2, "larger": 2, "space": 2, "let": 2, "expans": 2, "calcul": 2, "memory_expansion_cost": 2, "expansion_s": 2, "initi": 2, "zero": 2, "0x00": [2, 3], "_": 2, "rang": 2, "extend": 2, "need": [0, 2, 3], "simplifi": [2, 3], "super": 2, "some": [0, 2, 3], "0x01": [2, 3], "0x02": [2, 3], "0x03": [2, 3], "0x04": [2, 3], "alwai": 2, "thi": [2, 3], "actual": 2, "how": [2, 3], "cost": 2, "calc_memory_expansion_ga": 2, "memory_byte_s": 2, "memory_size_word": 2, "31": 2, "memory_cost": 2, "512": 2, "round": 2, "If": [0, 3], "build": 3, "scratch": 3, "do": [0, 3], "understand": 3, "have": 3, "ever": 3, "whether": 3, "develop": 3, "user": [0, 3], "chanc": 3, "came": 3, "across": 3, "central": 3, "part": 3, "s": 3, "engin": 3, "respons": 3, "program": [0, 3], "smart": 3, "contract": 3, "In": 3, "tutori": 3, "go": 3, "howev": 3, "refer": 3, "implement": 3, "i": 3, "omit": 3, "detail": 3, "believ": 3, "thei": 3, "necessari": 3, "about": 3, "learn": 3, "core": 3, "concept": [0, 3], "first": 3, "principl": 3, "That": [0, 3], "why": 3, "want": 3, "mini": 3, "version": 3, "real": 3, "thing": 3, "virtual": 3, "take": 3, "input": 3, "But": 3, "what": 3, "exactli": 3, "like": 3, "comput": [0, 3], "run": [0, 3], "your": [0, 3], "instead": 3, "separ": 3, "physic": 3, "all": 3, "done": 3, "softwar": 3, "just": 3, "its": 3, "own": 3, "languag": 3, "For": 3, "simpli": 3, "valid": 3, "opcod": 3, "oper": [0, 3], "subtract": 3, "stop": [0, 3], "them": 3, "seen": 3, "tabl": 3, "below": 3, "name": 3, "descript": 3, "halt": 3, "addit": 3, "mul": 3, "multipl": 3, "sub": 3, "div": 3, "integ": 3, "divis": 3, "importantli": 3, "doe": 3, "know": 3, "identifi": 3, "so": [0, 3], "look": 3, "604260005260206000f3": 3, "someth": 3, "could": [0, 3], "interpret": 3, "current": 3, "144": 3, "see": 3, "here": 3, "chang": 3, "time": 3, "fix": 3, "ad": 3, "old": 3, "ones": 3, "deprec": 3, "quit": 3, "frequent": 3, "As": 3, "realli": 3, "don": 3, "write": 3, "slow": 3, "error": 3, "prone": 3, "where": 3, "high": 3, "level": 3, "solidii": 3, "come": 3, "file": 3, "text": 3, "translat": 3, "compil": 3, "said": 3, "target": 3, "special": 3, "compar": 3, "other": 3, "blockchain": 3, "befor": 3, "becaus": [0, 3], "univers": 3, "ture": 3, "ani": 3, "arbitrari": 3, "ignor": 3, "memori": [0, 3], "restrict": 3, "capabl": 3, "script": 3, "NOT": 3, "There": 3, "case": 3, "our": 3, "bottom": 3, "up": 3, "stack": 3, "Then": 3, "move": 3, "storag": [0, 3], "built": 3, "end": 3, "us": 3, "import": [0, 3], "live": 3, "total": 3, "isol": 3, "clue": 3, "account": 3, "function": 3, "outsid": 3, "world": 3, "mock": 3, "deliber": 3, "choic": 3, "keep": 3, "python": 3, "hexadecim": 3, "notebook": 3, "avail": 3, "mistak": 3, "pleas": 3, "issu": 3, "github": 3, "even": 3, "better": 3, "pull": 3, "request": 3, "measur": 0, "amount": 0, "arithmet": 0, "ressourc": 0, "limit": 0, "order": 0, "avoid": 0, "ddo": 0, "attack": 0, "exampl": 0, "spend": 0, "hi": 0, "paid": 0, "eth": 0, "out": 0, "while": 0, "bytecod": 0, "kei": [], "practic": [], "purpos": [], "infinit": [], "ssd": [], "sourc": [], "http": [], "doc": [], "alchemi": [], "com": [], "layout": [], "dictionari": [], "keyvalu": [], "differ": [], "slot": [], "wa": [], "otherwis": [], "than": [], "logic": [], "track": [], "cach": [], "when": [], "save": [], "true": [], "els": [], "fals": [], "420": [], "notic": [], "retriev": [], "read": [], "random": [], "set": [], "42069": [], "machin": [], "ethereum": [], "manipul": [], "specif": [], "point": [], "next": [], "And": [], "area": [], "dure": [], "immut": [], "much": [], "down": [], "ether": [], "wei": [], "Is": [], "two": [], "stop_flag": [], "revert_flag": [], "sever": [], "emit": [], "result": [], "insturct": [], "categori": [], "deal": [], "follow": [], "common": [], "instanc": [], "paramet": [], "uniqu": [], "convini": [], "denot": [], "To": [], "easier": [], "give": [], "short": [], "found": [], "0x0": [], "0x1": [], "0x2": [], "0x3": [], "0x4": [], "sdiv": [], "0x5": [], "mod": [], "0x6": [], "smod": [], "0x7": [], "addmod": [], "0x8": [], "mulmod": [], "0x9": [], "exp": [], "0xa": [], "signextend": [], "0xb": [], "lt": [], "0x10": [], "gt": [], "0x11": [], "slt": [], "0x12": [], "sgt": [], "0x13": [], "eq": [], "0x14": [], "iszero": [], "0x15": [], "AND": [], "0x16": [], "OR": [], "0x17": [], "xor": [], "0x18": [], "0x19": [], "0x1a": [], "shl": [], "0x1b": [], "shr": [], "0x1c": [], "sar": [], "0x1d": [], "sha3": [], "0x20": [], "address": [], "0x30": [], "balanc": [], "0x31": [], "origin": [], "0x32": [], "caller": [], "0x33": [], "callvalu": [], "0x34": [], "calldataload": [], "0x35": [], "calldatas": [], "0x36": [], "calldatacopi": [], "0x37": [], "codes": [], "0x38": [], "codecopi": [], "0x39": [], "gaspric": [], "0x3a": [], "extcodes": [], "0x3b": [], "extcodecopi": [], "0x3c": [], "returndatas": [], "0x3d": [], "returndatacopi": [], "0x3e": [], "extcodehash": [], "0x3f": [], "blockhash": [], "0x40": [], "coinbas": [], "0x41": [], "timestamp": [], "0x42": [], "0x43": [], "difficulti": [], "0x44": [], "gaslimit": [], "0x45": [], "chainid": [], "0x46": [], "selfbal": [], "0x47": [], "basefe": [], "0x48": [], "0x50": [], "mload": [], "0x51": [], "mstore": [], "0x52": [], "mstore8": [], "0x53": [], "sload": [], "0x54": [], "sstore": [], "0x55": [], "0x56": [], "jumpi": [], "0x57": [], "pc": [], "0x58": [], "jumpdest": [], "0x5b": [], "push1": [], "0x60": [], "push2": [], "0x61": [], "push3": [], "0x62": [], "push4": [], "0x63": [], "push5": [], "0x64": [], "push6": [], "0x65": [], "push7": [], "0x66": [], "push8": [], "0x67": [], "push9": [], "0x68": [], "push10": [], "0x69": [], "push11": [], "0x6a": [], "push12": [], "0x6b": [], "push13": [], "0x6c": [], "push14": [], "0x6d": [], "push15": [], "0x6e": [], "push16": [], "0x6f": [], "push17": [], "0x70": [], "push18": [], "0x71": [], "push19": [], "0x72": [], "push20": [], "0x73": [], "push21": [], "0x74": [], "push22": [], "0x75": [], "push23": [], "0x76": [], "push24": [], "0x77": [], "push25": [], "0x78": [], "push26": [], "0x79": [], "push27": [], "0x7a": [], "push28": [], "0x7b": [], "push29": [], "0x7c": [], "push30": [], "0x7d": [], "push31": [], "0x7e": [], "push32": [], "0x7f": [], "dup1": [], "0x80": [], "dup2": [], "0x81": [], "dup3": [], "0x82": [], "dup4": [], "0x83": [], "dup5": [], "0x84": [], "dup6": [], "0x85": [], "dup7": [], "0x86": [], "dup8": [], "0x87": [], "dup9": [], "0x88": [], "dup10": [], "0x89": [], "dup11": [], "0x8a": [], "dup12": [], "0x8b": [], "dup13": [], "0x8c": [], "dup14": [], "0x8d": [], "dup15": [], "0x8e": [], "dup16": [], "0x8f": [], "swap1": [], "0x90": [], "swap2": [], "0x91": [], "swap3": [], "0x92": [], "swap4": [], "0x93": [], "swap5": [], "0x94": [], "swap6": [], "0x95": [], "swap7": [], "0x96": [], "swap8": [], "0x97": [], "swap9": [], "0x98": [], "swap10": [], "0x99": [], "swap11": [], "0x9a": [], "swap12": [], "0x9b": [], "swap13": [], "0x9c": [], "swap14": [], "0x9d": [], "swap15": [], "0x9e": [], "swap16": [], "0x9f": [], "log0": [], "0xa0": [], "log1": [], "0xa1": [], "log2": [], "0xa2": [], "log3": [], "0xa3": [], "log4": [], "0xa4": [], "0xf0": [], "0xf1": [], "callcod": [], "0xf2": [], "legaci": [], "support": [], "delegatecal": [], "0xf3": [], "0xf4": [], "create2": [], "0xf5": [], "staticcal": [], "0xfa": [], "revert": [], "0xfd": [], "invalid": [], "0xfe": [], "selfdestruct": [], "0xff": [], "These": [], "back": [], "increment": [], "counter": [], "deduct": [], "b": [], "gas_dec": [], "One": [], "interest": [], "note": [], "handl": [], "system": [], "divid": [], "Not": [], "mostli": [], "featur": [], "solid": [], "absolut": [], "both": [], "denomin": [], "numer": [], "small": [], "littl": [], "helper": [], "determin": [], "sign": [], "pos_or_neg": [], "lambda": [], "ab": [], "dynam": [], "mani": [], "expon": [], "binari": [], "size_in_byt": [], "bits_need": [], "ceil": [], "10": [], "50": [], "inform": [], "rare": [], "x": [], "testbit": [], "sign_bit": [], "captur": [], "util": [], "ipynb": [], "oserror": [], "librari": [], "lib": [], "site": [], "packag": [], "ipython": [], "magic": [], "parameter_": [], "runner": [], "file_find": [], "713": [], "fpath": [], "arg_lst": [], "714": [], "filenam": [], "715": [], "indexerror": [], "path": [], "get_py_filenam": [], "force_win32": [], "108": [], "109": [], "ioerror": [], "r": [], "110": [], "abov": [], "anoth": [], "occur": [], "ipykernel_18822": [], "3891275799": [], "get_ipython": [], "run_line_mag": [], "interactiveshel": [], "magic_nam": [], "_stack_depth": [], "2416": [], "kwarg": [], "local_n": [], "get_local_scop": [], "stack_depth": [], "2417": [], "builtin_trap": [], "2418": [], "fn": [], "arg": [], "2419": [], "2420": [], "decor": [], "fun": [], "kw": [], "230": [], "kwsyntax": [], "231": [], "sig": [], "232": [], "func": [], "extra": [], "233": [], "__name__": [], "234": [], "__doc__": [], "f": [], "k": [], "185": [], "overkil": [], "state": [], "186": [], "magic_deco": [], "187": [], "188": [], "189": [], "callabl": [], "723": [], "os": [], "nt": [], "re": [], "match": [], "724": [], "warn": [], "window": [], "doubl": [], "quot": [], "wrap": [], "mypath": [], "myfil": [], "725": [], "msg": [], "726": [], "727": [], "sy": [], "meta_path": [], "rather": [], "unsigned_to_sign": [], "cpu": [], "familiar": [], "_and": [], "_or": [], "_xor": [], "_not": [], "ipykernel_18832": [], "again": [], "word": [], "pow": [], "bin": [], "22": [], "0b10110": [], "0b1011000": [], "0b101": [], "1010": [], "becom": [], "101000": [], "uint_255_negative_on": [], "uint_256_max": [], "hard": [], "classifi": [], "9": [], "ineffici": [], "decid": [], "includ": [], "itself": [], "easili": [], "been": [], "weather": [], "should": [], "precomipl": [], "matter": [], "debat": [], "commun": [], "cryptograph": [], "primit": [], "characterist": [], "messag": [], "determinist": [], "produc": [], "output": [], "infeas": [], "invert": [], "chaotic": [], "whole": [], "toatlli": [], "extern": [], "keccak": [], "minimum_word_s": [], "dynamic_ga": [], "6": [], "todo": [], "30": [], "0x414b60745072088d013721b4a28a0559b1a9d213": [], "99999999999": [], "2600": [], "100": [], "warm": [], "delta": [], "calldata": [], "until": [], "destoffset": [], "static_ga": [], "extcod": [], "refactor": [], "seper": [], "method": [], "address_access_cost": [], "returndata": [], "blocknumb": [], "0x1cbcfa1ffb1ca1ca8397d4f490194db5fc0543089b9dee43f76cf3f962a185e8": [], "20": [], "_pop": [], "three": [], "specifi": [], "allow": [], "right": [], "align": [], "2100": [], "old_valu": [], "base_dynamic_ga": [], "test": [], "20000": [], "2900": [], "access_cost": [], "refund": [], "05_opcod": [], "jump": [], "sure": [], "_push": [], "peek": [], "int": [], "_dup": [], "big": [], "enough": [], "_swap": [], "value1": [], "value2": [], "log": [], "topic1": [], "none": [], "topic2": [], "topic3": [], "topic4": [], "calc_ga": [], "topic_count": [], "375": [], "append_log": [], "memeori": [], "topic": [], "02_stack": [], "03_memori": [], "04_storag": [], "06_stop": [], "07_math": [], "book": [], "ipykernel_18893": [], "35317130": [], "733": [], "preserve_kei": [], "shell": [], "user_n": [], "__file__": [], "734": [], "735": [], "safe_execfile_ipi": [], "raise_except": [], "736": [], "737": [], "fname": [], "shell_futur": [], "2903": [], "run_cel": [], "silent": [], "2904": [], "2905": [], "raise_error": [], "2906": [], "elif": [], "success": [], "2907": [], "break": [], "347": [], "error_before_exec": [], "348": [], "error_in_exec": [], "349": [], "350": [], "351": [], "__repr__": [], "skip": [], "hidden": [], "frame": [], "put": [], "everyth": [], "togeth": [], "tell": [], "should_execute_next_opcod": [], "op": [], "talk": [], "operand": [], "simple_push": [], "0x6042": [], "consist": [], "writer": [], "mix": [], "von": [], "neumann": [], "architectur": [], "onto": [], "simple_add": [], "element": [], "321": [], "step": [], "ipykernel_18903": [], "1196339088": [], "21_000": [], "nameerror": [], "1728536637": [], "defin": [], "consid": [], "under": [], "over": [], "flow": [], "protect": [], "cold": [], "proof": [], "stake": [], "static": [], "deleg": [], "implemen": [], "highli": [], "recommend": [], "code": [], "best": [], "ipykernel_5617": 1}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"stack": 1, "memori": 2, "advanc": 2, "introduct": 3, "evm": 3, "virut": 3, "machin": 3, "bytecod": 3, "solid": 3, "vyper": 3, "huff": 3, "ethereum": 3, "vs": 3, "bitcoin": 3, "outlin": 3, "prerequisit": 3, "note": 3, "ga": 0, "storag": [], "warm": [], "cold": [], "state": [], "program": [], "counter": [], "pc": [], "valu": [], "calldata": [], "flag": [], "returndata": [], "log": [], "opcod": [], "implement": [], "list": [], "math": [], "comparison": [], "logic": [], "bit": [], "op": [], "misc": [], "pop": [], "jump": [], "push": [], "dup": [], "swap": [], "contract": [], "stop": [], "less": [], "than": [], "sign": [], "greater": [], "equal": [], "Is": [], "zero": [], "And": [], "Or": [], "xor": [], "Not": [], "byte": [], "shift": [], "left": [], "right": [], "precompil": [], "hash": [], "function": [], "environ": [], "address": [], "balanc": [], "origin": [], "caller": [], "callvalu": [], "calldataload": [], "calldatas": [], "calldatacopi": [], "codes": [], "codecopi": [], "price": [], "extern": [], "code": [], "size": [], "copi": [], "return": [], "data": [], "block": [], "coinbas": [], "simpl": [], "instruct": [], "add": [], "resourc": []}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 6, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.intersphinx": 1, "sphinxcontrib.bibtex": 9, "sphinx": 56}}) \ No newline at end of file +Search.setIndex({"docnames": ["02_a_gas", "02_stack", "03_memory", "04_storage", "05_1_state", "05_opcodes", "06_stop", "07_math", "08_comparisions", "09_logic", "10_bit", "11_misc", "12_environment", "13_pop", "14_memory", "15_storage", "16_jump", "17_push", "18_dup", "19_swap", "20_log", "21_contract", "24_evm", "25_bytecode", "26_run", "99_conclusion", "intro"], "filenames": ["02_a_gas.ipynb", "02_stack.ipynb", "03_memory.ipynb", "04_storage.ipynb", "05_1_state.ipynb", "05_opcodes.ipynb", "06_stop.ipynb", "07_math.ipynb", "08_comparisions.ipynb", "09_logic.ipynb", "10_bit.ipynb", "11_misc.ipynb", "12_environment.ipynb", "13_pop.ipynb", "14_memory.ipynb", "15_storage.ipynb", "16_jump.ipynb", "17_push.ipynb", "18_dup.ipynb", "19_swap.ipynb", "20_log.ipynb", "21_contract.ipynb", "24_evm.ipynb", "25_bytecode.ipynb", "26_run.ipynb", "99_conclusion.ipynb", "intro.ipynb"], "titles": ["Gas", "Stack", "Memory", "Storage", "EVM State", "Opcodes", "Stop", "Math", "Comparisons", "Logic", "Bit", "Misc", "Environment", "<no title>", "<no title>", "<no title>", "<no title>", "<no title>", "<no title>", "<no title>", "<no title>", "<no title>", "EVM", "Bytecode", "<no title>", "Resources", "Introduction"], "terms": {"The": [1, 2, 3, 4, 7, 11, 22, 23, 26], "veri": [0, 1, 5, 6, 8, 9, 11, 26], "simpl": [1, 2, 6, 26], "data": [1, 4, 20], "structur": [1, 5], "It": [0, 1, 2, 3, 4, 7, 11, 22, 23, 26], "list": [1, 2, 23, 26], "one": [1, 4, 5, 7, 8, 10, 11, 14, 22, 23, 24], "restrction": 1, "you": [0, 1, 7, 9, 12, 23, 25, 26], "can": [1, 2, 3, 4, 5, 11, 12, 16, 23, 26], "onli": [1, 11, 12, 16, 26], "directli": [1, 7, 11, 26], "interact": [1, 26], "top": 1, "push": [1, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 22], "new": [1, 26], "valu": [0, 1, 2, 3, 7, 8, 10, 11, 12, 14, 15, 17, 18, 20, 22], "pop": [1, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 21, 22], "an": [0, 1, 2, 3, 4, 5, 7, 11, 14, 16, 26], "alreadi": [1, 4, 26], "exist": 1, "from": [1, 2, 3, 7, 10, 22, 26], "A": [1, 2, 3, 4, 5, 11, 14, 26], "plate": 1, "good": [1, 26], "metaphor": 1, "add": [1, 2, 5, 7, 22, 26], "remov": 1, "work": [0, 1, 7, 26], "exact": 1, "same": [1, 9, 10, 11], "wai": [1, 2, 11], "evm": [1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25], "ha": [0, 1, 5, 11, 12, 26], "maximum": 1, "capac": 1, "1024": 1, "item": 1, "everi": [1, 3, 5, 11, 26], "max": 1, "256": [1, 7, 10, 11, 12], "bit": [1, 2, 8, 11, 22, 24], "32": [1, 2, 3, 10, 11, 12, 14], "byte": [1, 2, 3, 5, 7, 12, 14], "maximum_stack_s": 1, "we": [0, 1, 2, 3, 4, 5, 7, 8, 11, 12, 16, 22, 23, 25, 26], "also": [1, 2, 7, 11, 26], "throw": [1, 3, 7], "except": [1, 3, 7, 8, 10, 12, 16, 22, 24], "try": [1, 7], "empti": [1, 2], "class": [1, 2, 3, 4, 20, 22], "def": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 24], "__init__": [1, 2, 3, 4, 20, 22], "self": [1, 2, 3, 4, 8, 10, 20, 22, 24], "__str__": [1, 20], "return": [1, 2, 3, 4, 5, 7, 8, 10, 20, 22, 24], "n": [1, 7, 13, 17, 18, 19, 22], "join": [1, 17], "map": [1, 3, 17], "str": [1, 11, 17], "1": [1, 2, 3, 5, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 24], "len": [1, 2, 12, 22], "rais": [1, 8, 10, 12, 16, 22, 24], "overflow": 1, "append": [1, 2, 3, 12, 17], "0": [1, 2, 3, 4, 7, 8, 10, 12, 15, 16, 19, 20, 21, 22, 24], "underflow": 1, "del": 1, "creat": [1, 2, 5, 11, 26], "3": [1, 2, 7, 8, 9, 10, 12, 17, 18, 19, 20, 22, 24], "2": [1, 2, 7, 10, 12, 13, 16, 20, 22, 24], "4": [1, 2, 20, 22], "print": [1, 22, 24], "typeerror": [1, 8, 10, 22, 24], "traceback": [1, 8, 10, 22, 24], "most": [1, 4, 5, 7, 8, 10, 11, 22, 24, 26], "recent": [1, 8, 10, 22, 24], "call": [1, 5, 8, 10, 11, 22, 23, 24, 25, 26], "last": [1, 8, 10, 12, 22, 24], "var": [1, 8, 10, 22, 24], "folder": [1, 8, 10, 22, 24], "08": [1, 8, 10, 22, 24], "q0syv9y576b_rnls32m9d3nr0000gn": [1, 8, 10, 22, 24], "t": [1, 8, 10, 22, 24, 26], "ipykernel_13808": [], "1192403925": [1, 22], "py": [1, 8, 10, 22, 24, 25], "cell": [1, 2, 8, 10, 22, 24], "line": [1, 8, 10, 22, 24], "miss": [1, 22], "requir": [1, 22], "posit": [1, 10, 22], "argument": [1, 22], "now": [1, 3, 9, 22, 23], "ar": [0, 1, 4, 5, 7, 9, 11, 14, 22, 23, 25, 26], "left": 1, "each": [2, 5], "access": [2, 3, 11, 12, 20, 21, 25], "individu": 2, "similar": [2, 8], "ram": 2, "start": [2, 26], "being": 2, "complet": [2, 26], "volatil": [2, 3], "which": [2, 4, 22, 26], "mean": [2, 26], "after": [2, 4, 23, 26], "execut": [0, 2, 4, 5, 6, 7, 8, 10, 11, 22, 23, 24, 26], "reset": [2, 22], "hold": 2, "8": [2, 7, 8, 10, 16, 20, 22, 24], "number": [2, 3, 5, 7, 26], "between": 2, "255": 2, "repres": [2, 3, 5, 7], "index": [2, 22], "offset": [2, 11, 12, 14, 20, 21], "would": [2, 7, 11, 23, 26], "get": [2, 10, 19], "store": [0, 2, 3, 4, 12, 14, 15], "combin": [2, 26], "size": [0, 2, 11, 20, 21], "block": [2, 26], "5": [2, 7, 22], "7": [2, 7], "simplememori": 2, "load": [2, 3, 14, 15], "expand": [0, 2], "consum": [2, 4, 7], "ga": [2, 3, 7, 11, 22, 24, 25, 26], "non": [2, 3], "linearli": 2, "make": [2, 4, 5, 16, 18, 23, 26], "more": [2, 3, 7, 23], "costli": 2, "larger": [2, 5], "space": 2, "let": [2, 7, 10, 14], "expans": [2, 20], "calcul": [2, 7, 11], "memory_expansion_cost": [2, 11, 12, 20], "expansion_s": 2, "initi": [2, 3], "zero": 2, "0x00": [2, 3, 12, 26], "_": [2, 17], "rang": [2, 17], "extend": 2, "need": [0, 2, 4, 7, 26], "simplifi": [2, 26], "super": [2, 3], "some": [0, 2, 5, 7, 26], "0x01": [2, 23, 26], "0x02": [2, 26], "0x03": [2, 26], "0x04": [2, 26], "alwai": [2, 12], "thi": [2, 3, 4, 5, 7, 9, 11, 12, 23, 26], "actual": [2, 7, 23], "how": [2, 3, 4, 7, 26], "cost": [2, 3, 7, 20], "calc_memory_expansion_ga": 2, "memory_byte_s": 2, "memory_size_word": 2, "31": [2, 7, 10, 11, 12], "memory_cost": 2, "512": 2, "round": 2, "If": [0, 3, 4, 25, 26], "build": 26, "scratch": [22, 26], "do": [0, 11, 15, 25, 26], "understand": [25, 26], "have": [4, 5, 11, 23, 26], "ever": 26, "whether": [3, 26], "develop": 26, "user": [0, 26], "chanc": 26, "came": 26, "across": 26, "central": 26, "part": [4, 26], "s": [8, 10, 22, 24, 26], "engin": 26, "respons": 26, "program": [0, 7, 11, 12, 16, 23, 26], "smart": [3, 26], "contract": [3, 26], "In": [5, 7, 23, 26], "tutori": 26, "go": [4, 7, 22, 26], "howev": 26, "refer": [25, 26], "implement": [3, 7, 11, 26], "i": [10, 12, 25, 26], "omit": 26, "detail": 26, "believ": 26, "thei": [5, 11, 25, 26], "necessari": 26, "about": [7, 23, 26], "learn": 26, "core": [8, 10, 22, 24, 26], "concept": [0, 9, 10, 26], "first": [3, 6, 7, 26], "principl": 26, "That": [0, 5, 26], "why": [5, 26], "want": 26, "mini": 26, "version": 26, "real": 26, "thing": [5, 25, 26], "virtual": 26, "take": [5, 24, 26], "input": [4, 11, 26], "But": [8, 26], "what": [10, 23, 25, 26], "exactli": [7, 23, 26], "like": [3, 5, 7, 10, 23, 25, 26], "comput": [0, 3, 26], "run": [0, 8, 10, 16, 22, 24, 26], "your": [0, 3, 26], "instead": 26, "separ": 26, "physic": 26, "all": [3, 4, 5, 6, 7, 26], "done": 26, "softwar": 26, "just": [7, 8, 10, 22, 24, 26], "its": [3, 11, 12, 26], "own": 26, "languag": [7, 26], "For": [8, 10, 24, 26], "simpli": [23, 26], "valid": [4, 23, 26], "opcod": [4, 6, 7, 8, 12, 14, 16, 22, 23, 25, 26], "oper": [0, 4, 5, 7, 9, 10, 11, 26], "subtract": [8, 26], "stop": [0, 4, 5, 22, 26], "them": [4, 5, 7, 8, 11, 23, 26], "seen": 26, "tabl": 26, "below": 26, "name": [5, 8, 10, 24, 26], "descript": [5, 26], "halt": [6, 26], "addit": 26, "mul": [5, 7, 26], "multipl": 26, "sub": [5, 7, 26], "div": [5, 7, 26], "integ": 26, "divis": [7, 26], "importantli": 26, "doe": [6, 26], "know": 26, "identifi": [5, 26], "so": [0, 11, 26], "look": [10, 23, 24, 25, 26], "604260005260206000f3": 26, "someth": [3, 26], "could": [0, 11, 23, 26], "interpret": 26, "current": [4, 5, 11, 26], "144": 26, "see": [7, 10, 23, 26], "here": [4, 5, 7, 23, 26], "chang": [4, 11, 26], "time": [3, 11, 26], "fix": [5, 8, 10, 11, 22, 24, 26], "ad": [8, 26], "old": 26, "ones": 26, "deprec": 26, "quit": 26, "frequent": 26, "As": [23, 26], "realli": 26, "don": 26, "write": 26, "slow": 26, "error": 26, "prone": 26, "where": [4, 26], "high": 26, "level": 26, "solidii": 26, "come": 26, "file": [8, 10, 24, 26], "text": 26, "translat": 26, "compil": 26, "said": [3, 26], "target": 26, "special": 26, "compar": [8, 26], "other": [5, 7, 26], "blockchain": 26, "befor": [3, 26], "becaus": [0, 5, 26], "univers": 26, "ture": 26, "ani": [3, 11, 26], "arbitrari": 26, "ignor": 26, "memori": [0, 11, 12, 14, 20, 21, 22, 26], "restrict": 26, "capabl": 26, "script": 26, "NOT": [5, 26], "There": [4, 5, 14, 26], "case": 26, "our": [4, 6, 26], "bottom": 26, "up": [3, 23, 24, 26], "stack": [5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26], "Then": 26, "move": 26, "storag": [0, 15, 22, 26], "built": [11, 23, 26], "end": [7, 26], "us": [5, 7, 8, 10, 11, 14, 23, 24, 26], "import": [0, 7, 11, 14, 26], "live": 26, "total": 26, "isol": 26, "clue": 26, "account": 26, "function": [5, 7, 26], "outsid": 26, "world": 26, "mock": 26, "deliber": 26, "choic": 26, "keep": [3, 4, 26], "python": [8, 10, 11, 22, 24, 26], "hexadecim": [5, 26], "notebook": [5, 26], "avail": 26, "mistak": 26, "pleas": 26, "issu": 26, "github": 26, "even": 26, "better": 26, "pull": 26, "request": 26, "measur": 0, "amount": [0, 3, 22], "arithmet": [0, 5, 7, 8], "ressourc": 0, "limit": 0, "order": 0, "avoid": 0, "ddo": 0, "attack": 0, "exampl": 0, "spend": 0, "hi": 0, "paid": 0, "eth": 0, "out": [0, 22], "while": [0, 22], "bytecod": [0, 4, 11, 22, 24], "kei": [3, 15], "practic": [3, 11], "purpos": 3, "infinit": 3, "ssd": 3, "sourc": [3, 11], "http": 3, "doc": 3, "alchemi": 3, "com": 3, "layout": 3, "dictionari": 3, "keyvalu": 3, "differ": [3, 5, 9], "slot": 3, "wa": [3, 11], "otherwis": 3, "than": [3, 5], "logic": 3, "track": [3, 4], "cach": 3, "when": [3, 4], "save": [3, 4, 14], "true": [3, 4, 6, 21, 22], "els": [3, 7, 8, 10, 12, 15, 16, 24], "fals": [3, 4, 22], "420": 3, "notic": 3, "retriev": 3, "read": 3, "random": [3, 11], "set": [3, 6, 19, 24], "42069": 3, "machin": 4, "ethereum": [4, 11, 12], "manipul": [4, 5, 7], "specif": 4, "point": 4, "next": [4, 22, 23], "And": 4, "area": 4, "dure": [4, 8, 10, 24], "immut": 4, "much": 4, "down": 4, "ether": 4, "wei": 4, "Is": 4, "two": [4, 14], "stop_flag": [4, 6, 21, 22], "revert_flag": [4, 21, 22], "sever": 4, "emit": 4, "result": [4, 7, 8, 10, 22, 23, 24], "insturct": 5, "categori": 5, "deal": 5, "follow": [5, 11], "common": 5, "instanc": 5, "paramet": 5, "uniqu": 5, "convini": 5, "denot": 5, "To": 5, "easier": 5, "give": [5, 12], "short": 5, "found": [5, 8, 10, 24], "0x0": 5, "0x1": 5, "0x2": 5, "0x3": 5, "0x4": 5, "sdiv": [5, 7], "0x5": 5, "mod": [5, 7], "0x6": 5, "smod": [5, 7], "0x7": 5, "addmod": [5, 7], "0x8": 5, "mulmod": [5, 7], "0x9": 5, "exp": [5, 7], "0xa": 5, "signextend": [5, 7], "0xb": 5, "lt": [5, 8], "0x10": 5, "gt": [5, 8], "0x11": 5, "slt": [5, 8], "0x12": 5, "sgt": [5, 8], "0x13": 5, "eq": [5, 8], "0x14": 5, "iszero": [5, 8], "0x15": 5, "AND": 5, "0x16": 5, "OR": 5, "0x17": 5, "xor": 5, "0x18": 5, "0x19": 5, "0x1a": 5, "shl": [5, 10], "0x1b": 5, "shr": [5, 10], "0x1c": 5, "sar": [5, 10], "0x1d": 5, "sha3": [5, 11], "0x20": 5, "address": 5, "0x30": 5, "balanc": 5, "0x31": 5, "origin": 5, "0x32": 5, "caller": [5, 8, 10, 22, 24], "0x33": 5, "callvalu": 5, "0x34": 5, "calldataload": 5, "0x35": 5, "calldatas": 5, "0x36": 5, "calldatacopi": 5, "0x37": 5, "codes": 5, "0x38": 5, "codecopi": 5, "0x39": 5, "gaspric": [5, 12], "0x3a": 5, "extcodes": [5, 12, 25], "0x3b": 5, "extcodecopi": [5, 12], "0x3c": 5, "returndatas": [5, 12], "0x3d": 5, "returndatacopi": [5, 12], "0x3e": 5, "extcodehash": [5, 12], "0x3f": 5, "blockhash": [5, 12], "0x40": 5, "coinbas": 5, "0x41": 5, "timestamp": 5, "0x42": [5, 23], "0x43": 5, "difficulti": 5, "0x44": 5, "gaslimit": 5, "0x45": 5, "chainid": 5, "0x46": 5, "selfbal": 5, "0x47": 5, "basefe": 5, "0x48": 5, "0x50": 5, "mload": [5, 14], "0x51": 5, "mstore": [5, 14], "0x52": 5, "mstore8": [5, 14], "0x53": 5, "sload": [5, 15], "0x54": 5, "sstore": [5, 15], "0x55": 5, "0x56": 5, "jumpi": [5, 16], "0x57": 5, "pc": [5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22], "0x58": 5, "jumpdest": [5, 16], "0x5b": 5, "push1": [5, 22], "0x60": [5, 23], "push2": 5, "0x61": 5, "push3": 5, "0x62": 5, "push4": 5, "0x63": 5, "push5": 5, "0x64": 5, "push6": 5, "0x65": 5, "push7": 5, "0x66": 5, "push8": 5, "0x67": 5, "push9": 5, "0x68": 5, "push10": 5, "0x69": 5, "push11": 5, "0x6a": 5, "push12": 5, "0x6b": 5, "push13": 5, "0x6c": 5, "push14": 5, "0x6d": 5, "push15": 5, "0x6e": 5, "push16": 5, "0x6f": 5, "push17": 5, "0x70": 5, "push18": 5, "0x71": 5, "push19": 5, "0x72": 5, "push20": 5, "0x73": 5, "push21": 5, "0x74": 5, "push22": 5, "0x75": 5, "push23": 5, "0x76": 5, "push24": 5, "0x77": 5, "push25": 5, "0x78": 5, "push26": 5, "0x79": 5, "push27": 5, "0x7a": 5, "push28": 5, "0x7b": 5, "push29": 5, "0x7c": 5, "push30": 5, "0x7d": 5, "push31": 5, "0x7e": 5, "push32": 5, "0x7f": 5, "dup1": 5, "0x80": 5, "dup2": 5, "0x81": 5, "dup3": 5, "0x82": 5, "dup4": 5, "0x83": 5, "dup5": 5, "0x84": 5, "dup6": 5, "0x85": 5, "dup7": 5, "0x86": 5, "dup8": 5, "0x87": 5, "dup9": 5, "0x88": 5, "dup10": 5, "0x89": 5, "dup11": 5, "0x8a": 5, "dup12": 5, "0x8b": 5, "dup13": 5, "0x8c": 5, "dup14": 5, "0x8d": 5, "dup15": 5, "0x8e": 5, "dup16": 5, "0x8f": 5, "swap1": 5, "0x90": 5, "swap2": 5, "0x91": 5, "swap3": 5, "0x92": 5, "swap4": 5, "0x93": 5, "swap5": 5, "0x94": 5, "swap6": 5, "0x95": 5, "swap7": 5, "0x96": 5, "swap8": 5, "0x97": 5, "swap9": 5, "0x98": 5, "swap10": 5, "0x99": 5, "swap11": 5, "0x9a": 5, "swap12": 5, "0x9b": 5, "swap13": 5, "0x9c": 5, "swap14": 5, "0x9d": 5, "swap15": 5, "0x9e": 5, "swap16": 5, "0x9f": 5, "log0": [5, 20], "0xa0": 5, "log1": [5, 20], "0xa1": 5, "log2": [5, 7, 20], "0xa2": 5, "log3": [5, 20], "0xa3": 5, "log4": [5, 20], "0xa4": 5, "0xf0": 5, "0xf1": 5, "callcod": 5, "0xf2": 5, "legaci": 5, "support": 5, "delegatecal": 5, "0xf3": 5, "0xf4": 5, "create2": 5, "0xf5": 5, "staticcal": 5, "0xfa": 5, "revert": [5, 21], "0xfd": 5, "invalid": 5, "0xfe": 5, "selfdestruct": 5, "0xff": [5, 23], "These": [7, 12], "back": [7, 23], "increment": 7, "counter": [7, 16], "deduct": 7, "b": [7, 8, 9, 16], "gas_dec": [7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22], "One": [7, 14], "interest": 7, "note": [7, 11], "handl": [7, 8, 10, 24], "system": 7, "divid": 7, "Not": 7, "mostli": 7, "featur": 7, "solid": 7, "absolut": 7, "both": [7, 23], "denomin": 7, "numer": 7, "small": 7, "littl": [7, 23], "helper": 7, "determin": 7, "sign": 7, "pos_or_neg": 7, "lambda": [7, 8, 10, 22, 24], "ab": 7, "dynam": 7, "mani": 7, "expon": 7, "binari": [7, 10], "size_in_byt": 7, "bits_need": 7, "ceil": 7, "10": [7, 10, 16], "50": 7, "inform": 7, "rare": 7, "x": [7, 10], "testbit": 7, "sign_bit": 7, "captur": [8, 10, 16, 22, 24], "util": [8, 10, 24], "ipynb": [8, 10, 16, 22, 24], "oserror": [8, 10, 24], "librari": [8, 10, 11, 22, 24], "lib": [8, 10, 22, 24], "site": [8, 10, 22, 24], "packag": [8, 10, 22, 24], "ipython": [8, 10, 22, 24], "magic": [8, 10, 22, 24], "parameter_": [8, 10, 22, 24], "runner": [8, 10, 22, 24], "file_find": [8, 10, 22, 24], "713": [8, 10, 24], "fpath": [8, 10, 24], "arg_lst": [8, 10, 24], "714": [8, 10, 24], "filenam": [8, 10, 22, 24], "715": [8, 10, 24], "indexerror": [8, 10, 24], "path": [8, 10, 24], "get_py_filenam": [8, 10, 24], "force_win32": [8, 10, 24], "108": [8, 10, 24], "109": [8, 10, 24], "ioerror": [8, 10, 24], "r": [8, 10, 24], "110": [8, 10, 24], "abov": [8, 10, 24], "anoth": [8, 10, 23, 24], "occur": [8, 10, 24], "ipykernel_18822": [], "3891275799": [8, 10], "get_ipython": [8, 10, 22, 24], "run_line_mag": [8, 10, 22, 24], "interactiveshel": [8, 10, 22, 24], "magic_nam": [8, 10, 22, 24], "_stack_depth": [8, 10, 22, 24], "2416": [8, 10, 22, 24], "kwarg": [8, 10, 22, 24], "local_n": [8, 10, 22, 24], "get_local_scop": [8, 10, 22, 24], "stack_depth": [8, 10, 22, 24], "2417": [8, 10, 22, 24], "builtin_trap": [8, 10, 22, 24], "2418": [8, 10, 22, 24], "fn": [8, 10, 22, 24], "arg": [8, 10, 22, 24], "2419": [8, 10, 22, 24], "2420": [8, 10, 22, 24], "decor": [8, 10, 22, 24], "fun": [8, 10, 22, 24], "kw": [8, 10, 22, 24], "230": [8, 10, 22, 24], "kwsyntax": [8, 10, 22, 24], "231": [8, 10, 22, 24], "sig": [8, 10, 22, 24], "232": [8, 10, 22, 24], "func": [8, 10, 22, 24], "extra": [8, 10, 22, 24], "233": [8, 10, 22, 24], "__name__": [8, 10, 22, 24], "234": [8, 10, 22, 24], "__doc__": [8, 10, 22, 24], "f": [8, 10, 20, 22, 24], "k": [8, 10, 22, 24], "185": [8, 10, 22, 24], "overkil": [8, 10, 22, 24], "state": [8, 10, 22, 24, 25], "186": [8, 10, 22, 24], "magic_deco": [8, 10, 22, 24], "187": [8, 10, 22, 24], "188": [8, 10, 22, 24], "189": [8, 10, 22, 24], "callabl": [8, 10, 22, 24], "723": [8, 10, 24], "os": [8, 10, 24], "nt": [8, 10, 24], "re": [8, 10, 24], "match": [8, 10, 24], "724": [8, 10, 24], "warn": [8, 10, 24], "window": [8, 10, 24], "doubl": [8, 10, 24], "quot": [8, 10, 24], "wrap": [8, 10, 24], "mypath": [8, 10, 24], "myfil": [8, 10, 24], "725": [8, 10, 24], "msg": [8, 10, 24], "726": [8, 10, 24], "727": [8, 10, 24], "sy": [8, 10, 24], "meta_path": [8, 10, 24], "rather": 8, "unsigned_to_sign": 8, "cpu": [8, 10, 12, 14, 16, 20], "familiar": 9, "_and": 9, "_or": 9, "_xor": 9, "_not": 9, "ipykernel_18832": [], "again": 10, "word": [10, 14], "pow": 10, "bin": 10, "22": 10, "0b10110": 10, "0b1011000": 10, "0b101": 10, "1010": 10, "becom": 10, "101000": 10, "uint_255_negative_on": 10, "uint_256_max": 10, "hard": 11, "classifi": 11, "9": 11, "ineffici": 11, "decid": 11, "includ": 11, "itself": 11, "easili": 11, "been": 11, "weather": 11, "should": [11, 14, 23], "precomipl": 11, "matter": 11, "debat": 11, "commun": 11, "cryptograph": 11, "primit": 11, "characterist": 11, "messag": 11, "determinist": 11, "produc": 11, "output": 11, "infeas": 11, "invert": 11, "chaotic": 11, "whole": 11, "toatlli": 11, "extern": 11, "keccak": 11, "minimum_word_s": [11, 12], "dynamic_ga": [11, 12], "6": 11, "todo": [11, 14, 15, 20], "30": 11, "0x414b60745072088d013721b4a28a0559b1a9d213": 12, "99999999999": 12, "2600": 12, "100": [12, 15], "warm": [12, 15, 25], "delta": 12, "calldata": [12, 22], "until": 12, "destoffset": 12, "static_ga": [12, 20], "extcod": 12, "refactor": 12, "seper": 12, "method": 12, "address_access_cost": 12, "returndata": [12, 21, 22], "blocknumb": 12, "0x1cbcfa1ffb1ca1ca8397d4f490194db5fc0543089b9dee43f76cf3f962a185e8": 12, "20": 12, "_pop": 13, "three": 14, "specifi": 14, "allow": 14, "right": 14, "align": 14, "2100": 15, "old_valu": 15, "base_dynamic_ga": 15, "test": 15, "20000": 15, "2900": 15, "access_cost": 15, "refund": [15, 25], "05_opcod": [16, 22], "jump": 16, "sure": [16, 18, 23], "_push": [17, 22], "peek": [17, 22], "int": 17, "_dup": 18, "big": 18, "enough": 18, "_swap": 19, "value1": 19, "value2": 19, "log": [20, 22], "topic1": 20, "none": [20, 22], "topic2": 20, "topic3": 20, "topic4": 20, "calc_ga": 20, "topic_count": 20, "375": 20, "append_log": 20, "memeori": 20, "topic": 20, "02_stack": 22, "03_memori": 22, "04_storag": 22, "06_stop": 22, "07_math": 22, "book": 22, "ipykernel_18893": [], "35317130": 22, "733": 22, "preserve_kei": 22, "shell": 22, "user_n": 22, "__file__": 22, "734": 22, "735": 22, "safe_execfile_ipi": 22, "raise_except": 22, "736": 22, "737": 22, "fname": 22, "shell_futur": 22, "2903": 22, "run_cel": 22, "silent": 22, "2904": 22, "2905": 22, "raise_error": 22, "2906": 22, "elif": 22, "success": 22, "2907": 22, "break": 22, "347": 22, "error_before_exec": 22, "348": 22, "error_in_exec": 22, "349": 22, "350": 22, "351": 22, "__repr__": 22, "skip": 22, "hidden": 22, "frame": 22, "put": [22, 23], "everyth": 22, "togeth": [22, 23], "tell": 22, "should_execute_next_opcod": 22, "op": 22, "talk": 23, "operand": 23, "simple_push": 23, "0x6042": 23, "consist": 23, "writer": 23, "mix": 23, "von": 23, "neumann": 23, "architectur": 23, "onto": 23, "simple_add": [23, 24], "element": 23, "321": [23, 24], "step": 23, "ipykernel_18903": [], "1196339088": 24, "21_000": 24, "nameerror": 24, "1728536637": 24, "defin": 24, "consid": 25, "under": 25, "over": 25, "flow": 25, "protect": 25, "cold": 25, "proof": 25, "stake": 25, "static": 25, "deleg": 25, "implemen": 25, "highli": 25, "recommend": 25, "code": 25, "best": 25, "ipykernel_5617": 1, "ipykernel_5748": 8, "ipykernel_5758": 10, "ipykernel_5819": 22, "ipykernel_5829": 24}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"stack": [1, 4], "memori": [2, 4, 5], "advanc": 2, "introduct": 26, "evm": [4, 22, 26], "virut": 26, "machin": 26, "bytecod": [23, 26], "solid": 26, "vyper": 26, "huff": 26, "ethereum": [5, 26], "vs": [11, 26], "bitcoin": 26, "outlin": 26, "prerequisit": 26, "note": 26, "ga": [0, 4, 12], "storag": [3, 4, 5], "warm": 3, "cold": 3, "state": [4, 5], "program": [4, 22], "counter": [4, 22], "pc": 4, "valu": 4, "calldata": 4, "flag": 4, "returndata": 4, "log": [4, 5], "opcod": [5, 11], "implement": 5, "list": 5, "math": [5, 7], "comparison": [5, 8], "logic": [5, 9], "bit": [5, 10], "op": 5, "misc": [5, 11], "pop": 5, "jump": 5, "push": [5, 23], "dup": 5, "swap": 5, "contract": 5, "stop": 6, "less": 8, "than": 8, "sign": [8, 10], "greater": 8, "equal": 8, "Is": 8, "zero": 8, "And": 9, "Or": 9, "xor": 9, "Not": 9, "byte": 10, "shift": 10, "left": 10, "right": 10, "precompil": 11, "hash": [11, 12], "function": 11, "environ": 12, "address": 12, "balanc": 12, "origin": 12, "caller": 12, "callvalu": 12, "calldataload": 12, "calldatas": 12, "calldatacopi": 12, "codes": 12, "codecopi": 12, "price": 12, "extern": 12, "code": 12, "size": 12, "copi": 12, "return": 12, "data": [12, 23], "block": 12, "coinbas": 12, "simpl": 23, "instruct": 23, "add": 23, "resourc": 25}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 6, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.intersphinx": 1, "sphinxcontrib.bibtex": 9, "sphinx": 56}}) \ No newline at end of file diff --git a/_toc.yml b/_toc.yml index 1e98a33..ad69717 100644 --- a/_toc.yml +++ b/_toc.yml @@ -8,3 +8,4 @@ chapters: - file: 02_a_gas.ipynb - file: 02_stack.ipynb - file: 03_memory.ipynb +- file: 04_storage.ipynb