evm-rs/src/opcodes.rs
src/opcodes.rsRaw
1use super::*;
2
3// Non-opcode gas prices
4const GDEFAULT: usize = 1;
5const GMEMORY: usize = 3;
6const GQUADRATICMEMDENOM: usize = 512; // 1 gas per 512 quadwords
7const GSTORAGEREFUND: usize = 15000;
8const GSTORAGEKILL: usize = 5000;
9const GSTORAGEMOD: usize = 5000;
10const GSTORAGEADD: usize = 20000;
11const GEXPONENTBYTE: usize = 10; // cost of EXP exponent per byte
12const GCOPY: usize = 3; // cost to copy one 32 byte word
13const GCONTRACTBYTE: usize = 200; // one byte of code in contract creation
14const GCALLVALUETRANSFER: usize = 9000; // non-zero-valued call
15const GLOGBYTE: usize = 8; // cost of a byte of logdata
16
17const GTXCOST: usize = 21000; // TX BASE GAS COST
18const GTXDATAZERO: usize = 4; // TX DATA ZERO BYTE GAS COST
19const GTXDATANONZERO: usize = 68; // TX DATA NON ZERO BYTE GAS COST
20const GSHA3WORD: usize = 6; // Cost of SHA3 per word
21const GSHA256BASE: usize = 60; // Base c of SHA256
22const GSHA256WORD: usize = 12; // Cost of SHA256 per word
23const GRIPEMD160BASE: usize = 600; // Base cost of RIPEMD160
24const GRIPEMD160WORD: usize = 120; // Cost of RIPEMD160 per word
25const GIDENTITYBASE: usize = 15; // Base cost of indentity
26const GIDENTITYWORD: usize = 3; // Cost of identity per word
27const GECRECOVER: usize = 3000; // Cost of ecrecover op
28
29const GSTIPEND: usize = 2300;
30
31const GCALLNEWACCOUNT: usize = 25000;
32const GSUICIDEREFUND: usize = 24000;
33
34pub struct Opcode {
35 pub name: String,
36 pub ins: u32,
37 pub outs: u32,
38 pub gas: u64,
39 // operation: fn(),
40}
41
42pub fn new_opcode(name: &str, ins: u32, outs: u32, gas: u64) -> Opcode {
43 Opcode {
44 name: name.to_string(),
45 ins,
46 outs,
47 gas,
48 }
49}
50
51pub fn new_opcodes() -> HashMap<u8, Opcode> {
52 let mut opcodes: HashMap<u8, Opcode> = HashMap::new();
53
54 // arithmetic
55 opcodes.insert(0x00, new_opcode("STOP", 0, 0, 0));
56 opcodes.insert(0x01, new_opcode("ADD", 2, 1, 3));
57 opcodes.insert(0x02, new_opcode("MUL", 2, 1, 5));
58 opcodes.insert(0x03, new_opcode("SUB", 2, 1, 3));
59 opcodes.insert(0x04, new_opcode("DIV", 2, 1, 5));
60 opcodes.insert(0x05, new_opcode("SDIV", 2, 1, 5));
61 opcodes.insert(0x06, new_opcode("MOD", 2, 1, 5));
62 opcodes.insert(0x07, new_opcode("SMOD", 2, 1, 5));
63 opcodes.insert(0x08, new_opcode("ADDMOD", 3, 1, 8));
64 opcodes.insert(0x09, new_opcode("MULMOD", 3, 1, 8));
65 opcodes.insert(0x0a, new_opcode("EXP", 2, 1, 10));
66 opcodes.insert(0x0b, new_opcode("SIGNEXTEND", 2, 1, 5));
67
68 // boolean
69 opcodes.insert(0x10, new_opcode("LT", 2, 1, 3));
70 opcodes.insert(0x11, new_opcode("GT", 2, 1, 3));
71 opcodes.insert(0x12, new_opcode("SLT", 2, 1, 3));
72 opcodes.insert(0x13, new_opcode("SGT", 2, 1, 3));
73 opcodes.insert(0x14, new_opcode("EQ", 2, 1, 3));
74 opcodes.insert(0x15, new_opcode("ISZERO", 1, 1, 3));
75 opcodes.insert(0x16, new_opcode("AND", 2, 1, 3));
76 opcodes.insert(0x17, new_opcode("OR", 2, 1, 3));
77 opcodes.insert(0x18, new_opcode("XOR", 2, 1, 3));
78 opcodes.insert(0x19, new_opcode("NOT", 1, 1, 3));
79 opcodes.insert(0x1a, new_opcode("BYTE", 2, 1, 3));
80
81 // crypto
82 opcodes.insert(0x20, new_opcode("SHA3", 2, 1, 30));
83
84 // contract context
85 opcodes.insert(0x30, new_opcode("ADDRESS", 0, 1, 2));
86 opcodes.insert(0x31, new_opcode("BALANCE", 1, 1, 20));
87 opcodes.insert(0x32, new_opcode("ORIGIN", 0, 1, 2));
88 opcodes.insert(0x33, new_opcode("CALLER", 0, 1, 2));
89 opcodes.insert(0x34, new_opcode("CALLVALUE", 0, 1, 2));
90 opcodes.insert(0x35, new_opcode("CALLDATALOAD", 1, 1, 3));
91 opcodes.insert(0x36, new_opcode("CALLDATASIZE", 0, 1, 2));
92 opcodes.insert(0x37, new_opcode("CALLDATACOPY", 3, 0, 3));
93 opcodes.insert(0x38, new_opcode("CODESIZE", 0, 1, 2));
94 opcodes.insert(0x39, new_opcode("CODECOPY", 3, 0, 3));
95 opcodes.insert(0x3a, new_opcode("GASPRICE", 0, 1, 2));
96 opcodes.insert(0x3b, new_opcode("EXTCODESIZE", 1, 1, 20));
97 opcodes.insert(0x3c, new_opcode("EXTCODECOPY", 4, 0, 20));
98
99 // blockchain context
100 opcodes.insert(0x40, new_opcode("BLOCKHASH", 1, 1, 20));
101 opcodes.insert(0x41, new_opcode("COINBASE", 0, 1, 2));
102 opcodes.insert(0x42, new_opcode("TIMESTAMP", 0, 1, 2));
103 opcodes.insert(0x43, new_opcode("NUMBER", 0, 1, 2));
104 opcodes.insert(0x44, new_opcode("DIFFICULTY", 0, 1, 2));
105 opcodes.insert(0x45, new_opcode("GASLIMIT", 0, 1, 2));
106
107 // storage and execution
108 opcodes.insert(0x50, new_opcode("POP", 1, 0, 2));
109 opcodes.insert(0x51, new_opcode("MLOAD", 1, 1, 3));
110 opcodes.insert(0x52, new_opcode("MSTORE", 2, 0, 3));
111 opcodes.insert(0x53, new_opcode("MSTORE8", 2, 0, 3));
112 opcodes.insert(0x54, new_opcode("SLOAD", 1, 1, 50));
113 opcodes.insert(0x55, new_opcode("SSTORE", 2, 0, 0));
114 opcodes.insert(0x56, new_opcode("JUMP", 1, 0, 8));
115 opcodes.insert(0x57, new_opcode("JUMPI", 2, 0, 10));
116 opcodes.insert(0x58, new_opcode("PC", 0, 1, 2));
117 opcodes.insert(0x59, new_opcode("MSIZE", 0, 1, 2));
118 opcodes.insert(0x5a, new_opcode("GAS", 0, 1, 2));
119 opcodes.insert(0x5b, new_opcode("JUMPDEST", 0, 0, 1));
120
121 // logging
122 opcodes.insert(0xa0, new_opcode("LOG0", 2, 0, 375));
123 opcodes.insert(0xa1, new_opcode("LOG1", 3, 0, 750));
124 opcodes.insert(0xa2, new_opcode("LOG2", 4, 0, 1125));
125 opcodes.insert(0xa3, new_opcode("LOG3", 5, 0, 1500));
126 opcodes.insert(0xa4, new_opcode("LOG4", 6, 0, 1875));
127
128 // closures
129 opcodes.insert(0xf0, new_opcode("CREATE", 3, 1, 32000));
130 opcodes.insert(0xf1, new_opcode("CALL", 7, 1, 40));
131 opcodes.insert(0xf2, new_opcode("CALLCODE", 7, 1, 40));
132 opcodes.insert(0xf3, new_opcode("RETURN", 2, 0, 0));
133 opcodes.insert(0xf4, new_opcode("DELEGATECALL", 6, 0, 40));
134 opcodes.insert(0xff, new_opcode("SUICIDE", 1, 0, 0));
135
136 for i in 1..33 {
137 let name = format!("PUSH{}", i);
138 opcodes.insert(0x5f + i, new_opcode(&name, 0, 1, 3));
139 }
140
141 for i in 1..17 {
142 let name = format!("DUP{}", i);
143 opcodes.insert(0x7f + i, new_opcode(&name, i as u32, i as u32 + 1, 3));
144
145 let name = format!("SWAP{}", i);
146 opcodes.insert(0x8f + i, new_opcode(&name, i as u32 + 1, i as u32 + 1, 3));
147 }
148
149 opcodes
150}
151
152impl Stack {
153 // arithmetic
154 // TODO instead of [u8;32] converted to BigUint, use custom type uint256 that implements all
155 // the arithmetic
156 pub fn add(&mut self) {
157 let b0 = BigUint::from_bytes_be(&self.pop()[..]);
158 let b1 = BigUint::from_bytes_be(&self.pop()[..]);
159 self.push_arbitrary(&(b0 + b1).to_bytes_be());
160 }
161 pub fn mul(&mut self) {
162 let b0 = BigUint::from_bytes_be(&self.pop()[..]);
163 let b1 = BigUint::from_bytes_be(&self.pop()[..]);
164 self.push_arbitrary(&(b0 * b1).to_bytes_be());
165 }
166 pub fn sub(&mut self) {
167 let b0 = BigUint::from_bytes_be(&self.pop()[..]);
168 let b1 = BigUint::from_bytes_be(&self.pop()[..]);
169 if b0 >= b1 {
170 self.push_arbitrary(&(b0 - b1).to_bytes_be());
171 } else {
172 // 2**256
173 let max =
174 "115792089237316195423570985008687907853269984665640564039457584007913129639936"
175 .parse::<BigUint>()
176 .unwrap();
177 self.push_arbitrary(&(max + b0 - b1).to_bytes_be());
178 }
179 }
180 pub fn div(&mut self) {
181 let b0 = BigUint::from_bytes_be(&self.pop()[..]);
182 let b1 = BigUint::from_bytes_be(&self.pop()[..]);
183 self.push_arbitrary(&(b0 / b1).to_bytes_be());
184 }
185 pub fn sdiv(&mut self) {
186 panic!("unimplemented");
187 }
188 pub fn modulus(&mut self) {
189 let b0 = BigUint::from_bytes_be(&self.pop()[..]);
190 let b1 = BigUint::from_bytes_be(&self.pop()[..]);
191 self.push_arbitrary(&(b0 % b1).to_bytes_be());
192 }
193 pub fn smod(&mut self) {
194 panic!("unimplemented");
195 }
196 pub fn add_mod(&mut self) {
197 let b0 = BigUint::from_bytes_be(&self.pop()[..]);
198 let b1 = BigUint::from_bytes_be(&self.pop()[..]);
199 let b2 = BigUint::from_bytes_be(&self.pop()[..]);
200 self.push_arbitrary(&(b0 + b1 % b2).to_bytes_be());
201 }
202 pub fn mul_mod(&mut self) {
203 let b0 = BigUint::from_bytes_be(&self.pop()[..]);
204 let b1 = BigUint::from_bytes_be(&self.pop()[..]);
205 let b2 = BigUint::from_bytes_be(&self.pop()[..]);
206 self.push_arbitrary(&(b0 * b1 % b2).to_bytes_be());
207 }
208 pub fn exp(&mut self) {
209 panic!("unimplemented");
210 // let b0 = BigUint::from_bytes_be(&self.pop()[..]);
211 // let b1 = BigUint::from_bytes_be(&self.pop()[..]);
212 // self.push_arbitrary(&(pow(b0, b1)).to_bytes_be());
213 }
214
215 // boolean
216 // crypto
217
218 // contract context
219 pub fn calldata_load(&mut self, calldata: &[u8]) {
220 self.put_arbitrary(&calldata[self.calldata_i..self.calldata_i + 32]);
221 self.calldata_i += 32;
222 }
223
224 // blockchain context
225
226 // storage and execution
227 pub fn extend_mem(&mut self, start: usize, size: usize) {
228 if size <= self.mem.len() || start + size <= self.mem.len() {
229 return;
230 }
231 let old_size = self.mem.len() / 32;
232 let new_size = (start + size) / 32;
233 let old_total_fee = old_size * GMEMORY + old_size.pow(2) / GQUADRATICMEMDENOM;
234 let new_total_fee = new_size * GMEMORY + new_size.pow(2) / GQUADRATICMEMDENOM;
235 let mem_fee = new_total_fee - old_total_fee;
236 self.gas -= mem_fee as u64;
237 let mut new_bytes: Vec<u8> = vec![0; size];
238 self.mem.append(&mut new_bytes);
239 }
240 pub fn mload(&mut self) {
241 let pos = u256_to_u64(self.pop()) as usize;
242 self.extend_mem(pos as usize, 32);
243 let mem32 = self.mem[pos..pos + 32].to_vec();
244 self.push_arbitrary(&mem32);
245 }
246 pub fn mstore(&mut self) {
247 let pos = u256_to_u64(self.pop());
248 let val = self.pop();
249 self.extend_mem(pos as usize, 32);
250
251 self.mem[pos as usize..].copy_from_slice(&val);
252 }
253 pub fn jump(&mut self) {
254 // TODO that jump destination is valid
255 self.pc = u256_to_u64(self.pop()) as usize;
256 }
257 pub fn jump_i(&mut self) {
258 let new_pc = u256_to_u64(self.pop()) as usize;
259 if !self.stack.is_empty() {
260 let cond = u256_to_u64(self.pop()) as usize;
261 if cond != 0 {
262 self.pc = new_pc;
263 }
264 }
265 // let cont = self.pop();
266 // if cont {} // TODO depends on having impl Err in pop()
267 }
268 pub fn jump_dest(&mut self) {
269 // TODO
270 }
271}