EVM

Contents

%run utils.ipynb

notebooks = [
    "03_stack.ipynb",
    "04_memory.ipynb",
    "05_storage.ipynb",
    "07_opcodes.ipynb",
    "07a_opcodes/01_stop.ipynb",
    "07a_opcodes/02_math.ipynb",
    "07a_opcodes/03_comparisions.ipynb", 
    "07a_opcodes/04_logic.ipynb",
    "07a_opcodes/05_bit.ipynb",
    "07a_opcodes/06_misc.ipynb",
    "07a_opcodes/07_environment.ipynb",
    "07a_opcodes/08_pop.ipynb",
    "07a_opcodes/09_memory.ipynb",
    "07a_opcodes/10_storage.ipynb",
    "07a_opcodes/11_jump.ipynb",
    "07a_opcodes/12_push.ipynb",
    "07a_opcodes/13_dup.ipynb",
    "07a_opcodes/14_swap.ipynb",
    "07a_opcodes/15_log.ipynb",
    "07a_opcodes/16_contract.ipynb",
    "07a_opcodes/17_transient.ipynb",
]

import_notebooks(notebooks)

EVM#

Now we are going to put everything together.

Program Counter#

The program counter indexes into the bytecode. It tells the EVM which opcode to execute next

class EVM:
    def __init__(self,
                 program,
                 gas,
                 value,
                 calldata=[]):
        self.pc      = 0
        self.stack   = Stack()
        self.memory  = Memory()
        self.storage = Storage()
        
        self.program  = program
        self.gas      = gas
        self.value    = value
        self.calldata = calldata
        
        self.stop_flag   = False
        self.revert_flag = False
        
        self.returndata = []
        self.logs       = []
        
    def peek(self): return self.program[self.pc]
    
    def gas_dec(self, amount):
        if self.gas - amount < 0: 
            raise Exception("out of gas")
        self.gas -= amount

    
    def should_execute_next_opcode(self):
        if self.pc > len(self.program)-1: return False
        if self.stop_flag               : return False
        if self.revert_flag             : return False
        
        return True
    
    def run(self):
        while self.should_execute_next_opcode():
            op = self.program[self.pc]
            
            # Stop & Control Flow
            if op == STOP: stop(self)
            
            # Math Operations
            elif op == ADD:        add(self)
            elif op == MUL:        mul(self)
            elif op == SUB:        sub(self)
            elif op == DIV:        div(self)
            elif op == SDIV:       sdiv(self)
            elif op == MOD:        mod(self)
            elif op == SMOD:       smod(self)
            elif op == ADDMOD:     addmod(self)
            elif op == MULMOD:     mulmod(self)
            elif op == EXP:        exp(self)
            elif op == SIGNEXTEND: signextend(self)
            
            # Comparison Operations
            elif op == LT:     lt(self)
            elif op == GT:     gt(self)
            elif op == SLT:    slt(self)
            elif op == SGT:    sgt(self)
            elif op == EQ:     eq(self)
            elif op == ISZERO: iszero(self)
            
            # Logic Operations
            elif op == AND: _and(self)
            elif op == OR:  _or(self)
            elif op == XOR: _xor(self)
            elif op == NOT: _not(self)
            
            # Bit Operations
            elif op == BYTE: byte(self)
            elif op == SHL:  shl(self)
            elif op == SHR:  shr(self)
            elif op == SAR:  sar(self)
            
            # SHA3
            elif op == SHA3: sha3(self)
            
            # Environment Information
            elif op == ADDRESS:        address(self)
            elif op == BALANCE:        balance(self)
            elif op == ORIGIN:         origin(self)
            elif op == CALLER:         caller(self)
            elif op == CALLVALUE:      callvalue(self)
            elif op == CALLDATALOAD:   calldataload(self)
            elif op == CALLDATASIZE:   calldatasize(self)
            elif op == CALLDATACOPY:   calldatacopy(self)
            elif op == CODESIZE:       codesize(self)
            elif op == CODECOPY:       codecopy(self)
            elif op == GASPRICE:       gasprice(self)
            elif op == EXTCODESIZE:    extcodesize(self)
            elif op == EXTCODECOPY:    extcodecopy(self)
            elif op == RETURNDATASIZE: returndatasize(self)
            elif op == RETURNDATACOPY: returndatacopy(self)
            elif op == EXTCODEHASH:    extcodehash(self)
            elif op == BLOCKHASH:      blockhash(self)
            elif op == COINBASE:       coinbase(self)
            elif op == TIMESTAMP:      timestamp(self)
            elif op == NUMBER:         number(self)
            elif op == DIFFICULTY:     difficulty(self)
            elif op == GASLIMIT:       gaslimit(self)
            elif op == CHAINID:        chainid(self)
            elif op == SELFBALANCE:    selfbalance(self)
            elif op == BASEFEE:        basefee(self)
            
            # Stack Operations
            elif op == POP: _pop(self)
            
            # Memory Operations
            elif op == MLOAD:   mload(self)
            elif op == MSTORE:  mstore(self)
            elif op == MSTORE8: mstore8(self)
            
            # Storage Operations
            elif op == SLOAD:  sload(self)
            elif op == SSTORE: sstore(self)
            
            # Jump Operations
            elif op == JUMP:     jump(self)
            elif op == JUMPI:    jumpi(self)
            elif op == PC:       pc(self)
            elif op == JUMPDEST: jumpdest(self)
            
            # Transient Storage Operations
            elif op == TLOAD:  tload(self)
            elif op == TSTORE: tstore(self)
            
            # Push Operations (0x60-0x7F)
            elif op == PUSH1:  _push(self, 1)
            elif op == PUSH2:  _push(self, 2)
            elif op == PUSH3:  _push(self, 3)
            elif op == PUSH4:  _push(self, 4)
            elif op == PUSH5:  _push(self, 5)
            elif op == PUSH6:  _push(self, 6)
            elif op == PUSH7:  _push(self, 7)
            elif op == PUSH8:  _push(self, 8)
            elif op == PUSH9:  _push(self, 9)
            elif op == PUSH10: _push(self, 10)
            elif op == PUSH11: _push(self, 11)
            elif op == PUSH12: _push(self, 12)
            elif op == PUSH13: _push(self, 13)
            elif op == PUSH14: _push(self, 14)
            elif op == PUSH15: _push(self, 15)
            elif op == PUSH16: _push(self, 16)
            elif op == PUSH17: _push(self, 17)
            elif op == PUSH18: _push(self, 18)
            elif op == PUSH19: _push(self, 19)
            elif op == PUSH20: _push(self, 20)
            elif op == PUSH21: _push(self, 21)
            elif op == PUSH22: _push(self, 22)
            elif op == PUSH23: _push(self, 23)
            elif op == PUSH24: _push(self, 24)
            elif op == PUSH25: _push(self, 25)
            elif op == PUSH26: _push(self, 26)
            elif op == PUSH27: _push(self, 27)
            elif op == PUSH28: _push(self, 28)
            elif op == PUSH29: _push(self, 29)
            elif op == PUSH30: _push(self, 30)
            elif op == PUSH31: _push(self, 31)
            elif op == PUSH32: _push(self, 32)
            
            # Dup Operations (0x80-0x8F)
            elif op == DUP1:  _dup(self, 1)
            elif op == DUP2:  _dup(self, 2)
            elif op == DUP3:  _dup(self, 3)
            elif op == DUP4:  _dup(self, 4)
            elif op == DUP5:  _dup(self, 5)
            elif op == DUP6:  _dup(self, 6)
            elif op == DUP7:  _dup(self, 7)
            elif op == DUP8:  _dup(self, 8)
            elif op == DUP9:  _dup(self, 9)
            elif op == DUP10: _dup(self, 10)
            elif op == DUP11: _dup(self, 11)
            elif op == DUP12: _dup(self, 12)
            elif op == DUP13: _dup(self, 13)
            elif op == DUP14: _dup(self, 14)
            elif op == DUP15: _dup(self, 15)
            elif op == DUP16: _dup(self, 16)
            
            # Swap Operations (0x90-0x9F)
            elif op == SWAP1:  _swap(self, 1)
            elif op == SWAP2:  _swap(self, 2)
            elif op == SWAP3:  _swap(self, 3)
            elif op == SWAP4:  _swap(self, 4)
            elif op == SWAP5:  _swap(self, 5)
            elif op == SWAP6:  _swap(self, 6)
            elif op == SWAP7:  _swap(self, 7)
            elif op == SWAP8:  _swap(self, 8)
            elif op == SWAP9:  _swap(self, 9)
            elif op == SWAP10: _swap(self, 10)
            elif op == SWAP11: _swap(self, 11)
            elif op == SWAP12: _swap(self, 12)
            elif op == SWAP13: _swap(self, 13)
            elif op == SWAP14: _swap(self, 14)
            elif op == SWAP15: _swap(self, 15)
            elif op == SWAP16: _swap(self, 16)
            
            # Log Operations
            elif op == LOG0: log0(self)
            elif op == LOG1: log1(self)
            elif op == LOG2: log2(self)
            elif op == LOG3: log3(self)
            elif op == LOG4: log4(self)
            
            # Contract Operations
            elif op == CREATE:       create(self)
            elif op == CALL:         call(self)
            elif op == CALLCODE:     callcode(self)
            elif op == RETURN:       _return(self)
            elif op == DELEGATECALL: delegatecall(self)
            elif op == CREATE2:      create2(self)
            elif op == STATICCALL:   staticcall(self)
            elif op == REVERT:       revert(self)
            elif op == INVALID:      invalid(self)
            elif op == SELFDESTRUCT: selfdestruct(self)
            
            else:
                raise Exception(f"Unknown opcode: {hex(op)}")
        
    def reset(self):
        self.pc      = 0
        self.stack   = Stack()
        self.memory  = Memory()
        self.storage = Storage()