You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

271 lines
10 KiB

2 years ago
  1. use super::*;
  2. // Non-opcode gas prices
  3. const GDEFAULT: usize = 1;
  4. const GMEMORY: usize = 3;
  5. const GQUADRATICMEMDENOM: usize = 512; // 1 gas per 512 quadwords
  6. const GSTORAGEREFUND: usize = 15000;
  7. const GSTORAGEKILL: usize = 5000;
  8. const GSTORAGEMOD: usize = 5000;
  9. const GSTORAGEADD: usize = 20000;
  10. const GEXPONENTBYTE: usize = 10; // cost of EXP exponent per byte
  11. const GCOPY: usize = 3; // cost to copy one 32 byte word
  12. const GCONTRACTBYTE: usize = 200; // one byte of code in contract creation
  13. const GCALLVALUETRANSFER: usize = 9000; // non-zero-valued call
  14. const GLOGBYTE: usize = 8; // cost of a byte of logdata
  15. const GTXCOST: usize = 21000; // TX BASE GAS COST
  16. const GTXDATAZERO: usize = 4; // TX DATA ZERO BYTE GAS COST
  17. const GTXDATANONZERO: usize = 68; // TX DATA NON ZERO BYTE GAS COST
  18. const GSHA3WORD: usize = 6; // Cost of SHA3 per word
  19. const GSHA256BASE: usize = 60; // Base c of SHA256
  20. const GSHA256WORD: usize = 12; // Cost of SHA256 per word
  21. const GRIPEMD160BASE: usize = 600; // Base cost of RIPEMD160
  22. const GRIPEMD160WORD: usize = 120; // Cost of RIPEMD160 per word
  23. const GIDENTITYBASE: usize = 15; // Base cost of indentity
  24. const GIDENTITYWORD: usize = 3; // Cost of identity per word
  25. const GECRECOVER: usize = 3000; // Cost of ecrecover op
  26. const GSTIPEND: usize = 2300;
  27. const GCALLNEWACCOUNT: usize = 25000;
  28. const GSUICIDEREFUND: usize = 24000;
  29. pub struct Opcode {
  30. pub name: String,
  31. pub ins: u32,
  32. pub outs: u32,
  33. pub gas: u64,
  34. // operation: fn(),
  35. }
  36. pub fn new_opcode(name: &str, ins: u32, outs: u32, gas: u64) -> Opcode {
  37. Opcode {
  38. name: name.to_string(),
  39. ins,
  40. outs,
  41. gas,
  42. }
  43. }
  44. pub fn new_opcodes() -> HashMap<u8, Opcode> {
  45. let mut opcodes: HashMap<u8, Opcode> = HashMap::new();
  46. // arithmetic
  47. opcodes.insert(0x00, new_opcode("STOP", 0, 0, 0));
  48. opcodes.insert(0x01, new_opcode("ADD", 2, 1, 3));
  49. opcodes.insert(0x02, new_opcode("MUL", 2, 1, 5));
  50. opcodes.insert(0x03, new_opcode("SUB", 2, 1, 3));
  51. opcodes.insert(0x04, new_opcode("DIV", 2, 1, 5));
  52. opcodes.insert(0x05, new_opcode("SDIV", 2, 1, 5));
  53. opcodes.insert(0x06, new_opcode("MOD", 2, 1, 5));
  54. opcodes.insert(0x07, new_opcode("SMOD", 2, 1, 5));
  55. opcodes.insert(0x08, new_opcode("ADDMOD", 3, 1, 8));
  56. opcodes.insert(0x09, new_opcode("MULMOD", 3, 1, 8));
  57. opcodes.insert(0x0a, new_opcode("EXP", 2, 1, 10));
  58. opcodes.insert(0x0b, new_opcode("SIGNEXTEND", 2, 1, 5));
  59. // boolean
  60. opcodes.insert(0x10, new_opcode("LT", 2, 1, 3));
  61. opcodes.insert(0x11, new_opcode("GT", 2, 1, 3));
  62. opcodes.insert(0x12, new_opcode("SLT", 2, 1, 3));
  63. opcodes.insert(0x13, new_opcode("SGT", 2, 1, 3));
  64. opcodes.insert(0x14, new_opcode("EQ", 2, 1, 3));
  65. opcodes.insert(0x15, new_opcode("ISZERO", 1, 1, 3));
  66. opcodes.insert(0x16, new_opcode("AND", 2, 1, 3));
  67. opcodes.insert(0x17, new_opcode("OR", 2, 1, 3));
  68. opcodes.insert(0x18, new_opcode("XOR", 2, 1, 3));
  69. opcodes.insert(0x19, new_opcode("NOT", 1, 1, 3));
  70. opcodes.insert(0x1a, new_opcode("BYTE", 2, 1, 3));
  71. // crypto
  72. opcodes.insert(0x20, new_opcode("SHA3", 2, 1, 30));
  73. // contract context
  74. opcodes.insert(0x30, new_opcode("ADDRESS", 0, 1, 2));
  75. opcodes.insert(0x31, new_opcode("BALANCE", 1, 1, 20));
  76. opcodes.insert(0x32, new_opcode("ORIGIN", 0, 1, 2));
  77. opcodes.insert(0x33, new_opcode("CALLER", 0, 1, 2));
  78. opcodes.insert(0x34, new_opcode("CALLVALUE", 0, 1, 2));
  79. opcodes.insert(0x35, new_opcode("CALLDATALOAD", 1, 1, 3));
  80. opcodes.insert(0x36, new_opcode("CALLDATASIZE", 0, 1, 2));
  81. opcodes.insert(0x37, new_opcode("CALLDATACOPY", 3, 0, 3));
  82. opcodes.insert(0x38, new_opcode("CODESIZE", 0, 1, 2));
  83. opcodes.insert(0x39, new_opcode("CODECOPY", 3, 0, 3));
  84. opcodes.insert(0x3a, new_opcode("GASPRICE", 0, 1, 2));
  85. opcodes.insert(0x3b, new_opcode("EXTCODESIZE", 1, 1, 20));
  86. opcodes.insert(0x3c, new_opcode("EXTCODECOPY", 4, 0, 20));
  87. // blockchain context
  88. opcodes.insert(0x40, new_opcode("BLOCKHASH", 1, 1, 20));
  89. opcodes.insert(0x41, new_opcode("COINBASE", 0, 1, 2));
  90. opcodes.insert(0x42, new_opcode("TIMESTAMP", 0, 1, 2));
  91. opcodes.insert(0x43, new_opcode("NUMBER", 0, 1, 2));
  92. opcodes.insert(0x44, new_opcode("DIFFICULTY", 0, 1, 2));
  93. opcodes.insert(0x45, new_opcode("GASLIMIT", 0, 1, 2));
  94. // storage and execution
  95. opcodes.insert(0x50, new_opcode("POP", 1, 0, 2));
  96. opcodes.insert(0x51, new_opcode("MLOAD", 1, 1, 3));
  97. opcodes.insert(0x52, new_opcode("MSTORE", 2, 0, 3));
  98. opcodes.insert(0x53, new_opcode("MSTORE8", 2, 0, 3));
  99. opcodes.insert(0x54, new_opcode("SLOAD", 1, 1, 50));
  100. opcodes.insert(0x55, new_opcode("SSTORE", 2, 0, 0));
  101. opcodes.insert(0x56, new_opcode("JUMP", 1, 0, 8));
  102. opcodes.insert(0x57, new_opcode("JUMPI", 2, 0, 10));
  103. opcodes.insert(0x58, new_opcode("PC", 0, 1, 2));
  104. opcodes.insert(0x59, new_opcode("MSIZE", 0, 1, 2));
  105. opcodes.insert(0x5a, new_opcode("GAS", 0, 1, 2));
  106. opcodes.insert(0x5b, new_opcode("JUMPDEST", 0, 0, 1));
  107. // logging
  108. opcodes.insert(0xa0, new_opcode("LOG0", 2, 0, 375));
  109. opcodes.insert(0xa1, new_opcode("LOG1", 3, 0, 750));
  110. opcodes.insert(0xa2, new_opcode("LOG2", 4, 0, 1125));
  111. opcodes.insert(0xa3, new_opcode("LOG3", 5, 0, 1500));
  112. opcodes.insert(0xa4, new_opcode("LOG4", 6, 0, 1875));
  113. // closures
  114. opcodes.insert(0xf0, new_opcode("CREATE", 3, 1, 32000));
  115. opcodes.insert(0xf1, new_opcode("CALL", 7, 1, 40));
  116. opcodes.insert(0xf2, new_opcode("CALLCODE", 7, 1, 40));
  117. opcodes.insert(0xf3, new_opcode("RETURN", 2, 0, 0));
  118. opcodes.insert(0xf4, new_opcode("DELEGATECALL", 6, 0, 40));
  119. opcodes.insert(0xff, new_opcode("SUICIDE", 1, 0, 0));
  120. for i in 1..33 {
  121. let name = format!("PUSH{}", i);
  122. opcodes.insert(0x5f + i, new_opcode(&name, 0, 1, 3));
  123. }
  124. for i in 1..17 {
  125. let name = format!("DUP{}", i);
  126. opcodes.insert(0x7f + i, new_opcode(&name, i as u32, i as u32 + 1, 3));
  127. let name = format!("SWAP{}", i);
  128. opcodes.insert(0x8f + i, new_opcode(&name, i as u32 + 1, i as u32 + 1, 3));
  129. }
  130. opcodes
  131. }
  132. impl Stack {
  133. // arithmetic
  134. // TODO instead of [u8;32] converted to BigUint, use custom type uint256 that implements all
  135. // the arithmetic
  136. pub fn add(&mut self) {
  137. let b0 = BigUint::from_bytes_be(&self.pop()[..]);
  138. let b1 = BigUint::from_bytes_be(&self.pop()[..]);
  139. self.push_arbitrary(&(b0 + b1).to_bytes_be());
  140. }
  141. pub fn mul(&mut self) {
  142. let b0 = BigUint::from_bytes_be(&self.pop()[..]);
  143. let b1 = BigUint::from_bytes_be(&self.pop()[..]);
  144. self.push_arbitrary(&(b0 * b1).to_bytes_be());
  145. }
  146. pub fn sub(&mut self) {
  147. let b0 = BigUint::from_bytes_be(&self.pop()[..]);
  148. let b1 = BigUint::from_bytes_be(&self.pop()[..]);
  149. if b0 >= b1 {
  150. self.push_arbitrary(&(b0 - b1).to_bytes_be());
  151. } else {
  152. // 2**256
  153. let max =
  154. "115792089237316195423570985008687907853269984665640564039457584007913129639936"
  155. .parse::<BigUint>()
  156. .unwrap();
  157. self.push_arbitrary(&(max + b0 - b1).to_bytes_be());
  158. }
  159. }
  160. pub fn div(&mut self) {
  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. }
  165. pub fn sdiv(&mut self) {
  166. panic!("unimplemented");
  167. }
  168. pub fn modulus(&mut self) {
  169. let b0 = BigUint::from_bytes_be(&self.pop()[..]);
  170. let b1 = BigUint::from_bytes_be(&self.pop()[..]);
  171. self.push_arbitrary(&(b0 % b1).to_bytes_be());
  172. }
  173. pub fn smod(&mut self) {
  174. panic!("unimplemented");
  175. }
  176. pub fn add_mod(&mut self) {
  177. let b0 = BigUint::from_bytes_be(&self.pop()[..]);
  178. let b1 = BigUint::from_bytes_be(&self.pop()[..]);
  179. let b2 = BigUint::from_bytes_be(&self.pop()[..]);
  180. self.push_arbitrary(&(b0 + b1 % b2).to_bytes_be());
  181. }
  182. pub fn mul_mod(&mut self) {
  183. let b0 = BigUint::from_bytes_be(&self.pop()[..]);
  184. let b1 = BigUint::from_bytes_be(&self.pop()[..]);
  185. let b2 = BigUint::from_bytes_be(&self.pop()[..]);
  186. self.push_arbitrary(&(b0 * b1 % b2).to_bytes_be());
  187. }
  188. pub fn exp(&mut self) {
  189. panic!("unimplemented");
  190. // let b0 = BigUint::from_bytes_be(&self.pop()[..]);
  191. // let b1 = BigUint::from_bytes_be(&self.pop()[..]);
  192. // self.push_arbitrary(&(pow(b0, b1)).to_bytes_be());
  193. }
  194. // boolean
  195. // crypto
  196. // contract context
  197. pub fn calldata_load(&mut self, calldata: &[u8]) {
  198. self.put_arbitrary(&calldata[self.calldata_i..self.calldata_i + 32]);
  199. self.calldata_i += 32;
  200. }
  201. // blockchain context
  202. // storage and execution
  203. pub fn extend_mem(&mut self, start: usize, size: usize) {
  204. if size <= self.mem.len() || start + size <= self.mem.len() {
  205. return;
  206. }
  207. let old_size = self.mem.len() / 32;
  208. let new_size = (start + size) / 32;
  209. let old_total_fee = old_size * GMEMORY + old_size.pow(2) / GQUADRATICMEMDENOM;
  210. let new_total_fee = new_size * GMEMORY + new_size.pow(2) / GQUADRATICMEMDENOM;
  211. let mem_fee = new_total_fee - old_total_fee;
  212. self.gas -= mem_fee as u64;
  213. let mut new_bytes: Vec<u8> = vec![0; size];
  214. self.mem.append(&mut new_bytes);
  215. }
  216. pub fn mload(&mut self) {
  217. let pos = u256_to_u64(self.pop()) as usize;
  218. self.extend_mem(pos as usize, 32);
  219. let mem32 = self.mem[pos..pos + 32].to_vec();
  220. self.push_arbitrary(&mem32);
  221. }
  222. pub fn mstore(&mut self) {
  223. let pos = u256_to_u64(self.pop());
  224. let val = self.pop();
  225. self.extend_mem(pos as usize, 32);
  226. self.mem[pos as usize..].copy_from_slice(&val);
  227. }
  228. pub fn jump(&mut self) {
  229. // TODO that jump destination is valid
  230. self.pc = u256_to_u64(self.pop()) as usize;
  231. }
  232. pub fn jump_i(&mut self) {
  233. let new_pc = u256_to_u64(self.pop()) as usize;
  234. if !self.stack.is_empty() {
  235. let cond = u256_to_u64(self.pop()) as usize;
  236. if cond != 0 {
  237. self.pc = new_pc;
  238. }
  239. }
  240. // let cont = self.pop();
  241. // if cont {} // TODO depends on having impl Err in pop()
  242. }
  243. pub fn jump_dest(&mut self) {
  244. // TODO
  245. }
  246. }