diff --git a/.DS_Store b/.DS_Store index b0b95da..c0ea106 100644 Binary files a/.DS_Store and b/.DS_Store differ 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 d6ce590..2f2a801 100644 Binary files a/_build/.doctrees/environment.pickle and b/_build/.doctrees/environment.pickle differ 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