arnaucube
arnaucube/evm-rsPublic Self-hosted repository
evm-rs/src/lib.rs
src/lib.rsRaw
  1#![allow(dead_code)]
  2
  3// use num::pow::pow;
  4use num_bigint::BigUint;
  5use std::collections::HashMap;
  6
  7// Non-opcode gas prices
  8const GDEFAULT: usize = 1;
  9const GMEMORY: usize = 3;
 10const GQUADRATICMEMDENOM: usize = 512; // 1 gas per 512 quadwords
 11const GSTORAGEREFUND: usize = 15000;
 12const GSTORAGEKILL: usize = 5000;
 13const GSTORAGEMOD: usize = 5000;
 14const GSTORAGEADD: usize = 20000;
 15const GEXPONENTBYTE: usize = 10; // cost of EXP exponent per byte
 16const GCOPY: usize = 3; // cost to copy one 32 byte word
 17const GCONTRACTBYTE: usize = 200; // one byte of code in contract creation
 18const GCALLVALUETRANSFER: usize = 9000; // non-zero-valued call
 19const GLOGBYTE: usize = 8; // cost of a byte of logdata
 20
 21const GTXCOST: usize = 21000; // TX BASE GAS COST
 22const GTXDATAZERO: usize = 4; // TX DATA ZERO BYTE GAS COST
 23const GTXDATANONZERO: usize = 68; // TX DATA NON ZERO BYTE GAS COST
 24const GSHA3WORD: usize = 6; // Cost of SHA3 per word
 25const GSHA256BASE: usize = 60; // Base c of SHA256
 26const GSHA256WORD: usize = 12; // Cost of SHA256 per word
 27const GRIPEMD160BASE: usize = 600; // Base cost of RIPEMD160
 28const GRIPEMD160WORD: usize = 120; // Cost of RIPEMD160 per word
 29const GIDENTITYBASE: usize = 15; // Base cost of indentity
 30const GIDENTITYWORD: usize = 3; // Cost of identity per word
 31const GECRECOVER: usize = 3000; // Cost of ecrecover op
 32
 33const GSTIPEND: usize = 2300;
 34
 35const GCALLNEWACCOUNT: usize = 25000;
 36const GSUICIDEREFUND: usize = 24000;
 37
 38pub struct Stack {
 39    pc: usize,
 40    calldata_i: usize,
 41    stack: Vec<[u8; 32]>,
 42    mem: Vec<u8>,
 43    gas: u64,
 44    opcodes: HashMap<u8, Opcode>,
 45}
 46
 47impl Stack {
 48    pub fn new() -> Stack {
 49        let mut s = Stack {
 50            pc: 0,
 51            calldata_i: 0,
 52            stack: Vec::new(),
 53            mem: Vec::new(),
 54            gas: 10000000000,
 55            opcodes: HashMap::new(),
 56        };
 57        s.opcodes = new_opcodes();
 58        s
 59    }
 60    fn push(&mut self, b: [u8; 32]) {
 61        self.stack.push(b);
 62    }
 63    fn pop(&mut self) -> [u8; 32] {
 64        match self.stack.pop() {
 65            Some(x) => return x,
 66            None => panic!("err"),
 67        }
 68    }
 69}
 70
 71fn u256_to_u64(a: [u8; 32]) -> u64 {
 72    let mut b8: [u8; 8] = [0; 8];
 73    b8.copy_from_slice(&a[32 - 8..32]);
 74    let pos = u64::from_be_bytes(b8);
 75    pos
 76}
 77fn str_to_u256(s: &str) -> [u8; 32] {
 78    let bi = s.parse::<BigUint>().unwrap().to_bytes_be();
 79    let mut r: [u8; 32] = [0; 32];
 80    r[32 - bi.len()..].copy_from_slice(&bi[..]);
 81    r
 82}
 83
 84struct Opcode {
 85    name: String,
 86    ins: u32,
 87    outs: u32,
 88    gas: u64,
 89}
 90
 91fn new_opcode(name: &str, ins: u32, outs: u32, gas: u64) -> Opcode {
 92    Opcode {
 93        name: name.to_string(),
 94        ins,
 95        outs,
 96        gas,
 97    }
 98}
 99
100fn new_opcodes() -> HashMap<u8, Opcode> {
101    let mut opcodes: HashMap<u8, Opcode> = HashMap::new();
102
103    // arithmetic
104    opcodes.insert(0x00, new_opcode("STOP", 0, 0, 0));
105    opcodes.insert(0x01, new_opcode("ADD", 2, 1, 3));
106    opcodes.insert(0x02, new_opcode("MUL", 2, 1, 5));
107    opcodes.insert(0x03, new_opcode("SUB", 2, 1, 3));
108    opcodes.insert(0x04, new_opcode("DIV", 2, 1, 5));
109    opcodes.insert(0x05, new_opcode("SDIV", 2, 1, 5));
110    opcodes.insert(0x06, new_opcode("MOD", 2, 1, 5));
111    opcodes.insert(0x07, new_opcode("SMOD", 2, 1, 5));
112    opcodes.insert(0x08, new_opcode("ADDMOD", 3, 1, 8));
113    opcodes.insert(0x09, new_opcode("MULMOD", 3, 1, 8));
114    opcodes.insert(0x0a, new_opcode("EXP", 2, 1, 10));
115    opcodes.insert(0x0b, new_opcode("SIGNEXTEND", 2, 1, 5));
116
117    // boolean
118    opcodes.insert(0x10, new_opcode("LT", 2, 1, 3));
119    opcodes.insert(0x11, new_opcode("GT", 2, 1, 3));
120    opcodes.insert(0x12, new_opcode("SLT", 2, 1, 3));
121    opcodes.insert(0x13, new_opcode("SGT", 2, 1, 3));
122    opcodes.insert(0x14, new_opcode("EQ", 2, 1, 3));
123    opcodes.insert(0x15, new_opcode("ISZERO", 1, 1, 3));
124    opcodes.insert(0x16, new_opcode("AND", 2, 1, 3));
125    opcodes.insert(0x17, new_opcode("OR", 2, 1, 3));
126    opcodes.insert(0x18, new_opcode("XOR", 2, 1, 3));
127    opcodes.insert(0x19, new_opcode("NOT", 1, 1, 3));
128    opcodes.insert(0x1a, new_opcode("BYTE", 2, 1, 3));
129
130    // crypto
131    opcodes.insert(0x20, new_opcode("SHA3", 2, 1, 30));
132
133    // contract context
134    opcodes.insert(0x30, new_opcode("ADDRESS", 0, 1, 2));
135    opcodes.insert(0x31, new_opcode("BALANCE", 1, 1, 20));
136    opcodes.insert(0x32, new_opcode("ORIGIN", 0, 1, 2));
137    opcodes.insert(0x33, new_opcode("CALLER", 0, 1, 2));
138    opcodes.insert(0x34, new_opcode("CALLVALUE", 0, 1, 2));
139    opcodes.insert(0x35, new_opcode("CALLDATALOAD", 1, 1, 3));
140    opcodes.insert(0x36, new_opcode("CALLDATASIZE", 0, 1, 2));
141    opcodes.insert(0x37, new_opcode("CALLDATACOPY", 3, 0, 3));
142    opcodes.insert(0x38, new_opcode("CODESIZE", 0, 1, 2));
143    opcodes.insert(0x39, new_opcode("CODECOPY", 3, 0, 3));
144    opcodes.insert(0x3a, new_opcode("GASPRICE", 0, 1, 2));
145    opcodes.insert(0x3b, new_opcode("EXTCODESIZE", 1, 1, 20));
146    opcodes.insert(0x3c, new_opcode("EXTCODECOPY", 4, 0, 20));
147
148    // blockchain context
149    opcodes.insert(0x40, new_opcode("BLOCKHASH", 1, 1, 20));
150    opcodes.insert(0x41, new_opcode("COINBASE", 0, 1, 2));
151    opcodes.insert(0x42, new_opcode("TIMESTAMP", 0, 1, 2));
152    opcodes.insert(0x43, new_opcode("NUMBER", 0, 1, 2));
153    opcodes.insert(0x44, new_opcode("DIFFICULTY", 0, 1, 2));
154    opcodes.insert(0x45, new_opcode("GASLIMIT", 0, 1, 2));
155
156    // storage and execution
157    opcodes.insert(0x50, new_opcode("POP", 1, 0, 2));
158    opcodes.insert(0x51, new_opcode("MLOAD", 1, 1, 3));
159    opcodes.insert(0x52, new_opcode("MSTORE", 2, 0, 3));
160    opcodes.insert(0x53, new_opcode("MSTORE8", 2, 0, 3));
161    opcodes.insert(0x54, new_opcode("SLOAD", 1, 1, 50));
162    opcodes.insert(0x55, new_opcode("SSTORE", 2, 0, 0));
163    opcodes.insert(0x56, new_opcode("JUMP", 1, 0, 8));
164    opcodes.insert(0x57, new_opcode("JUMPI", 2, 0, 10));
165    opcodes.insert(0x58, new_opcode("PC", 0, 1, 2));
166    opcodes.insert(0x59, new_opcode("MSIZE", 0, 1, 2));
167    opcodes.insert(0x5a, new_opcode("GAS", 0, 1, 2));
168    opcodes.insert(0x5b, new_opcode("JUMPDEST", 0, 0, 1));
169
170    // logging
171    opcodes.insert(0xa0, new_opcode("LOG0", 2, 0, 375));
172    opcodes.insert(0xa1, new_opcode("LOG1", 3, 0, 750));
173    opcodes.insert(0xa2, new_opcode("LOG2", 4, 0, 1125));
174    opcodes.insert(0xa3, new_opcode("LOG3", 5, 0, 1500));
175    opcodes.insert(0xa4, new_opcode("LOG4", 6, 0, 1875));
176
177    // closures
178    opcodes.insert(0xf0, new_opcode("CREATE", 3, 1, 32000));
179    opcodes.insert(0xf1, new_opcode("CALL", 7, 1, 40));
180    opcodes.insert(0xf2, new_opcode("CALLCODE", 7, 1, 40));
181    opcodes.insert(0xf3, new_opcode("RETURN", 2, 0, 0));
182    opcodes.insert(0xf4, new_opcode("DELEGATECALL", 6, 0, 40));
183    opcodes.insert(0xff, new_opcode("SUICIDE", 1, 0, 0));
184
185    for i in 1..33 {
186        let name = format!("PUSH{}", i);
187        opcodes.insert(0x5f + i, new_opcode(&name, 0, 1, 3));
188    }
189
190    for i in 1..17 {
191        let name = format!("DUP{}", i);
192        opcodes.insert(0x7f + i, new_opcode(&name, i as u32, i as u32 + 1, 3));
193
194        let name = format!("SWAP{}", i);
195        opcodes.insert(0x8f + i, new_opcode(&name, i as u32 + 1, i as u32 + 1, 3));
196    }
197
198    opcodes
199}
200
201#[cfg(test)]
202mod tests {
203    use super::*;
204
205    #[test]
206    fn stack_simple_push_pop() {
207        let mut s = Stack::new();
208        s.push(str_to_u256("1"));
209        s.push(str_to_u256("2"));
210        s.push(str_to_u256("3"));
211        assert_eq!(s.pop(), str_to_u256("3"));
212        assert_eq!(s.pop(), str_to_u256("2"));
213        assert_eq!(s.pop(), str_to_u256("1"));
214        // assert_eq!(s.pop(), str_to_u256("1"));
215        // assert_eq!(s.pop(), error); // TODO expect error as stack is empty
216    }
217}