From 198236e029661c142b5478442d5b7eee8c279c5d Mon Sep 17 00:00:00 2001 From: arnaucube Date: Wed, 15 Sep 2021 23:21:35 +0200 Subject: [PATCH] Add errors handling --- README.md | 2 - src/lib.rs | 67 ++++++++------- src/opcodes.rs | 207 +++++++++++++++++++++++++---------------------- src/u256.rs | 19 +++++ tests/execute.rs | 48 +++++------ 5 files changed, 187 insertions(+), 156 deletions(-) create mode 100644 src/u256.rs diff --git a/README.md b/README.md index b54555c..fa73c20 100644 --- a/README.md +++ b/README.md @@ -2,5 +2,3 @@ EVM ([Ethereum Virtual Machine](https://ethereum.org/en/developers/docs/evm/)) implementation from scratch in Rust. *This is a repo done to get familiar with the EVM, do not use.* - -Opcodes implemented: 83/130. diff --git a/src/lib.rs b/src/lib.rs index 0d7d937..b0a33e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -76,14 +76,19 @@ impl Stack { let l = self.stack.len(); self.stack[l - 1] = d; } - pub fn pop(&mut self) -> [u8; 32] { + pub fn pop(&mut self) -> Result<[u8; 32], String> { match self.stack.pop() { - Some(x) => x, - None => panic!("pop err"), + Some(x) => Ok(x), + None => Err(format!("pop err")), // WIP } } - pub fn execute(&mut self, code: &[u8], calldata: &[u8], debug: bool) -> Vec { + pub fn execute( + &mut self, + code: &[u8], + calldata: &[u8], + debug: bool, + ) -> Result, String> { self.pc = 0; self.calldata_i = 0; let l = code.len(); @@ -91,7 +96,7 @@ impl Stack { while self.pc < l { let opcode = code[self.pc]; if !self.opcodes.contains_key(&opcode) { - panic!("invalid opcode {:x}", opcode); + return Err(format!("invalid opcode {:x}", opcode)); } if debug { @@ -113,20 +118,20 @@ impl Stack { match opcode { 0x00 => { println!("0x00: STOP"); - return Vec::new(); + return Ok(Vec::new()); } - 0x01 => self.add(), - 0x02 => self.mul(), - 0x03 => self.sub(), - 0x04 => self.div(), - 0x05 => self.sdiv(), - 0x06 => self.modulus(), - 0x07 => self.smod(), - 0x08 => self.add_mod(), - 0x09 => self.mul_mod(), - 0x0a => self.exp(), + 0x01 => self.add()?, + 0x02 => self.mul()?, + 0x03 => self.sub()?, + 0x04 => self.div()?, + 0x05 => self.sdiv()?, + 0x06 => self.modulus()?, + 0x07 => self.smod()?, + 0x08 => self.add_mod()?, + 0x09 => self.mul_mod()?, + 0x0a => self.exp()?, // 0x0b => self.sign_extend(), - _ => panic!("unimplemented {:x}", opcode), + _ => return Err(format!("unimplemented {:x}", opcode)), } self.pc += 1; } @@ -134,21 +139,21 @@ impl Stack { match opcode { 0x35 => self.calldata_load(&calldata), 0x36 => self.calldata_size(&calldata), - 0x39 => self.code_copy(&code), - _ => panic!("unimplemented {:x}", opcode), + 0x39 => self.code_copy(&code)?, + _ => return Err(format!("unimplemented {:x}", opcode)), } self.pc += 1; } 0x50 => { self.pc += 1; match opcode { - 0x51 => self.mload(), - 0x52 => self.mstore(), - 0x55 => self.sstore(), - 0x56 => self.jump(), - 0x57 => self.jump_i(), - 0x5b => self.jump_dest(), - _ => panic!("unimplemented {:x}", opcode), + 0x51 => self.mload()?, + 0x52 => self.mstore()?, + 0x55 => self.sstore()?, + 0x56 => self.jump()?, + 0x57 => self.jump_i()?, + 0x5b => self.jump_dest()?, + _ => return Err(format!("unimplemented {:x}", opcode)), } } 0x60 | 0x70 => { @@ -181,18 +186,18 @@ impl Stack { } 0xf0 => { if opcode == 0xf3 { - let pos_to_return = u256::u256_to_u64(self.pop()) as usize; - let len_to_return = u256::u256_to_u64(self.pop()) as usize; - return self.mem[pos_to_return..pos_to_return + len_to_return].to_vec(); + let pos_to_return = u256::u256_to_u64(self.pop()?) as usize; + let len_to_return = u256::u256_to_u64(self.pop()?) as usize; + return Ok(self.mem[pos_to_return..pos_to_return + len_to_return].to_vec()); } } _ => { - return panic!("unimplemented {:x}", opcode); + return Err(format!("unimplemented {:x}", opcode)); } } self.gas -= self.opcodes.get(&opcode).unwrap().gas; } - Vec::new() + Ok(Vec::new()) } } pub fn vec_u8_to_hex(bytes: Vec) -> String { diff --git a/src/opcodes.rs b/src/opcodes.rs index 5e0b4c3..93aa7a1 100644 --- a/src/opcodes.rs +++ b/src/opcodes.rs @@ -58,81 +58,81 @@ pub fn new_opcodes() -> HashMap { opcodes.insert(0x02, new_opcode("MUL", 2, 1, 5)); opcodes.insert(0x03, new_opcode("SUB", 2, 1, 3)); opcodes.insert(0x04, new_opcode("DIV", 2, 1, 5)); - // opcodes.insert(0x05, new_opcode("SDIV", 2, 1, 5)); + opcodes.insert(0x05, new_opcode("SDIV", 2, 1, 5)); opcodes.insert(0x06, new_opcode("MOD", 2, 1, 5)); - // opcodes.insert(0x07, new_opcode("SMOD", 2, 1, 5)); + opcodes.insert(0x07, new_opcode("SMOD", 2, 1, 5)); opcodes.insert(0x08, new_opcode("ADDMOD", 3, 1, 8)); opcodes.insert(0x09, new_opcode("MULMOD", 3, 1, 8)); opcodes.insert(0x0a, new_opcode("EXP", 2, 1, 10)); - // opcodes.insert(0x0b, new_opcode("SIGNEXTEND", 2, 1, 5)); + opcodes.insert(0x0b, new_opcode("SIGNEXTEND", 2, 1, 5)); // boolean - // opcodes.insert(0x10, new_opcode("LT", 2, 1, 3)); - // opcodes.insert(0x11, new_opcode("GT", 2, 1, 3)); - // opcodes.insert(0x12, new_opcode("SLT", 2, 1, 3)); - // opcodes.insert(0x13, new_opcode("SGT", 2, 1, 3)); - // opcodes.insert(0x14, new_opcode("EQ", 2, 1, 3)); - // opcodes.insert(0x15, new_opcode("ISZERO", 1, 1, 3)); - // opcodes.insert(0x16, new_opcode("AND", 2, 1, 3)); - // opcodes.insert(0x17, new_opcode("OR", 2, 1, 3)); - // opcodes.insert(0x18, new_opcode("XOR", 2, 1, 3)); - // opcodes.insert(0x19, new_opcode("NOT", 1, 1, 3)); - // opcodes.insert(0x1a, new_opcode("BYTE", 2, 1, 3)); + opcodes.insert(0x10, new_opcode("LT", 2, 1, 3)); + opcodes.insert(0x11, new_opcode("GT", 2, 1, 3)); + opcodes.insert(0x12, new_opcode("SLT", 2, 1, 3)); + opcodes.insert(0x13, new_opcode("SGT", 2, 1, 3)); + opcodes.insert(0x14, new_opcode("EQ", 2, 1, 3)); + opcodes.insert(0x15, new_opcode("ISZERO", 1, 1, 3)); + opcodes.insert(0x16, new_opcode("AND", 2, 1, 3)); + opcodes.insert(0x17, new_opcode("OR", 2, 1, 3)); + opcodes.insert(0x18, new_opcode("XOR", 2, 1, 3)); + opcodes.insert(0x19, new_opcode("NOT", 1, 1, 3)); + opcodes.insert(0x1a, new_opcode("BYTE", 2, 1, 3)); // crypto - // opcodes.insert(0x20, new_opcode("SHA3", 2, 1, 30)); + opcodes.insert(0x20, new_opcode("SHA3", 2, 1, 30)); // contract context - // opcodes.insert(0x30, new_opcode("ADDRESS", 0, 1, 2)); - // opcodes.insert(0x31, new_opcode("BALANCE", 1, 1, 20)); - // opcodes.insert(0x32, new_opcode("ORIGIN", 0, 1, 2)); - // opcodes.insert(0x33, new_opcode("CALLER", 0, 1, 2)); - // opcodes.insert(0x34, new_opcode("CALLVALUE", 0, 1, 2)); + opcodes.insert(0x30, new_opcode("ADDRESS", 0, 1, 2)); + opcodes.insert(0x31, new_opcode("BALANCE", 1, 1, 20)); + opcodes.insert(0x32, new_opcode("ORIGIN", 0, 1, 2)); + opcodes.insert(0x33, new_opcode("CALLER", 0, 1, 2)); + opcodes.insert(0x34, new_opcode("CALLVALUE", 0, 1, 2)); opcodes.insert(0x35, new_opcode("CALLDATALOAD", 1, 1, 3)); opcodes.insert(0x36, new_opcode("CALLDATASIZE", 0, 1, 2)); - // opcodes.insert(0x37, new_opcode("CALLDATACOPY", 3, 0, 3)); - // opcodes.insert(0x38, new_opcode("CODESIZE", 0, 1, 2)); + opcodes.insert(0x37, new_opcode("CALLDATACOPY", 3, 0, 3)); + opcodes.insert(0x38, new_opcode("CODESIZE", 0, 1, 2)); opcodes.insert(0x39, new_opcode("CODECOPY", 3, 0, 3)); - // opcodes.insert(0x3a, new_opcode("GASPRICE", 0, 1, 2)); - // opcodes.insert(0x3b, new_opcode("EXTCODESIZE", 1, 1, 20)); - // opcodes.insert(0x3c, new_opcode("EXTCODECOPY", 4, 0, 20)); + opcodes.insert(0x3a, new_opcode("GASPRICE", 0, 1, 2)); + opcodes.insert(0x3b, new_opcode("EXTCODESIZE", 1, 1, 20)); + opcodes.insert(0x3c, new_opcode("EXTCODECOPY", 4, 0, 20)); // blockchain context - // opcodes.insert(0x40, new_opcode("BLOCKHASH", 1, 1, 20)); - // opcodes.insert(0x41, new_opcode("COINBASE", 0, 1, 2)); - // opcodes.insert(0x42, new_opcode("TIMESTAMP", 0, 1, 2)); - // opcodes.insert(0x43, new_opcode("NUMBER", 0, 1, 2)); - // opcodes.insert(0x44, new_opcode("DIFFICULTY", 0, 1, 2)); - // opcodes.insert(0x45, new_opcode("GASLIMIT", 0, 1, 2)); + opcodes.insert(0x40, new_opcode("BLOCKHASH", 1, 1, 20)); + opcodes.insert(0x41, new_opcode("COINBASE", 0, 1, 2)); + opcodes.insert(0x42, new_opcode("TIMESTAMP", 0, 1, 2)); + opcodes.insert(0x43, new_opcode("NUMBER", 0, 1, 2)); + opcodes.insert(0x44, new_opcode("DIFFICULTY", 0, 1, 2)); + opcodes.insert(0x45, new_opcode("GASLIMIT", 0, 1, 2)); // storage and execution - // opcodes.insert(0x50, new_opcode("POP", 1, 0, 2)); + opcodes.insert(0x50, new_opcode("POP", 1, 0, 2)); opcodes.insert(0x51, new_opcode("MLOAD", 1, 1, 3)); opcodes.insert(0x52, new_opcode("MSTORE", 2, 0, 3)); - // opcodes.insert(0x53, new_opcode("MSTORE8", 2, 0, 3)); - // opcodes.insert(0x54, new_opcode("SLOAD", 1, 1, 50)); + opcodes.insert(0x53, new_opcode("MSTORE8", 2, 0, 3)); + opcodes.insert(0x54, new_opcode("SLOAD", 1, 1, 50)); opcodes.insert(0x55, new_opcode("SSTORE", 2, 0, 0)); opcodes.insert(0x56, new_opcode("JUMP", 1, 0, 8)); opcodes.insert(0x57, new_opcode("JUMPI", 2, 0, 10)); - // opcodes.insert(0x58, new_opcode("PC", 0, 1, 2)); - // opcodes.insert(0x59, new_opcode("MSIZE", 0, 1, 2)); - // opcodes.insert(0x5a, new_opcode("GAS", 0, 1, 2)); + opcodes.insert(0x58, new_opcode("PC", 0, 1, 2)); + opcodes.insert(0x59, new_opcode("MSIZE", 0, 1, 2)); + opcodes.insert(0x5a, new_opcode("GAS", 0, 1, 2)); opcodes.insert(0x5b, new_opcode("JUMPDEST", 0, 0, 1)); // logging - // opcodes.insert(0xa0, new_opcode("LOG0", 2, 0, 375)); - // opcodes.insert(0xa1, new_opcode("LOG1", 3, 0, 750)); - // opcodes.insert(0xa2, new_opcode("LOG2", 4, 0, 1125)); - // opcodes.insert(0xa3, new_opcode("LOG3", 5, 0, 1500)); - // opcodes.insert(0xa4, new_opcode("LOG4", 6, 0, 1875)); + opcodes.insert(0xa0, new_opcode("LOG0", 2, 0, 375)); + opcodes.insert(0xa1, new_opcode("LOG1", 3, 0, 750)); + opcodes.insert(0xa2, new_opcode("LOG2", 4, 0, 1125)); + opcodes.insert(0xa3, new_opcode("LOG3", 5, 0, 1500)); + opcodes.insert(0xa4, new_opcode("LOG4", 6, 0, 1875)); // closures - // opcodes.insert(0xf0, new_opcode("CREATE", 3, 1, 32000)); - // opcodes.insert(0xf1, new_opcode("CALL", 7, 1, 40)); - // opcodes.insert(0xf2, new_opcode("CALLCODE", 7, 1, 40)); + opcodes.insert(0xf0, new_opcode("CREATE", 3, 1, 32000)); + opcodes.insert(0xf1, new_opcode("CALL", 7, 1, 40)); + opcodes.insert(0xf2, new_opcode("CALLCODE", 7, 1, 40)); opcodes.insert(0xf3, new_opcode("RETURN", 2, 0, 0)); - // opcodes.insert(0xf4, new_opcode("DELEGATECALL", 6, 0, 40)); - // opcodes.insert(0xff, new_opcode("SUICIDE", 1, 0, 0)); + opcodes.insert(0xf4, new_opcode("DELEGATECALL", 6, 0, 40)); + opcodes.insert(0xff, new_opcode("SUICIDE", 1, 0, 0)); for i in 1..33 { let name = format!("PUSH{}", i); @@ -154,19 +154,21 @@ impl Stack { // arithmetic // TODO instead of [u8;32] converted to BigUint, use custom type uint256 that implements all // the arithmetic - pub fn add(&mut self) { - let b0 = BigUint::from_bytes_be(&self.pop()[..]); - let b1 = BigUint::from_bytes_be(&self.pop()[..]); + pub fn add(&mut self) -> Result<(), String> { + let b0 = BigUint::from_bytes_be(&self.pop()?[..]); + let b1 = BigUint::from_bytes_be(&self.pop()?[..]); self.push_arbitrary(&(b0 + b1).to_bytes_be()); + Ok(()) } - pub fn mul(&mut self) { - let b0 = BigUint::from_bytes_be(&self.pop()[..]); - let b1 = BigUint::from_bytes_be(&self.pop()[..]); + pub fn mul(&mut self) -> Result<(), String> { + let b0 = BigUint::from_bytes_be(&self.pop()?[..]); + let b1 = BigUint::from_bytes_be(&self.pop()?[..]); self.push_arbitrary(&(b0 * b1).to_bytes_be()); + Ok(()) } - pub fn sub(&mut self) { - let b0 = BigUint::from_bytes_be(&self.pop()[..]); - let b1 = BigUint::from_bytes_be(&self.pop()[..]); + pub fn sub(&mut self) -> Result<(), String> { + let b0 = BigUint::from_bytes_be(&self.pop()?[..]); + let b1 = BigUint::from_bytes_be(&self.pop()?[..]); if b0 >= b1 { self.push_arbitrary(&(b0 - b1).to_bytes_be()); } else { @@ -177,38 +179,43 @@ impl Stack { .unwrap(); self.push_arbitrary(&(max + b0 - b1).to_bytes_be()); } + Ok(()) } - pub fn div(&mut self) { - let b0 = BigUint::from_bytes_be(&self.pop()[..]); - let b1 = BigUint::from_bytes_be(&self.pop()[..]); + pub fn div(&mut self) -> Result<(), String> { + let b0 = BigUint::from_bytes_be(&self.pop()?[..]); + let b1 = BigUint::from_bytes_be(&self.pop()?[..]); self.push_arbitrary(&(b0 / b1).to_bytes_be()); + Ok(()) } - pub fn sdiv(&mut self) { - panic!("unimplemented"); + pub fn sdiv(&mut self) -> Result<(), String> { + Err(format!("unimplemented")) } - pub fn modulus(&mut self) { - let b0 = BigUint::from_bytes_be(&self.pop()[..]); - let b1 = BigUint::from_bytes_be(&self.pop()[..]); + pub fn modulus(&mut self) -> Result<(), String> { + let b0 = BigUint::from_bytes_be(&self.pop()?[..]); + let b1 = BigUint::from_bytes_be(&self.pop()?[..]); self.push_arbitrary(&(b0 % b1).to_bytes_be()); + Ok(()) } - pub fn smod(&mut self) { - panic!("unimplemented"); + pub fn smod(&mut self) -> Result<(), String> { + Err(format!("unimplemented")) } - pub fn add_mod(&mut self) { - let b0 = BigUint::from_bytes_be(&self.pop()[..]); - let b1 = BigUint::from_bytes_be(&self.pop()[..]); - let b2 = BigUint::from_bytes_be(&self.pop()[..]); + pub fn add_mod(&mut self) -> Result<(), String> { + let b0 = BigUint::from_bytes_be(&self.pop()?[..]); + let b1 = BigUint::from_bytes_be(&self.pop()?[..]); + let b2 = BigUint::from_bytes_be(&self.pop()?[..]); self.push_arbitrary(&(b0 + b1 % b2).to_bytes_be()); + Ok(()) } - pub fn mul_mod(&mut self) { - let b0 = BigUint::from_bytes_be(&self.pop()[..]); - let b1 = BigUint::from_bytes_be(&self.pop()[..]); - let b2 = BigUint::from_bytes_be(&self.pop()[..]); + pub fn mul_mod(&mut self) -> Result<(), String> { + let b0 = BigUint::from_bytes_be(&self.pop()?[..]); + let b1 = BigUint::from_bytes_be(&self.pop()?[..]); + let b2 = BigUint::from_bytes_be(&self.pop()?[..]); self.push_arbitrary(&(b0 * b1 % b2).to_bytes_be()); + Ok(()) } - pub fn exp(&mut self) { - let b = BigUint::from_bytes_be(&self.pop()[..]); - let e = BigUint::from_bytes_be(&self.pop()[..]); + pub fn exp(&mut self) -> Result<(), String> { + let b = BigUint::from_bytes_be(&self.pop()?[..]); + let e = BigUint::from_bytes_be(&self.pop()?[..]); let mut r = "1".parse::().unwrap(); let zero = "0".parse::().unwrap(); @@ -233,6 +240,7 @@ impl Stack { let mut exp_fee = n_bytes * GEXPONENTBYTE; exp_fee += EXP_SUPPLEMENTAL_GAS * n_bytes; self.gas -= exp_fee as u64; + Ok(()) } // boolean @@ -251,10 +259,10 @@ impl Stack { let length32 = upper_multiple_of_32(length); self.gas -= ((GCOPY * length32) / 32) as u64; } - pub fn code_copy(&mut self, code: &[u8]) { - let dest_offset = u256::u256_to_u64(self.pop()) as usize; - let offset = u256::u256_to_u64(self.pop()) as usize; - let length = u256::u256_to_u64(self.pop()) as usize; + pub fn code_copy(&mut self, code: &[u8]) -> Result<(), String> { + let dest_offset = u256::u256_to_u64(self.pop()?) as usize; + let offset = u256::u256_to_u64(self.pop()?) as usize; + let length = u256::u256_to_u64(self.pop()?) as usize; self.extend_mem(dest_offset, length); self.spend_gas_data_copy(length); @@ -267,6 +275,7 @@ impl Stack { } } // self.mem[dest_offset..dest_offset+length] = + Ok(()) } // blockchain context @@ -285,27 +294,29 @@ impl Stack { let mut new_bytes: Vec = vec![0; (new_size - old_size) * 32]; self.mem.append(&mut new_bytes); } - pub fn mload(&mut self) { - let pos = u256::u256_to_u64(self.pop()) as usize; + pub fn mload(&mut self) -> Result<(), String> { + let pos = u256::u256_to_u64(self.pop()?) as usize; self.extend_mem(pos as usize, 32); let mem32 = self.mem[pos..pos + 32].to_vec(); self.push_arbitrary(&mem32); + Ok(()) } - pub fn mstore(&mut self) { - let pos = u256::u256_to_u64(self.pop()); - let val = self.pop(); + pub fn mstore(&mut self) -> Result<(), String> { + let pos = u256::u256_to_u64(self.pop()?); + let val = self.pop()?; self.extend_mem(pos as usize, 32); self.mem[pos as usize..].copy_from_slice(&val); + Ok(()) } - pub fn sstore(&mut self) { - let key = self.pop(); - let value = self.pop(); + pub fn sstore(&mut self) -> Result<(), String> { + let key = self.pop()?; + let value = self.pop()?; if self.storage.contains_key(&key) { let old_value = self.storage.get(&key).unwrap(); if &value.to_vec() == old_value { // if the new value is the same as the old one, do not set - return; + return Ok(()); } // if value (from self.pop()) does not exist in the stack, is a STORAGEKILL TODO println!("mingas {:?}", GSTORAGEMOD); @@ -321,24 +332,28 @@ impl Stack { vec_u8_to_hex(value.to_vec()) ); self.storage.insert(key, value.to_vec()); + Ok(()) } - pub fn jump(&mut self) { + pub fn jump(&mut self) -> Result<(), String> { // TODO that jump destination is valid - self.pc = u256::u256_to_u64(self.pop()) as usize; + self.pc = u256::u256_to_u64(self.pop()?) as usize; + Ok(()) } - pub fn jump_i(&mut self) { - let new_pc = u256::u256_to_u64(self.pop()) as usize; + pub fn jump_i(&mut self) -> Result<(), String> { + let new_pc = u256::u256_to_u64(self.pop()?) as usize; if !self.stack.is_empty() { - let cond = u256::u256_to_u64(self.pop()) as usize; + let cond = u256::u256_to_u64(self.pop()?) as usize; if cond != 0 { self.pc = new_pc; } } // let cont = self.pop(); // if cont {} // TODO depends on having impl Err in pop() + Ok(()) } - pub fn jump_dest(&mut self) { + pub fn jump_dest(&mut self) -> Result<(), String> { // TODO + Ok(()) } } diff --git a/src/u256.rs b/src/u256.rs new file mode 100644 index 0000000..a5ea06c --- /dev/null +++ b/src/u256.rs @@ -0,0 +1,19 @@ +use num_bigint::BigUint; + +pub fn u256_to_u64(a: [u8; 32]) -> u64 { + let mut b8: [u8; 8] = [0; 8]; + b8.copy_from_slice(&a[32 - 8..32]); + u64::from_be_bytes(b8) +} +pub fn usize_to_u256(i: usize) -> [u8; 32] { + let i_bytes = i.to_be_bytes(); + let mut r: [u8; 32] = [0; 32]; + r[32 - i_bytes.len()..].copy_from_slice(&i_bytes); + r +} +pub fn str_to_u256(s: &str) -> [u8; 32] { + let bi = s.parse::().unwrap().to_bytes_be(); + let mut r: [u8; 32] = [0; 32]; + r[32 - bi.len()..].copy_from_slice(&bi[..]); + r +} diff --git a/tests/execute.rs b/tests/execute.rs index 0912563..90c2516 100644 --- a/tests/execute.rs +++ b/tests/execute.rs @@ -6,16 +6,10 @@ fn stack_simple_push_pop() { s.push(u256::str_to_u256("1")); s.push(u256::str_to_u256("2")); s.push(u256::str_to_u256("3")); - assert_eq!(s.pop(), u256::str_to_u256("3")); - assert_eq!(s.pop(), u256::str_to_u256("2")); - assert_eq!(s.pop(), u256::str_to_u256("1")); - // assert_eq!(s.pop(), error); // TODO expect error as stack is empty -} - -#[test] -fn available_opcodes() { - let s = Stack::new(); - println!("available opcodes {}/130", s.opcodes.len()); + assert_eq!(s.pop().unwrap(), u256::str_to_u256("3")); + assert_eq!(s.pop().unwrap(), u256::str_to_u256("2")); + assert_eq!(s.pop().unwrap(), u256::str_to_u256("1")); + assert_eq!(s.pop(), Err(format!("pop err"))); // WIP } // arithmetic @@ -25,8 +19,8 @@ fn execute_opcodes_0() { let calldata = vec![]; let mut s = Stack::new(); - s.execute(&code, &calldata, false); - assert_eq!(s.pop(), u256::str_to_u256("17")); + s.execute(&code, &calldata, false).unwrap(); + assert_eq!(s.pop().unwrap(), u256::str_to_u256("17")); assert_eq!(s.gas, 9999999991); assert_eq!(s.pc, 5); } @@ -37,7 +31,7 @@ fn execute_opcodes_1() { let calldata = vec![]; let mut s = Stack::new(); - let out = s.execute(&code, &calldata, false); + let out = s.execute(&code, &calldata, false).unwrap(); assert_eq!(out[0], 0x09); assert_eq!(s.gas, 9999999976); @@ -51,12 +45,12 @@ fn execute_opcodes_2() { let calldata = vec![]; let mut s = Stack::new(); - s.execute(&code, &calldata, false); + s.execute(&code, &calldata, false).unwrap(); // assert_eq!(out[0], 0x09); assert_eq!(s.gas, 9999999991); assert_eq!(s.pc, 7); - assert_eq!(s.pop(), u256::str_to_u256("515")); + assert_eq!(s.pop().unwrap(), u256::str_to_u256("515")); } #[test] @@ -66,11 +60,11 @@ fn execute_opcodes_3() { let calldata = hex::decode("00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000004").unwrap(); let mut s = Stack::new(); - s.execute(&code, &calldata, false); + s.execute(&code, &calldata, false).unwrap(); assert_eq!(s.gas, 9999999985); assert_eq!(s.pc, 7); - assert_eq!(s.pop(), u256::str_to_u256("9")); + assert_eq!(s.pop().unwrap(), u256::str_to_u256("9")); } // storage and execution @@ -82,7 +76,7 @@ fn execute_opcodes_4() { hex::decode("0000000000000000000000000000000000000000000000000000000000000005").unwrap(); let mut s = Stack::new(); - s.execute(&code, &calldata, false); + s.execute(&code, &calldata, false).unwrap(); assert_eq!(s.gas, 9999999795); assert_eq!(s.pc, 22); @@ -96,7 +90,7 @@ fn execute_opcodes_5() { hex::decode("0000000000000000000000000000000000000000000000000000000000000001").unwrap(); let mut s = Stack::new(); - s.execute(&code, &calldata, false); + s.execute(&code, &calldata, false).unwrap(); assert_eq!(s.gas, 9999999968); assert_eq!(s.pc, 12); @@ -106,7 +100,7 @@ fn execute_opcodes_5() { hex::decode("0000000000000000000000000000000000000000000000000000000000000002").unwrap(); let mut s = Stack::new(); - s.execute(&code, &calldata, false); + s.execute(&code, &calldata, false).unwrap(); assert_eq!(s.gas, 9999999942); assert_eq!(s.pc, 12); @@ -116,7 +110,7 @@ fn execute_opcodes_5() { hex::decode("0000000000000000000000000000000000000000000000000000000000000005").unwrap(); let mut s = Stack::new(); - s.execute(&code, &calldata, false); + s.execute(&code, &calldata, false).unwrap(); assert_eq!(s.gas, 9999999864); assert_eq!(s.pc, 12); @@ -128,7 +122,7 @@ fn execute_opcodes_6() { let calldata = hex::decode("01").unwrap(); let mut s = Stack::new(); - s.execute(&code, &calldata, false); + s.execute(&code, &calldata, false).unwrap(); assert_eq!(s.gas, 9999999892); assert_eq!(s.pc, 21); @@ -138,7 +132,7 @@ fn execute_opcodes_6() { let calldata = hex::decode("05").unwrap(); let mut s = Stack::new(); - s.execute(&code, &calldata, false); + s.execute(&code, &calldata, false).unwrap(); assert_eq!(s.gas, 9999999788); assert_eq!(s.pc, 21); @@ -148,7 +142,7 @@ fn execute_opcodes_6() { let calldata = hex::decode("0101").unwrap(); let mut s = Stack::new(); - s.execute(&code, &calldata, false); + s.execute(&code, &calldata, false).unwrap(); assert_eq!(s.gas, 9999993236); assert_eq!(s.pc, 21); @@ -162,7 +156,7 @@ fn execute_opcodes_7() { let calldata = hex::decode("").unwrap(); let mut s = Stack::new(); - let out = s.execute(&code, &calldata, true); + let out = s.execute(&code, &calldata, true).unwrap(); assert_eq!(s.gas, 9999999976); assert_eq!(s.pc, 10); @@ -181,7 +175,7 @@ fn execute_opcodes_8() { let calldata = hex::decode("").unwrap(); let mut s = Stack::new(); - s.execute(&code, &calldata, false); + s.execute(&code, &calldata, false).unwrap(); assert_eq!(s.gas, 9999999569); assert_eq!(s.pc, 6); @@ -196,7 +190,7 @@ fn execute_opcodes_9() { let calldata = hex::decode("").unwrap(); let mut s = Stack::new(); - s.execute(&code, &calldata, true); + s.execute(&code, &calldata, true).unwrap(); assert_eq!(s.gas, 9999974988); // assert_eq!(s.gas, 9999977788); // TODO WIP geth reported gas