arnaucube
arnaucube/evm-rsPublic Self-hosted repository
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 NETSSTORENOOPGAS: u64 = 200;
 15const NETSSTOREINITGAS: u64 = 20000;
 16const NETSSTORECLEARREFUND: u64 = 15000;
 17const NETSSTORERESETCLEARREFUND: u64 = 19800;
 18const NETSSTORERESETREFUND: u64 = 4800;
 19const NETSSTORECLEANGAS: u64 = 5000;
 20const NETSSTOREDIRTYGAS: u64 = 200;
 21
 22const GEXPONENTBYTE: usize = 10; // cost of EXP exponent per byte
 23const EXP_SUPPLEMENTAL_GAS: usize = 40;
 24const GCOPY: usize = 3; // cost to copy one 32 byte word
 25const GCONTRACTBYTE: usize = 200; // one byte of code in contract creation
 26const GCALLVALUETRANSFER: usize = 9000; // non-zero-valued call
 27const GLOGBYTE: usize = 8; // cost of a byte of logdata
 28
 29const GTXCOST: usize = 21000; // TX BASE GAS COST
 30const GTXDATAZERO: usize = 4; // TX DATA ZERO BYTE GAS COST
 31const GTXDATANONZERO: usize = 68; // TX DATA NON ZERO BYTE GAS COST
 32const GSHA3WORD: usize = 6; // Cost of SHA3 per word
 33const GSHA256BASE: usize = 60; // Base c of SHA256
 34const GSHA256WORD: usize = 12; // Cost of SHA256 per word
 35const GRIPEMD160BASE: usize = 600; // Base cost of RIPEMD160
 36const GRIPEMD160WORD: usize = 120; // Cost of RIPEMD160 per word
 37const GIDENTITYBASE: usize = 15; // Base cost of indentity
 38const GIDENTITYWORD: usize = 3; // Cost of identity per word
 39const GECRECOVER: usize = 3000; // Cost of ecrecover op
 40
 41const GSTIPEND: usize = 2300;
 42
 43const GCALLNEWACCOUNT: usize = 25000;
 44const GSUICIDEREFUND: usize = 24000;
 45
 46pub struct Opcode {
 47    pub name: String,
 48    pub ins: u32,
 49    pub outs: u32,
 50    pub gas: u64,
 51}
 52
 53pub fn new_opcode(name: &str, ins: u32, outs: u32, gas: u64) -> Opcode {
 54    Opcode {
 55        name: name.to_string(),
 56        ins,
 57        outs,
 58        gas,
 59    }
 60}
 61
 62pub fn new_opcodes() -> HashMap<u8, Opcode> {
 63    let mut opcodes: HashMap<u8, Opcode> = HashMap::new();
 64
 65    // arithmetic
 66    opcodes.insert(0x00, new_opcode("STOP", 0, 0, 0));
 67    opcodes.insert(0x01, new_opcode("ADD", 2, 1, 3));
 68    opcodes.insert(0x02, new_opcode("MUL", 2, 1, 5));
 69    opcodes.insert(0x03, new_opcode("SUB", 2, 1, 3));
 70    opcodes.insert(0x04, new_opcode("DIV", 2, 1, 5));
 71    opcodes.insert(0x05, new_opcode("SDIV", 2, 1, 5));
 72    opcodes.insert(0x06, new_opcode("MOD", 2, 1, 5));
 73    opcodes.insert(0x07, new_opcode("SMOD", 2, 1, 5));
 74    opcodes.insert(0x08, new_opcode("ADDMOD", 3, 1, 8));
 75    opcodes.insert(0x09, new_opcode("MULMOD", 3, 1, 8));
 76    opcodes.insert(0x0a, new_opcode("EXP", 2, 1, 10));
 77    opcodes.insert(0x0b, new_opcode("SIGNEXTEND", 2, 1, 5));
 78
 79    // boolean
 80    opcodes.insert(0x10, new_opcode("LT", 2, 1, 3));
 81    opcodes.insert(0x11, new_opcode("GT", 2, 1, 3));
 82    opcodes.insert(0x12, new_opcode("SLT", 2, 1, 3));
 83    opcodes.insert(0x13, new_opcode("SGT", 2, 1, 3));
 84    opcodes.insert(0x14, new_opcode("EQ", 2, 1, 3));
 85    opcodes.insert(0x15, new_opcode("ISZERO", 1, 1, 3));
 86    opcodes.insert(0x16, new_opcode("AND", 2, 1, 3));
 87    opcodes.insert(0x17, new_opcode("OR", 2, 1, 3));
 88    opcodes.insert(0x18, new_opcode("XOR", 2, 1, 3));
 89    opcodes.insert(0x19, new_opcode("NOT", 1, 1, 3));
 90    opcodes.insert(0x1a, new_opcode("BYTE", 2, 1, 3));
 91
 92    // crypto
 93    opcodes.insert(0x20, new_opcode("SHA3", 2, 1, 30));
 94
 95    // contract context
 96    opcodes.insert(0x30, new_opcode("ADDRESS", 0, 1, 2));
 97    opcodes.insert(0x31, new_opcode("BALANCE", 1, 1, 20));
 98    opcodes.insert(0x32, new_opcode("ORIGIN", 0, 1, 2));
 99    opcodes.insert(0x33, new_opcode("CALLER", 0, 1, 2));
100    opcodes.insert(0x34, new_opcode("CALLVALUE", 0, 1, 2));
101    opcodes.insert(0x35, new_opcode("CALLDATALOAD", 1, 1, 3));
102    opcodes.insert(0x36, new_opcode("CALLDATASIZE", 0, 1, 2));
103    opcodes.insert(0x37, new_opcode("CALLDATACOPY", 3, 0, 3));
104    opcodes.insert(0x38, new_opcode("CODESIZE", 0, 1, 2));
105    opcodes.insert(0x39, new_opcode("CODECOPY", 3, 0, 3));
106    opcodes.insert(0x3a, new_opcode("GASPRICE", 0, 1, 2));
107    opcodes.insert(0x3b, new_opcode("EXTCODESIZE", 1, 1, 20));
108    opcodes.insert(0x3c, new_opcode("EXTCODECOPY", 4, 0, 20));
109
110    // blockchain context
111    opcodes.insert(0x40, new_opcode("BLOCKHASH", 1, 1, 20));
112    opcodes.insert(0x41, new_opcode("COINBASE", 0, 1, 2));
113    opcodes.insert(0x42, new_opcode("TIMESTAMP", 0, 1, 2));
114    opcodes.insert(0x43, new_opcode("NUMBER", 0, 1, 2));
115    opcodes.insert(0x44, new_opcode("DIFFICULTY", 0, 1, 2));
116    opcodes.insert(0x45, new_opcode("GASLIMIT", 0, 1, 2));
117
118    // storage and execution
119    opcodes.insert(0x50, new_opcode("POP", 1, 0, 2));
120    opcodes.insert(0x51, new_opcode("MLOAD", 1, 1, 3));
121    opcodes.insert(0x52, new_opcode("MSTORE", 2, 0, 3));
122    opcodes.insert(0x53, new_opcode("MSTORE8", 2, 0, 3));
123    opcodes.insert(0x54, new_opcode("SLOAD", 1, 1, 50));
124    opcodes.insert(0x55, new_opcode("SSTORE", 2, 0, 0));
125    opcodes.insert(0x56, new_opcode("JUMP", 1, 0, 8));
126    opcodes.insert(0x57, new_opcode("JUMPI", 2, 0, 10));
127    opcodes.insert(0x58, new_opcode("PC", 0, 1, 2));
128    opcodes.insert(0x59, new_opcode("MSIZE", 0, 1, 2));
129    opcodes.insert(0x5a, new_opcode("GAS", 0, 1, 2));
130    opcodes.insert(0x5b, new_opcode("JUMPDEST", 0, 0, 1));
131
132    // logging
133    opcodes.insert(0xa0, new_opcode("LOG0", 2, 0, 375));
134    opcodes.insert(0xa1, new_opcode("LOG1", 3, 0, 750));
135    opcodes.insert(0xa2, new_opcode("LOG2", 4, 0, 1125));
136    opcodes.insert(0xa3, new_opcode("LOG3", 5, 0, 1500));
137    opcodes.insert(0xa4, new_opcode("LOG4", 6, 0, 1875));
138
139    // closures
140    opcodes.insert(0xf0, new_opcode("CREATE", 3, 1, 32000));
141    opcodes.insert(0xf1, new_opcode("CALL", 7, 1, 40));
142    opcodes.insert(0xf2, new_opcode("CALLCODE", 7, 1, 40));
143    opcodes.insert(0xf3, new_opcode("RETURN", 2, 0, 0));
144    opcodes.insert(0xf4, new_opcode("DELEGATECALL", 6, 0, 40));
145    opcodes.insert(0xff, new_opcode("SUICIDE", 1, 0, 0));
146
147    for i in 1..33 {
148        let name = format!("PUSH{}", i);
149        opcodes.insert(0x5f + i, new_opcode(&name, 0, 1, 3));
150    }
151
152    for i in 1..17 {
153        let name = format!("DUP{}", i);
154        opcodes.insert(0x7f + i, new_opcode(&name, i as u32, i as u32 + 1, 3));
155
156        let name = format!("SWAP{}", i);
157        opcodes.insert(0x8f + i, new_opcode(&name, i as u32 + 1, i as u32 + 1, 3));
158    }
159
160    opcodes
161}
162
163impl Stack {
164    // arithmetic
165    // TODO instead of [u8;32] converted to BigUint, use custom type uint256 that implements all
166    // the arithmetic
167    pub fn add(&mut self) -> Result<(), String> {
168        let b0 = BigUint::from_bytes_be(&self.pop()?[..]);
169        let b1 = BigUint::from_bytes_be(&self.pop()?[..]);
170        self.push_arbitrary(&(b0 + b1).to_bytes_be());
171        Ok(())
172    }
173    pub fn mul(&mut self) -> Result<(), String> {
174        let b0 = BigUint::from_bytes_be(&self.pop()?[..]);
175        let b1 = BigUint::from_bytes_be(&self.pop()?[..]);
176        self.push_arbitrary(&(b0 * b1).to_bytes_be());
177        Ok(())
178    }
179    pub fn sub(&mut self) -> Result<(), String> {
180        let b0 = BigUint::from_bytes_be(&self.pop()?[..]);
181        let b1 = BigUint::from_bytes_be(&self.pop()?[..]);
182        if b0 >= b1 {
183            self.push_arbitrary(&(b0 - b1).to_bytes_be());
184        } else {
185            // 2**256 TODO this will not be here hardcoded, there will be a custom type uint256
186            let max =
187                "115792089237316195423570985008687907853269984665640564039457584007913129639936"
188                    .parse::<BigUint>()
189                    .unwrap();
190            self.push_arbitrary(&(max + b0 - b1).to_bytes_be());
191        }
192        Ok(())
193    }
194    pub fn div(&mut self) -> Result<(), String> {
195        let b0 = BigUint::from_bytes_be(&self.pop()?[..]);
196        let b1 = BigUint::from_bytes_be(&self.pop()?[..]);
197        self.push_arbitrary(&(b0 / b1).to_bytes_be());
198        Ok(())
199    }
200    pub fn sdiv(&mut self) -> Result<(), String> {
201        Err("unimplemented".to_string())
202    }
203    pub fn modulus(&mut self) -> Result<(), String> {
204        let b0 = BigUint::from_bytes_be(&self.pop()?[..]);
205        let b1 = BigUint::from_bytes_be(&self.pop()?[..]);
206        self.push_arbitrary(&(b0 % b1).to_bytes_be());
207        Ok(())
208    }
209    pub fn smod(&mut self) -> Result<(), String> {
210        Err("unimplemented".to_string())
211    }
212    pub fn add_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 mul_mod(&mut self) -> Result<(), String> {
220        let b0 = BigUint::from_bytes_be(&self.pop()?[..]);
221        let b1 = BigUint::from_bytes_be(&self.pop()?[..]);
222        let b2 = BigUint::from_bytes_be(&self.pop()?[..]);
223        self.push_arbitrary(&(b0 * b1 % b2).to_bytes_be());
224        Ok(())
225    }
226    pub fn exp(&mut self) -> Result<(), String> {
227        let b = BigUint::from_bytes_be(&self.pop()?[..]);
228        let e = BigUint::from_bytes_be(&self.pop()?[..]);
229
230        let mut r = "1".parse::<BigUint>().unwrap();
231        let zero = "0".parse::<BigUint>().unwrap();
232        let mut rem = e.clone();
233        let mut exp = b;
234        // 2**256 TODO this will not be here hardcoded, there will be a custom type uint256
235        let field =
236            "115792089237316195423570985008687907853269984665640564039457584007913129639936"
237                .parse::<BigUint>()
238                .unwrap();
239        while rem != zero {
240            if rem.bit(0) {
241                // is odd
242                r = r * exp.clone() % field.clone();
243            }
244            exp = exp.clone() * exp.clone();
245            rem >>= 1;
246        }
247        self.push_arbitrary(&r.to_bytes_be());
248
249        let n_bytes = &e.to_bytes_be().len();
250        let mut exp_fee = n_bytes * GEXPONENTBYTE;
251        exp_fee += EXP_SUPPLEMENTAL_GAS * n_bytes;
252        self.gas -= exp_fee as u64;
253        Ok(())
254    }
255
256    // boolean
257    pub fn lt(&mut self) -> Result<(), String> {
258        let a = BigUint::from_bytes_be(&self.pop()?[..]);
259        let b = BigUint::from_bytes_be(&self.pop()?[..]);
260        self.push(u256::usize_to_u256((a < b) as usize));
261        Ok(())
262    }
263    pub fn gt(&mut self) -> Result<(), String> {
264        let a = BigUint::from_bytes_be(&self.pop()?[..]);
265        let b = BigUint::from_bytes_be(&self.pop()?[..]);
266        self.push(u256::usize_to_u256((a > b) as usize));
267        Ok(())
268    }
269    pub fn eq(&mut self) -> Result<(), String> {
270        let a = BigUint::from_bytes_be(&self.pop()?[..]);
271        let b = BigUint::from_bytes_be(&self.pop()?[..]);
272        self.push(u256::usize_to_u256((a == b) as usize));
273        Ok(())
274    }
275    pub fn is_zero(&mut self) -> Result<(), String> {
276        let a = BigUint::from_bytes_be(&self.pop()?[..]);
277        self.push(u256::usize_to_u256(a.is_zero() as usize));
278        Ok(())
279    }
280    pub fn and(&mut self) -> Result<(), String> {
281        let a = BigUint::from_bytes_be(&self.pop()?[..]);
282        let b = BigUint::from_bytes_be(&self.pop()?[..]);
283        self.push_arbitrary(&(a & b).to_bytes_be());
284        Ok(())
285    }
286    pub fn or(&mut self) -> Result<(), String> {
287        let a = BigUint::from_bytes_be(&self.pop()?[..]);
288        let b = BigUint::from_bytes_be(&self.pop()?[..]);
289        self.push_arbitrary(&(a | b).to_bytes_be());
290        Ok(())
291    }
292    pub fn xor(&mut self) -> Result<(), String> {
293        let a = BigUint::from_bytes_be(&self.pop()?[..]);
294        let b = BigUint::from_bytes_be(&self.pop()?[..]);
295        self.push_arbitrary(&(a ^ b).to_bytes_be());
296        Ok(())
297    }
298    pub fn not(&mut self) -> Result<(), String> {
299        // 2**256-1 TODO this will not be here hardcoded, there will be a custom type uint256
300        let f = "115792089237316195423570985008687907853269984665640564039457584007913129639935"
301            .parse::<BigUint>()
302            .unwrap();
303
304        let a = BigUint::from_bytes_be(&self.pop()?[..]);
305        self.push_arbitrary(&(f - a).to_bytes_be());
306        Ok(())
307    }
308
309    // crypto
310
311    // contract context
312    pub fn calldata_load(&mut self, calldata: &[u8]) -> Result<(), String> {
313        let mut start = self.calldata_i;
314        if !self.stack.is_empty() {
315            start = u256::u256_to_u64(self.peek()?) as usize;
316        }
317        let l = calldata.len();
318        if start > l {
319            start = l;
320        }
321        let mut end = start + self.calldata_size;
322        if end > l {
323            end = l;
324        }
325        self.put_arbitrary(&calldata[start..end]);
326        self.calldata_i += self.calldata_size;
327        Ok(())
328    }
329    pub fn calldata_size(&mut self, calldata: &[u8]) {
330        self.calldata_size = calldata.len();
331        self.push(u256::usize_to_u256(self.calldata_size));
332    }
333    fn spend_gas_data_copy(&mut self, length: usize) {
334        let length32 = upper_multiple_of_32(length);
335        self.gas -= ((GCOPY * length32) / 32) as u64;
336    }
337    pub fn code_copy(&mut self, code: &[u8]) -> Result<(), String> {
338        let dest_offset = u256::u256_to_u64(self.pop()?) as usize;
339        let offset = u256::u256_to_u64(self.pop()?) as usize;
340        let length = u256::u256_to_u64(self.pop()?) as usize;
341
342        self.extend_mem(dest_offset, length);
343        self.spend_gas_data_copy(length);
344
345        for i in 0..length {
346            if offset + i < code.len() {
347                self.mem[dest_offset + i] = code[offset + i];
348            } else {
349                self.mem[dest_offset + i] = 0;
350            }
351        }
352        // self.mem[dest_offset..dest_offset+length] =
353        Ok(())
354    }
355
356    // blockchain context
357
358    // storage and execution
359    pub fn extend_mem(&mut self, start: usize, size: usize) {
360        if size <= self.mem.len() || start + size <= self.mem.len() {
361            return;
362        }
363        let old_size = self.mem.len() / 32;
364        let new_size = upper_multiple_of_32(start + size) / 32;
365        let old_total_fee = old_size * GMEMORY + old_size.pow(2) / GQUADRATICMEMDENOM;
366        let new_total_fee = new_size * GMEMORY + new_size.pow(2) / GQUADRATICMEMDENOM;
367        let mem_fee = new_total_fee - old_total_fee;
368        self.gas -= mem_fee as u64;
369        let mut new_bytes: Vec<u8> = vec![0; (new_size - old_size) * 32];
370        self.mem.append(&mut new_bytes);
371    }
372    pub fn mload(&mut self) -> Result<(), String> {
373        let pos = u256::u256_to_u64(self.pop()?) as usize;
374        self.extend_mem(pos as usize, 32);
375        let mem32 = self.mem[pos..pos + 32].to_vec();
376        self.push_arbitrary(&mem32);
377        Ok(())
378    }
379    pub fn mstore(&mut self) -> Result<(), String> {
380        let pos = u256::u256_to_u64(self.pop()?);
381        let val = self.pop()?;
382        self.extend_mem(pos as usize, 32);
383
384        self.mem[pos as usize..].copy_from_slice(&val);
385        Ok(())
386    }
387    pub fn sstore(&mut self) -> Result<(), String> {
388        // https://eips.ethereum.org/EIPS/eip-3529
389        // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1283.md
390        // 1. If current value equals new value (this is a no-op), 200 gas is deducted.
391        // 2. If current value does not equal new value
392        //   2.1. If original value equals current value (this storage slot has not been changed by the current execution context)
393        //     2.1.1. If original value is 0, 20000 gas is deducted.
394        // 	   2.1.2. Otherwise, 5000 gas is deducted. If new value is 0, add 15000 gas to refund counter.
395        // 	2.2. If original value does not equal current value (this storage slot is dirty), 200 gas is deducted. Apply both of the following clauses.
396        // 	  2.2.1. If original value is not 0
397        //       2.2.1.1. If current value is 0 (also means that new value is not 0), remove 15000 gas from refund counter. We can prove that refund counter will never go below 0.
398        //       2.2.1.2. If new value is 0 (also means that current value is not 0), add 15000 gas to refund counter.
399        // 	  2.2.2. If original value equals new value (this storage slot is reset)
400        //       2.2.2.1. If original value is 0, add 19800 gas to refund counter.
401        // 	     2.2.2.2. Otherwise, add 4800 gas to refund counter.
402
403        let empty: Vec<u8> = Vec::new();
404        let key = self.pop()?;
405        let value = self.pop()?;
406        let original = match self.storage_committed.get(&key) {
407            Some(v) => v.clone(),
408            None => empty.clone(),
409        };
410        let current = match self.storage.get(&key) {
411            Some(v) => v.clone(),
412            None => {
413                self.gas -= 2100;
414                empty.clone()
415            }
416        };
417
418        if current == value {
419            self.gas -= NETSSTORENOOPGAS;
420            return Ok(());
421        }
422        if original == current {
423            if original.is_empty() {
424                self.gas -= NETSSTOREINITGAS;
425                return Ok(());
426            }
427            if value.is_empty() {
428                self.gas += NETSSTORECLEARREFUND;
429            }
430            self.gas -= NETSSTORECLEANGAS;
431            return Ok(());
432        }
433        if !original.is_empty() {
434            if current.is_empty() {
435                self.gas -= NETSSTORECLEARREFUND;
436            } else if value.is_empty() {
437                self.gas += NETSSTORECLEARREFUND;
438            }
439        }
440        if original == value {
441            if original.is_empty() {
442                self.gas += NETSSTORERESETCLEARREFUND;
443            } else {
444                self.gas += NETSSTORERESETREFUND;
445            }
446        }
447        self.gas -= NETSSTOREDIRTYGAS;
448        self.storage.insert(key, value.to_vec());
449        Ok(())
450    }
451    pub fn jump(&mut self, code: &[u8]) -> Result<(), String> {
452        // TODO that jump destination is valid
453        let new_pc = u256::u256_to_u64(self.pop()?) as usize;
454        if !valid_dest(code, new_pc) {
455            return Err(format!("not valid dest: {:02x}", new_pc));
456        }
457        self.pc = new_pc;
458        Ok(())
459    }
460    pub fn jump_i(&mut self, code: &[u8]) -> Result<(), String> {
461        let new_pc = u256::u256_to_u64(self.pop()?) as usize;
462        if !valid_dest(code, new_pc) {
463            return Err(format!("not valid dest: {:02x}", new_pc));
464        }
465        if !self.stack.is_empty() {
466            let cond = u256::u256_to_u64(self.pop()?) as usize;
467            if cond != 0 {
468                self.pc = new_pc;
469            }
470        }
471        // let cont = self.pop();
472        // if cont {} // TODO depends on having impl Err in pop()
473        Ok(())
474    }
475    pub fn jump_dest(&mut self) -> Result<(), String> {
476        // TODO
477        Ok(())
478    }
479}
480
481fn valid_dest(code: &[u8], pos: usize) -> bool {
482    if code[pos] == 0x5b {
483        return true;
484    }
485    false
486}
487
488fn upper_multiple_of_32(n: usize) -> usize {
489    ((n - 1) | 31) + 1
490}