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) {
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 }
162 pub fn mul(&mut self) {
163 let b0 = BigUint::from_bytes_be(&self.pop()[..]);
164 let b1 = BigUint::from_bytes_be(&self.pop()[..]);
165 self.push_arbitrary(&(b0 * b1).to_bytes_be());
166 }
167 pub fn sub(&mut self) {
168 let b0 = BigUint::from_bytes_be(&self.pop()[..]);
169 let b1 = BigUint::from_bytes_be(&self.pop()[..]);
170 if b0 >= b1 {
171 self.push_arbitrary(&(b0 - b1).to_bytes_be());
172 } else {
173 // 2**256 TODO this will not be here hardcoded, there will be a custom type uint256
174 let max =
175 "115792089237316195423570985008687907853269984665640564039457584007913129639936"
176 .parse::<BigUint>()
177 .unwrap();
178 self.push_arbitrary(&(max + b0 - b1).to_bytes_be());
179 }
180 }
181 pub fn div(&mut self) {
182 let b0 = BigUint::from_bytes_be(&self.pop()[..]);
183 let b1 = BigUint::from_bytes_be(&self.pop()[..]);
184 self.push_arbitrary(&(b0 / b1).to_bytes_be());
185 }
186 pub fn sdiv(&mut self) {
187 panic!("unimplemented");
188 }
189 pub fn modulus(&mut self) {
190 let b0 = BigUint::from_bytes_be(&self.pop()[..]);
191 let b1 = BigUint::from_bytes_be(&self.pop()[..]);
192 self.push_arbitrary(&(b0 % b1).to_bytes_be());
193 }
194 pub fn smod(&mut self) {
195 panic!("unimplemented");
196 }
197 pub fn add_mod(&mut self) {
198 let b0 = BigUint::from_bytes_be(&self.pop()[..]);
199 let b1 = BigUint::from_bytes_be(&self.pop()[..]);
200 let b2 = BigUint::from_bytes_be(&self.pop()[..]);
201 self.push_arbitrary(&(b0 + b1 % b2).to_bytes_be());
202 }
203 pub fn mul_mod(&mut self) {
204 let b0 = BigUint::from_bytes_be(&self.pop()[..]);
205 let b1 = BigUint::from_bytes_be(&self.pop()[..]);
206 let b2 = BigUint::from_bytes_be(&self.pop()[..]);
207 self.push_arbitrary(&(b0 * b1 % b2).to_bytes_be());
208 }
209 pub fn exp(&mut self) {
210 let b = BigUint::from_bytes_be(&self.pop()[..]);
211 let e = BigUint::from_bytes_be(&self.pop()[..]);
212
213 let mut r = "1".parse::<BigUint>().unwrap();
214 let zero = "0".parse::<BigUint>().unwrap();
215 let mut rem = e.clone();
216 let mut exp = b;
217 // 2**256 TODO this will not be here hardcoded, there will be a custom type uint256
218 let field =
219 "115792089237316195423570985008687907853269984665640564039457584007913129639936"
220 .parse::<BigUint>()
221 .unwrap();
222 while rem != zero {
223 if rem.bit(0) {
224 // is odd
225 r = r * exp.clone() % field.clone();
226 }
227 exp = exp.clone() * exp.clone();
228 rem >>= 1;
229 }
230 self.push_arbitrary(&r.to_bytes_be());
231
232 let n_bytes = &e.to_bytes_be().len();
233 let mut exp_fee = n_bytes * GEXPONENTBYTE;
234 exp_fee += EXP_SUPPLEMENTAL_GAS * n_bytes;
235 self.gas -= exp_fee as u64;
236 }
237
238 // boolean
239 // crypto
240
241 // contract context
242 pub fn calldata_load(&mut self, calldata: &[u8]) {
243 self.put_arbitrary(&calldata[self.calldata_i..self.calldata_i + self.calldata_size]);
244 self.calldata_i += self.calldata_size;
245 }
246 pub fn calldata_size(&mut self, calldata: &[u8]) {
247 self.calldata_size = calldata.len();
248 self.push(u256::usize_to_u256(self.calldata_size));
249 }
250 fn spend_gas_data_copy(&mut self, length: usize) {
251 let length32 = upper_multiple_of_32(length);
252 self.gas -= ((GCOPY * length32) / 32) as u64;
253 }
254 pub fn code_copy(&mut self, code: &[u8]) {
255 let dest_offset = u256::u256_to_u64(self.pop()) as usize;
256 let offset = u256::u256_to_u64(self.pop()) as usize;
257 let length = u256::u256_to_u64(self.pop()) as usize;
258
259 self.extend_mem(dest_offset, length);
260 self.spend_gas_data_copy(length);
261
262 for i in 0..length {
263 if offset + i < code.len() {
264 self.mem[dest_offset + i] = code[offset + i];
265 } else {
266 self.mem[dest_offset + i] = 0;
267 }
268 }
269 // self.mem[dest_offset..dest_offset+length] =
270 }
271
272 // blockchain context
273
274 // storage and execution
275 pub fn extend_mem(&mut self, start: usize, size: usize) {
276 if size <= self.mem.len() || start + size <= self.mem.len() {
277 return;
278 }
279 let old_size = self.mem.len() / 32;
280 let new_size = upper_multiple_of_32(start + size) / 32;
281 let old_total_fee = old_size * GMEMORY + old_size.pow(2) / GQUADRATICMEMDENOM;
282 let new_total_fee = new_size * GMEMORY + new_size.pow(2) / GQUADRATICMEMDENOM;
283 let mem_fee = new_total_fee - old_total_fee;
284 self.gas -= mem_fee as u64;
285 let mut new_bytes: Vec<u8> = vec![0; (new_size - old_size) * 32];
286 self.mem.append(&mut new_bytes);
287 }
288 pub fn mload(&mut self) {
289 let pos = u256::u256_to_u64(self.pop()) as usize;
290 self.extend_mem(pos as usize, 32);
291 let mem32 = self.mem[pos..pos + 32].to_vec();
292 self.push_arbitrary(&mem32);
293 }
294 pub fn mstore(&mut self) {
295 let pos = u256::u256_to_u64(self.pop());
296 let val = self.pop();
297 self.extend_mem(pos as usize, 32);
298
299 self.mem[pos as usize..].copy_from_slice(&val);
300 }
301 pub fn sstore(&mut self) {
302 let key = self.pop();
303 let value = self.pop();
304 if self.storage.contains_key(&key) {
305 let old_value = self.storage.get(&key).unwrap();
306 if &value.to_vec() == old_value {
307 // if the new value is the same as the old one, do not set
308 return;
309 }
310 // if value (from self.pop()) does not exist in the stack, is a STORAGEKILL TODO
311 println!("mingas {:?}", GSTORAGEMOD);
312 self.gas -= GSTORAGEMOD as u64;
313 } else {
314 // if value does not exist, substract gas for the addition
315 println!("mingas {:?}", GSTORAGEADD);
316 self.gas -= GSTORAGEADD as u64;
317 }
318 println!(
319 "insert {:?} - {:?}",
320 vec_u8_to_hex(key.to_vec()),
321 vec_u8_to_hex(value.to_vec())
322 );
323 self.storage.insert(key, value.to_vec());
324 }
325 pub fn jump(&mut self) {
326 // TODO that jump destination is valid
327 self.pc = u256::u256_to_u64(self.pop()) as usize;
328 }
329 pub fn jump_i(&mut self) {
330 let new_pc = u256::u256_to_u64(self.pop()) as usize;
331 if !self.stack.is_empty() {
332 let cond = u256::u256_to_u64(self.pop()) as usize;
333 if cond != 0 {
334 self.pc = new_pc;
335 }
336 }
337 // let cont = self.pop();
338 // if cont {} // TODO depends on having impl Err in pop()
339 }
340 pub fn jump_dest(&mut self) {
341 // TODO
342 }
343}
344
345fn upper_multiple_of_32(n: usize) -> usize {
346 ((n - 1) | 31) + 1
347}