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 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}