arnaucube
arnaucube/evm-rsPublic Self-hosted repository
Add jump_dest check, add opcode exceptions tests
arnaucube root@arnaucube.com
Wed, 15 Sep 2021 23:58:15 +0200
commit

9a4abfdf6e2b63d302cd5af3ccf315070e3198c0

parent

198236e029661c142b5478442d5b7eee8c279c5d

3 files changed, 56 insertions(+), 12 deletions(-)

jump to
M src/lib.rs → src/lib.rs

@@ -40,13 +40,13 @@ println!("{:?}", vec_u8_to_hex(self.stack[i].to_vec()));

} } 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,8 +79,15 @@ }

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(

@@ -150,8 +157,8 @@ match opcode {

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 @@ _ => {

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()) }
M src/opcodes.rs → src/opcodes.rs

@@ -188,7 +188,7 @@ self.push_arbitrary(&(b0 / b1).to_bytes_be());

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 @@ self.push_arbitrary(&(b0 % b1).to_bytes_be());

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 @@ );

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 {

@@ -355,6 +362,13 @@ pub fn jump_dest(&mut self) -> Result<(), String> {

// TODO Ok(()) } +} + +fn valid_dest(code: &[u8], pos: usize) -> bool { + if code[pos] == 0x5b { + return true; + } + false } fn upper_multiple_of_32(n: usize) -> usize {
M tests/execute.rs → tests/execute.rs

@@ -170,6 +170,29 @@ 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(); let calldata = hex::decode("").unwrap();

@@ -190,7 +213,7 @@ let code = hex::decode("60026000556001600055").unwrap();

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