mirror of
https://github.com/arnaucube/evm-rs.git
synced 2026-02-02 17:06:40 +01:00
Add jump_dest check, add opcode exceptions tests
This commit is contained in:
19
src/lib.rs
19
src/lib.rs
@@ -40,13 +40,13 @@ impl Stack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn print_memory(&self) {
|
pub fn print_memory(&self) {
|
||||||
if self.mem.len() > 0 {
|
if !self.mem.is_empty() {
|
||||||
println!("memory ({}):", self.mem.len());
|
println!("memory ({}):", self.mem.len());
|
||||||
println!("{:?}", vec_u8_to_hex(self.mem.to_vec()));
|
println!("{:?}", vec_u8_to_hex(self.mem.to_vec()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn print_storage(&self) {
|
pub fn print_storage(&self) {
|
||||||
if self.storage.len() > 0 {
|
if !self.storage.is_empty() {
|
||||||
println!("storage ({}):", self.storage.len());
|
println!("storage ({}):", self.storage.len());
|
||||||
for (key, value) in self.storage.iter() {
|
for (key, value) in self.storage.iter() {
|
||||||
println!(
|
println!(
|
||||||
@@ -79,9 +79,16 @@ impl Stack {
|
|||||||
pub fn pop(&mut self) -> Result<[u8; 32], String> {
|
pub fn pop(&mut self) -> Result<[u8; 32], String> {
|
||||||
match self.stack.pop() {
|
match self.stack.pop() {
|
||||||
Some(x) => Ok(x),
|
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(
|
pub fn execute(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -150,8 +157,8 @@ impl Stack {
|
|||||||
0x51 => self.mload()?,
|
0x51 => self.mload()?,
|
||||||
0x52 => self.mstore()?,
|
0x52 => self.mstore()?,
|
||||||
0x55 => self.sstore()?,
|
0x55 => self.sstore()?,
|
||||||
0x56 => self.jump()?,
|
0x56 => self.jump(code)?,
|
||||||
0x57 => self.jump_i()?,
|
0x57 => self.jump_i(code)?,
|
||||||
0x5b => self.jump_dest()?,
|
0x5b => self.jump_dest()?,
|
||||||
_ => return Err(format!("unimplemented {:x}", opcode)),
|
_ => return Err(format!("unimplemented {:x}", opcode)),
|
||||||
}
|
}
|
||||||
@@ -195,7 +202,7 @@ impl Stack {
|
|||||||
return Err(format!("unimplemented {:x}", opcode));
|
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())
|
Ok(Vec::new())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ impl Stack {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
pub fn sdiv(&mut self) -> Result<(), String> {
|
pub fn sdiv(&mut self) -> Result<(), String> {
|
||||||
Err(format!("unimplemented"))
|
Err("unimplemented".to_string())
|
||||||
}
|
}
|
||||||
pub fn modulus(&mut self) -> Result<(), String> {
|
pub fn modulus(&mut self) -> Result<(), String> {
|
||||||
let b0 = BigUint::from_bytes_be(&self.pop()?[..]);
|
let b0 = BigUint::from_bytes_be(&self.pop()?[..]);
|
||||||
@@ -197,7 +197,7 @@ impl Stack {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
pub fn smod(&mut self) -> Result<(), String> {
|
pub fn smod(&mut self) -> Result<(), String> {
|
||||||
Err(format!("unimplemented"))
|
Err("unimplemented".to_string())
|
||||||
}
|
}
|
||||||
pub fn add_mod(&mut self) -> Result<(), String> {
|
pub fn add_mod(&mut self) -> Result<(), String> {
|
||||||
let b0 = BigUint::from_bytes_be(&self.pop()?[..]);
|
let b0 = BigUint::from_bytes_be(&self.pop()?[..]);
|
||||||
@@ -334,13 +334,20 @@ impl Stack {
|
|||||||
self.storage.insert(key, value.to_vec());
|
self.storage.insert(key, value.to_vec());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
pub fn jump(&mut self) -> Result<(), String> {
|
pub fn jump(&mut self, code: &[u8]) -> Result<(), String> {
|
||||||
// TODO that jump destination is valid
|
// 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(())
|
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;
|
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() {
|
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 {
|
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 {
|
fn upper_multiple_of_32(n: usize) -> usize {
|
||||||
((n - 1) | 31) + 1
|
((n - 1) | 31) + 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,6 +169,29 @@ fn execute_opcodes_7() {
|
|||||||
assert_eq!(out, hex::decode("6005600401").unwrap());
|
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]
|
#[test]
|
||||||
fn execute_opcodes_8() {
|
fn execute_opcodes_8() {
|
||||||
let code = hex::decode("611000805151").unwrap();
|
let code = hex::decode("611000805151").unwrap();
|
||||||
@@ -190,7 +213,7 @@ fn execute_opcodes_9() {
|
|||||||
let calldata = hex::decode("").unwrap();
|
let calldata = hex::decode("").unwrap();
|
||||||
|
|
||||||
let mut s = Stack::new();
|
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, 9999974988);
|
||||||
// assert_eq!(s.gas, 9999977788); // TODO WIP geth reported gas
|
// assert_eq!(s.gas, 9999977788); // TODO WIP geth reported gas
|
||||||
|
|||||||
Reference in New Issue
Block a user