#![allow(dead_code)] use num_bigint::BigUint; use std::collections::HashMap; pub mod opcodes; #[derive(Default)] pub struct Stack { pub pc: usize, pub calldata_i: usize, pub stack: Vec<[u8; 32]>, pub mem: Vec, pub gas: u64, pub opcodes: HashMap, } impl Stack { pub fn new() -> Stack { let mut s = Stack { pc: 0, calldata_i: 0, stack: Vec::new(), mem: Vec::new(), gas: 10000000000, opcodes: HashMap::new(), }; s.opcodes = opcodes::new_opcodes(); s } pub fn print_stack(&self) { for i in (0..self.stack.len()).rev() { println!("{:x?}", &self.stack[i][28..]); } } pub fn push(&mut self, b: [u8; 32]) { self.stack.push(b); } // push_arbitrary performs a push, but first converting the arbitrary-length // input into a 32 byte array pub fn push_arbitrary(&mut self, b: &[u8]) { // TODO if b.len()>32 return error let mut d: [u8; 32] = [0; 32]; d[32 - b.len()..].copy_from_slice(b); self.stack.push(d); } // put_arbitrary puts in the last element of the stack the value pub fn put_arbitrary(&mut self, b: &[u8]) { // TODO if b.len()>32 return error let mut d: [u8; 32] = [0; 32]; d[32 - b.len()..].copy_from_slice(b); let l = self.stack.len(); self.stack[l - 1] = d; } pub fn pop(&mut self) -> [u8; 32] { match self.stack.pop() { Some(x) => x, None => panic!("err"), } } pub fn execute(&mut self, code: &[u8], calldata: &[u8], debug: bool) -> Vec { self.pc = 0; self.calldata_i = 0; let l = code.len(); while self.pc < l { let opcode = code[self.pc]; if !self.opcodes.contains_key(&opcode) { panic!("invalid opcode {:x}", opcode); } if debug { println!( "{:?} (0x{:x}): pc={:?} gas={:?}\nstack:", self.opcodes.get(&opcode).unwrap().name, opcode, self.pc, self.gas, ); self.print_stack(); println!(); } match opcode & 0xf0 { 0x00 => { // arithmetic match opcode { 0x00 => { return Vec::new(); } 0x01 => self.add(), 0x02 => self.mul(), 0x03 => self.sub(), 0x04 => self.div(), 0x05 => self.sdiv(), 0x06 => self.modulus(), 0x07 => self.smod(), 0x08 => self.add_mod(), 0x09 => self.mul_mod(), 0x0a => self.exp(), // 0x0b => self.sign_extend(), _ => panic!("unimplemented {:x}", opcode), } self.pc += 1; } 0x30 => { match opcode { 0x35 => { self.calldata_load(&calldata); } _ => panic!("unimplemented {:x}", opcode), } self.pc += 1; } 0x50 => { self.pc += 1; match opcode { 0x51 => self.mload(), 0x52 => self.mstore(), 0x56 => self.jump(), 0x57 => self.jump_i(), 0x5b => self.jump_dest(), _ => panic!("unimplemented {:x}", opcode), } } 0x60 | 0x70 => { // push let n = (opcode - 0x5f) as usize; self.push_arbitrary(&code[self.pc + 1..self.pc + 1 + n]); self.pc += 1 + n; } 0x80 => { // 0x8x dup let l = self.stack.len(); if opcode > 0x7f { self.stack.push(self.stack[l - (opcode - 0x7f) as usize]); } else { self.stack.push(self.stack[(0x7f - opcode) as usize]); } self.pc += 1; } 0x90 => { // 0x9x swap let l = self.stack.len(); let pos; if opcode > 0x8e { pos = l - (opcode - 0x8e) as usize; } else { pos = (0x8e - opcode) as usize; } self.stack.swap(pos, l - 1); self.pc += 1; } 0xf0 => { if opcode == 0xf3 { let pos_to_return = u256_to_u64(self.pop()) as usize; let len_to_return = u256_to_u64(self.pop()) as usize; return self.mem[pos_to_return..pos_to_return + len_to_return].to_vec(); } } _ => { panic!("unimplemented {:x}", opcode); } } self.gas -= self.opcodes.get(&opcode).unwrap().gas; } Vec::new() } } pub fn u256_to_u64(a: [u8; 32]) -> u64 { let mut b8: [u8; 8] = [0; 8]; b8.copy_from_slice(&a[32 - 8..32]); u64::from_be_bytes(b8) } pub fn str_to_u256(s: &str) -> [u8; 32] { let bi = s.parse::().unwrap().to_bytes_be(); let mut r: [u8; 32] = [0; 32]; r[32 - bi.len()..].copy_from_slice(&bi[..]); r }