Browse Source

Add jump_dest check, add opcode exceptions tests

master
arnaucube 2 years ago
parent
commit
9a4abfdf6e
3 changed files with 56 additions and 12 deletions
  1. +13
    -6
      src/lib.rs
  2. +19
    -5
      src/opcodes.rs
  3. +24
    -1
      tests/execute.rs

+ 13
- 6
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())
}

+ 19
- 5
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
}

+ 24
- 1
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

Loading…
Cancel
Save