evm-rs/src/opcodes.rs
src/opcodes.rsRaw
1use super::*;
2use num_bigint::BigUint;
3use num_traits::identities::Zero;
4
5// Non-opcode gas prices
6const GDEFAULT: usize = 1;
7const GMEMORY: usize = 3;
8const GQUADRATICMEMDENOM: usize = 512; // 1 gas per 512 quadwords
9const GSTORAGEREFUND: usize = 15000;
10const GSTORAGEKILL: usize = 5000;
11const GSTORAGEMOD: usize = 5000;
12const GSTORAGEADD: usize = 20000;
13
14const GEXPONENTBYTE: usize = 10; // cost of EXP exponent per byte
15const EXP_SUPPLEMENTAL_GAS: usize = 40;
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 Opcode {
39 pub name: String,
40 pub ins: u32,
41 pub outs: u32,
42 pub gas: u64,
43 // operation: fn(),
44}
45
46pub fn new_opcode(name: &str, ins: u32, outs: u32, gas: u64) -> Opcode {
47 Opcode {
48 name: name.to_string(),
49 ins,
50 outs,
51 gas,
52 }
53}
54
55pub fn new_opcodes() -> HashMap<u8, Opcode> {
56 let mut opcodes: HashMap<u8, Opcode> = HashMap::new();
57
58 // arithmetic
59 opcodes.insert(0x00, new_opcode("STOP", 0, 0, 0));
60 opcodes.insert(0x01, new_opcode("ADD", 2, 1, 3));
61 opcodes.insert(0x02, new_opcode("MUL", 2, 1, 5));
62 opcodes.insert(0x03, new_opcode("SUB", 2, 1, 3));
63 opcodes.insert(0x04, new_opcode("DIV", 2, 1, 5));
64 opcodes.insert(0x05, new_opcode("SDIV", 2, 1, 5));
65 opcodes.insert(0x06, new_opcode("MOD", 2, 1, 5));
66 opcodes.insert(0x07, new_opcode("SMOD", 2, 1, 5));
67 opcodes.insert(0x08, new_opcode("ADDMOD", 3, 1, 8));
68 opcodes.insert(0x09, new_opcode("MULMOD", 3, 1, 8));
69 opcodes.insert(0x0a, new_opcode("EXP", 2, 1, 10));
70 opcodes.insert(0x0b, new_opcode("SIGNEXTEND", 2, 1, 5));
71
72 // boolean
73 opcodes.insert(0x10, new_opcode("LT", 2, 1, 3));
74 opcodes.insert(0x11, new_opcode("GT", 2, 1, 3));
75 opcodes.insert(0x12, new_opcode("SLT", 2, 1, 3));
76 opcodes.insert(0x13, new_opcode("SGT", 2, 1, 3));
77 opcodes.insert(0x14, new_opcode("EQ", 2, 1, 3));
78 opcodes.insert(0x15, new_opcode("ISZERO", 1, 1, 3));
79 opcodes.insert(0x16, new_opcode("AND", 2, 1, 3));
80 opcodes.insert(0x17, new_opcode("OR", 2, 1, 3));
81 opcodes.insert(0x18, new_opcode("XOR", 2, 1, 3));
82 opcodes.insert(0x19, new_opcode("NOT", 1, 1, 3));
83 opcodes.insert(0x1a, new_opcode("BYTE", 2, 1, 3));
84
85 // crypto
86 opcodes.insert(0x20, new_opcode("SHA3", 2, 1, 30));
87
88 // contract context
89 opcodes.insert(0x30, new_opcode("ADDRESS", 0, 1, 2));
90 opcodes.insert(0x31, new_opcode("BALANCE", 1, 1, 20));
91 opcodes.insert(0x32, new_opcode("ORIGIN", 0, 1, 2));
92 opcodes.insert(0x33, new_opcode("CALLER", 0, 1, 2));
93 opcodes.insert(0x34, new_opcode("CALLVALUE", 0, 1, 2));
94 opcodes.insert(0x35, new_opcode("CALLDATALOAD", 1, 1, 3));
95 opcodes.insert(0x36, new_opcode("CALLDATASIZE", 0, 1, 2));
96 opcodes.insert(0x37, new_opcode("CALLDATACOPY", 3, 0, 3));
97 opcodes.insert(0x38, new_opcode("CODESIZE", 0, 1, 2));
98 opcodes.insert(0x39, new_opcode("CODECOPY", 3, 0, 3));
99 opcodes.insert(0x3a, new_opcode("GASPRICE", 0, 1, 2));
100 opcodes.insert(0x3b, new_opcode("EXTCODESIZE", 1, 1, 20));
101 opcodes.insert(0x3c, new_opcode("EXTCODECOPY", 4, 0, 20));
102
103 // blockchain context
104 opcodes.insert(0x40, new_opcode("BLOCKHASH", 1, 1, 20));
105 opcodes.insert(0x41, new_opcode("COINBASE", 0, 1, 2));
106 opcodes.insert(0x42, new_opcode("TIMESTAMP", 0, 1, 2));
107 opcodes.insert(0x43, new_opcode("NUMBER", 0, 1, 2));
108 opcodes.insert(0x44, new_opcode("DIFFICULTY", 0, 1, 2));
109 opcodes.insert(0x45, new_opcode("GASLIMIT", 0, 1, 2));
110
111 // storage and execution
112 opcodes.insert(0x50, new_opcode("POP", 1, 0, 2));
113 opcodes.insert(0x51, new_opcode("MLOAD", 1, 1, 3));
114 opcodes.insert(0x52, new_opcode("MSTORE", 2, 0, 3));
115 opcodes.insert(0x53, new_opcode("MSTORE8", 2, 0, 3));
116 opcodes.insert(0x54, new_opcode("SLOAD", 1, 1, 50));
117 opcodes.insert(0x55, new_opcode("SSTORE", 2, 0, 0));
118 opcodes.insert(0x56, new_opcode("JUMP", 1, 0, 8));
119 opcodes.insert(0x57, new_opcode("JUMPI", 2, 0, 10));
120 opcodes.insert(0x58, new_opcode("PC", 0, 1, 2));
121 opcodes.insert(0x59, new_opcode("MSIZE", 0, 1, 2));
122 opcodes.insert(0x5a, new_opcode("GAS", 0, 1, 2));
123 opcodes.insert(0x5b, new_opcode("JUMPDEST", 0, 0, 1));
124
125 // logging
126 opcodes.insert(0xa0, new_opcode("LOG0", 2, 0, 375));
127 opcodes.insert(0xa1, new_opcode("LOG1", 3, 0, 750));
128 opcodes.insert(0xa2, new_opcode("LOG2", 4, 0, 1125));
129 opcodes.insert(0xa3, new_opcode("LOG3", 5, 0, 1500));
130 opcodes.insert(0xa4, new_opcode("LOG4", 6, 0, 1875));
131
132 // closures
133 opcodes.insert(0xf0, new_opcode("CREATE", 3, 1, 32000));
134 opcodes.insert(0xf1, new_opcode("CALL", 7, 1, 40));
135 opcodes.insert(0xf2, new_opcode("CALLCODE", 7, 1, 40));
136 opcodes.insert(0xf3, new_opcode("RETURN", 2, 0, 0));
137 opcodes.insert(0xf4, new_opcode("DELEGATECALL", 6, 0, 40));
138 opcodes.insert(0xff, new_opcode("SUICIDE", 1, 0, 0));
139
140 for i in 1..33 {
141 let name = format!("PUSH{}", i);
142 opcodes.insert(0x5f + i, new_opcode(&name, 0, 1, 3));
143 }
144
145 for i in 1..17 {
146 let name = format!("DUP{}", i);
147 opcodes.insert(0x7f + i, new_opcode(&name, i as u32, i as u32 + 1, 3));
148
149 let name = format!("SWAP{}", i);
150 opcodes.insert(0x8f + i, new_opcode(&name, i as u32 + 1, i as u32 + 1, 3));
151 }
152
153 opcodes
154}
155
156impl Stack {
157 // arithmetic
158 // TODO instead of [u8;32] converted to BigUint, use custom type uint256 that implements all
159 // the arithmetic
160 pub fn add(&mut self) -> Result<(), String> {
161 let b0 = BigUint::from_bytes_be(&self.pop()?[..]);
162 let b1 = BigUint::from_bytes_be(&self.pop()?[..]);
163 self.push_arbitrary(&(b0 + b1).to_bytes_be());
164 Ok(())
165 }
166 pub fn mul(&mut self) -> Result<(), String> {
167 let b0 = BigUint::from_bytes_be(&self.pop()?[..]);
168 let b1 = BigUint::from_bytes_be(&self.pop()?[..]);
169 self.push_arbitrary(&(b0 * b1).to_bytes_be());
170 Ok(())
171 }
172 pub fn sub(&mut self) -> Result<(), String> {
173 let b0 = BigUint::from_bytes_be(&self.pop()?[..]);
174 let b1 = BigUint::from_bytes_be(&self.pop()?[..]);
175 if b0 >= b1 {
176 self.push_arbitrary(&(b0 - b1).to_bytes_be());
177 } else {
178 // 2**256 TODO this will not be here hardcoded, there will be a custom type uint256
179 let max =
180 "115792089237316195423570985008687907853269984665640564039457584007913129639936"
181 .parse::<BigUint>()
182 .unwrap();
183 self.push_arbitrary(&(max + b0 - b1).to_bytes_be());
184 }
185 Ok(())
186 }
187 pub fn div(&mut self) -> Result<(), String> {
188 let b0 = BigUint::from_bytes_be(&self.pop()?[..]);
189 let b1 = BigUint::from_bytes_be(&self.pop()?[..]);
190 self.push_arbitrary(&(b0 / b1).to_bytes_be());
191 Ok(())
192 }
193 pub fn sdiv(&mut self) -> Result<(), String> {
194 Err("unimplemented".to_string())
195 }
196 pub fn modulus(&mut self) -> Result<(), String> {
197 let b0 = BigUint::from_bytes_be(&self.pop()?[..]);
198 let b1 = BigUint::from_bytes_be(&self.pop()?[..]);
199 self.push_arbitrary(&(b0 % b1).to_bytes_be());
200 Ok(())
201 }
202 pub fn smod(&mut self) -> Result<(), String> {
203 Err("unimplemented".to_string())
204 }
205 pub fn add_mod(&mut self) -> Result<(), String> {
206 let b0 = BigUint::from_bytes_be(&self.pop()?[..]);
207 let b1 = BigUint::from_bytes_be(&self.pop()?[..]);
208 let b2 = BigUint::from_bytes_be(&self.pop()?[..]);
209 self.push_arbitrary(&(b0 + b1 % b2).to_bytes_be());
210 Ok(())
211 }
212 pub fn mul_mod(&mut self) -> Result<(), String> {
213 let b0 = BigUint::from_bytes_be(&self.pop()?[..]);
214 let b1 = BigUint::from_bytes_be(&self.pop()?[..]);
215 let b2 = BigUint::from_bytes_be(&self.pop()?[..]);
216 self.push_arbitrary(&(b0 * b1 % b2).to_bytes_be());
217 Ok(())
218 }
219 pub fn exp(&mut self) -> Result<(), String> {
220 let b = BigUint::from_bytes_be(&self.pop()?[..]);
221 let e = BigUint::from_bytes_be(&self.pop()?[..]);
222
223 let mut r = "1".parse::<BigUint>().unwrap();
224 let zero = "0".parse::<BigUint>().unwrap();
225 let mut rem = e.clone();
226 let mut exp = b;
227 // 2**256 TODO this will not be here hardcoded, there will be a custom type uint256
228 let field =
229 "115792089237316195423570985008687907853269984665640564039457584007913129639936"
230 .parse::<BigUint>()
231 .unwrap();
232 while rem != zero {
233 if rem.bit(0) {
234 // is odd
235 r = r * exp.clone() % field.clone();
236 }
237 exp = exp.clone() * exp.clone();
238 rem >>= 1;
239 }
240 self.push_arbitrary(&r.to_bytes_be());
241
242 let n_bytes = &e.to_bytes_be().len();
243 let mut exp_fee = n_bytes * GEXPONENTBYTE;
244 exp_fee += EXP_SUPPLEMENTAL_GAS * n_bytes;
245 self.gas -= exp_fee as u64;
246 Ok(())
247 }
248
249 // boolean
250 pub fn lt(&mut self) -> Result<(), String> {
251 let a = BigUint::from_bytes_be(&self.pop()?[..]);
252 let b = BigUint::from_bytes_be(&self.pop()?[..]);
253 self.push(u256::usize_to_u256((a < b) as usize));
254 Ok(())
255 }
256 pub fn gt(&mut self) -> Result<(), String> {
257 let a = BigUint::from_bytes_be(&self.pop()?[..]);
258 let b = BigUint::from_bytes_be(&self.pop()?[..]);
259 self.push(u256::usize_to_u256((a > b) as usize));
260 Ok(())
261 }
262 pub fn eq(&mut self) -> Result<(), String> {
263 let a = BigUint::from_bytes_be(&self.pop()?[..]);
264 let b = BigUint::from_bytes_be(&self.pop()?[..]);
265 self.push(u256::usize_to_u256((a == b) as usize));
266 Ok(())
267 }
268 pub fn is_zero(&mut self) -> Result<(), String> {
269 let a = BigUint::from_bytes_be(&self.pop()?[..]);
270 self.push(u256::usize_to_u256(a.is_zero() as usize));
271 Ok(())
272 }
273 pub fn and(&mut self) -> Result<(), String> {
274 let a = BigUint::from_bytes_be(&self.pop()?[..]);
275 let b = BigUint::from_bytes_be(&self.pop()?[..]);
276 self.push_arbitrary(&(a & b).to_bytes_be());
277 Ok(())
278 }
279 pub fn or(&mut self) -> Result<(), String> {
280 let a = BigUint::from_bytes_be(&self.pop()?[..]);
281 let b = BigUint::from_bytes_be(&self.pop()?[..]);
282 self.push_arbitrary(&(a | b).to_bytes_be());
283 Ok(())
284 }
285 pub fn xor(&mut self) -> Result<(), String> {
286 let a = BigUint::from_bytes_be(&self.pop()?[..]);
287 let b = BigUint::from_bytes_be(&self.pop()?[..]);
288 self.push_arbitrary(&(a ^ b).to_bytes_be());
289 Ok(())
290 }
291 pub fn not(&mut self) -> Result<(), String> {
292 // 2**256-1 TODO this will not be here hardcoded, there will be a custom type uint256
293 let f = "115792089237316195423570985008687907853269984665640564039457584007913129639935"
294 .parse::<BigUint>()
295 .unwrap();
296
297 let a = BigUint::from_bytes_be(&self.pop()?[..]);
298 self.push_arbitrary(&(f - a).to_bytes_be());
299 Ok(())
300 }
301
302 // crypto
303
304 // contract context
305 pub fn calldata_load(&mut self, calldata: &[u8]) -> Result<(), String> {
306 let mut start = self.calldata_i;
307 if !self.stack.is_empty() {
308 start = u256::u256_to_u64(self.peek()?) as usize;
309 }
310 let l = calldata.len();
311 if start > l {
312 start = l;
313 }
314 let mut end = start + self.calldata_size;
315 if end > l {
316 end = l;
317 }
318 self.put_arbitrary(&calldata[start..end]);
319 self.calldata_i += self.calldata_size;
320 Ok(())
321 }
322 pub fn calldata_size(&mut self, calldata: &[u8]) {
323 self.calldata_size = calldata.len();
324 self.push(u256::usize_to_u256(self.calldata_size));
325 }
326 fn spend_gas_data_copy(&mut self, length: usize) {
327 let length32 = upper_multiple_of_32(length);
328 self.gas -= ((GCOPY * length32) / 32) as u64;
329 }
330 pub fn code_copy(&mut self, code: &[u8]) -> Result<(), String> {
331 let dest_offset = u256::u256_to_u64(self.pop()?) as usize;
332 let offset = u256::u256_to_u64(self.pop()?) as usize;
333 let length = u256::u256_to_u64(self.pop()?) as usize;
334
335 self.extend_mem(dest_offset, length);
336 self.spend_gas_data_copy(length);
337
338 for i in 0..length {
339 if offset + i < code.len() {
340 self.mem[dest_offset + i] = code[offset + i];
341 } else {
342 self.mem[dest_offset + i] = 0;
343 }
344 }
345 // self.mem[dest_offset..dest_offset+length] =
346 Ok(())
347 }
348
349 // blockchain context
350
351 // storage and execution
352 pub fn extend_mem(&mut self, start: usize, size: usize) {
353 if size <= self.mem.len() || start + size <= self.mem.len() {
354 return;
355 }
356 let old_size = self.mem.len() / 32;
357 let new_size = upper_multiple_of_32(start + size) / 32;
358 let old_total_fee = old_size * GMEMORY + old_size.pow(2) / GQUADRATICMEMDENOM;
359 let new_total_fee = new_size * GMEMORY + new_size.pow(2) / GQUADRATICMEMDENOM;
360 let mem_fee = new_total_fee - old_total_fee;
361 self.gas -= mem_fee as u64;
362 let mut new_bytes: Vec<u8> = vec![0; (new_size - old_size) * 32];
363 self.mem.append(&mut new_bytes);
364 }
365 pub fn mload(&mut self) -> Result<(), String> {
366 let pos = u256::u256_to_u64(self.pop()?) as usize;
367 self.extend_mem(pos as usize, 32);
368 let mem32 = self.mem[pos..pos + 32].to_vec();
369 self.push_arbitrary(&mem32);
370 Ok(())
371 }
372 pub fn mstore(&mut self) -> Result<(), String> {
373 let pos = u256::u256_to_u64(self.pop()?);
374 let val = self.pop()?;
375 self.extend_mem(pos as usize, 32);
376
377 self.mem[pos as usize..].copy_from_slice(&val);
378 Ok(())
379 }
380 pub fn sstore(&mut self) -> Result<(), String> {
381 // TODO WIP
382 let key = self.pop()?;
383 let value = self.pop()?;
384 if self.storage.contains_key(&key) {
385 let old_value = self.storage.get(&key).unwrap();
386 if &value.to_vec() == old_value {
387 // if the new value is the same as the old one, do not set
388 return Ok(());
389 }
390 // if value (from self.pop()) does not exist in the stack, is a STORAGEKILL TODO
391 println!("mingas {:?}", GSTORAGEMOD);
392 self.gas -= GSTORAGEMOD as u64;
393 } else {
394 // if value does not exist, substract gas for the addition
395 println!("mingas {:?}", GSTORAGEADD);
396 self.gas -= GSTORAGEADD as u64;
397 }
398 println!(
399 "insert {:?} - {:?}",
400 vec_u8_to_hex(key.to_vec()),
401 vec_u8_to_hex(value.to_vec())
402 );
403 self.storage.insert(key, value.to_vec());
404 Ok(())
405 }
406 pub fn jump(&mut self, code: &[u8]) -> Result<(), String> {
407 // TODO that jump destination is valid
408 let new_pc = u256::u256_to_u64(self.pop()?) as usize;
409 if !valid_dest(code, new_pc) {
410 return Err(format!("not valid dest: {:02x}", new_pc));
411 }
412 self.pc = new_pc;
413 Ok(())
414 }
415 pub fn jump_i(&mut self, code: &[u8]) -> Result<(), String> {
416 let new_pc = u256::u256_to_u64(self.pop()?) as usize;
417 if !valid_dest(code, new_pc) {
418 return Err(format!("not valid dest: {:02x}", new_pc));
419 }
420 if !self.stack.is_empty() {
421 let cond = u256::u256_to_u64(self.pop()?) as usize;
422 if cond != 0 {
423 self.pc = new_pc;
424 }
425 }
426 // let cont = self.pop();
427 // if cont {} // TODO depends on having impl Err in pop()
428 Ok(())
429 }
430 pub fn jump_dest(&mut self) -> Result<(), String> {
431 // TODO
432 Ok(())
433 }
434}
435
436fn valid_dest(code: &[u8], pos: usize) -> bool {
437 if code[pos] == 0x5b {
438 return true;
439 }
440 false
441}
442
443fn upper_multiple_of_32(n: usize) -> usize {
444 ((n - 1) | 31) + 1
445}