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