diff --git a/src/lib.rs b/src/lib.rs index b0a33e0..bff3e0d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,13 +40,13 @@ impl Stack { } } pub fn print_memory(&self) { - if self.mem.len() > 0 { + if !self.mem.is_empty() { println!("memory ({}):", self.mem.len()); println!("{:?}", vec_u8_to_hex(self.mem.to_vec())); } } pub fn print_storage(&self) { - if self.storage.len() > 0 { + if !self.storage.is_empty() { println!("storage ({}):", self.storage.len()); for (key, value) in self.storage.iter() { println!( @@ -79,9 +79,16 @@ impl Stack { pub fn pop(&mut self) -> Result<[u8; 32], String> { match self.stack.pop() { Some(x) => Ok(x), - None => Err(format!("pop err")), // WIP + None => Err("pop err".to_string()), // WIP } } + pub fn substract_gas(&mut self, val: u64) -> Result<(), String> { + if self.gas < val { + return Err("out of gas".to_string()); + } + self.gas -= val; + Ok(()) + } pub fn execute( &mut self, @@ -150,8 +157,8 @@ impl Stack { 0x51 => self.mload()?, 0x52 => self.mstore()?, 0x55 => self.sstore()?, - 0x56 => self.jump()?, - 0x57 => self.jump_i()?, + 0x56 => self.jump(code)?, + 0x57 => self.jump_i(code)?, 0x5b => self.jump_dest()?, _ => return Err(format!("unimplemented {:x}", opcode)), } @@ -195,7 +202,7 @@ impl Stack { return Err(format!("unimplemented {:x}", opcode)); } } - self.gas -= self.opcodes.get(&opcode).unwrap().gas; + self.substract_gas(self.opcodes.get(&opcode).unwrap().gas)?; } Ok(Vec::new()) } diff --git a/src/opcodes.rs b/src/opcodes.rs index 93aa7a1..7c9ce94 100644 --- a/src/opcodes.rs +++ b/src/opcodes.rs @@ -188,7 +188,7 @@ impl Stack { Ok(()) } pub fn sdiv(&mut self) -> Result<(), String> { - Err(format!("unimplemented")) + Err("unimplemented".to_string()) } pub fn modulus(&mut self) -> Result<(), String> { let b0 = BigUint::from_bytes_be(&self.pop()?[..]); @@ -197,7 +197,7 @@ impl Stack { Ok(()) } pub fn smod(&mut self) -> Result<(), String> { - Err(format!("unimplemented")) + Err("unimplemented".to_string()) } pub fn add_mod(&mut self) -> Result<(), String> { let b0 = BigUint::from_bytes_be(&self.pop()?[..]); @@ -334,13 +334,20 @@ impl Stack { self.storage.insert(key, value.to_vec()); Ok(()) } - pub fn jump(&mut self) -> Result<(), String> { + pub fn jump(&mut self, code: &[u8]) -> Result<(), String> { // TODO that jump destination is valid - self.pc = u256::u256_to_u64(self.pop()?) as usize; + let new_pc = u256::u256_to_u64(self.pop()?) as usize; + if !valid_dest(code, new_pc) { + return Err(format!("not valid dest: {:02x}", new_pc)); + } + self.pc = new_pc; Ok(()) } - pub fn jump_i(&mut self) -> Result<(), String> { + pub fn jump_i(&mut self, code: &[u8]) -> Result<(), String> { let new_pc = u256::u256_to_u64(self.pop()?) as usize; + if !valid_dest(code, new_pc) { + return Err(format!("not valid dest: {:02x}", new_pc)); + } if !self.stack.is_empty() { let cond = u256::u256_to_u64(self.pop()?) as usize; if cond != 0 { @@ -357,6 +364,13 @@ impl Stack { } } +fn valid_dest(code: &[u8], pos: usize) -> bool { + if code[pos] == 0x5b { + return true; + } + false +} + fn upper_multiple_of_32(n: usize) -> usize { ((n - 1) | 31) + 1 } diff --git a/tests/execute.rs b/tests/execute.rs index 90c2516..f690dc4 100644 --- a/tests/execute.rs +++ b/tests/execute.rs @@ -169,6 +169,29 @@ fn execute_opcodes_7() { assert_eq!(out, hex::decode("6005600401").unwrap()); } +#[test] +fn execute_exceptions() { + let mut s = Stack::new(); + let calldata = hex::decode("").unwrap(); + + let code = hex::decode("5f").unwrap(); + let out = s.execute(&code, &calldata, false); + assert_eq!(out, Err(format!("invalid opcode 5f"))); + + let code = hex::decode("56").unwrap(); + let out = s.execute(&code, &calldata, false); + assert_eq!(out, Err(format!("pop err"))); + + let code = hex::decode("600056").unwrap(); + let out = s.execute(&code, &calldata, false); + assert_eq!(out, Err(format!("not valid dest: 00"))); + + s.gas = 1; + let code = hex::decode("6000").unwrap(); + let out = s.execute(&code, &calldata, false); + assert_eq!(out, Err(format!("out of gas"))); +} + #[test] fn execute_opcodes_8() { let code = hex::decode("611000805151").unwrap(); @@ -190,7 +213,7 @@ fn execute_opcodes_9() { let calldata = hex::decode("").unwrap(); let mut s = Stack::new(); - s.execute(&code, &calldata, true).unwrap(); + s.execute(&code, &calldata, false).unwrap(); assert_eq!(s.gas, 9999974988); // assert_eq!(s.gas, 9999977788); // TODO WIP geth reported gas