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}