Browse Source

Add errors handling

master
arnaucube 2 years ago
parent
commit
198236e029
5 changed files with 187 additions and 156 deletions
  1. +0
    -2
      README.md
  2. +36
    -31
      src/lib.rs
  3. +111
    -96
      src/opcodes.rs
  4. +19
    -0
      src/u256.rs
  5. +21
    -27
      tests/execute.rs

+ 0
- 2
README.md

@ -2,5 +2,3 @@
EVM ([Ethereum Virtual Machine](https://ethereum.org/en/developers/docs/evm/)) implementation from scratch in Rust. 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.* *This is a repo done to get familiar with the EVM, do not use.*
Opcodes implemented: 83/130.

+ 36
- 31
src/lib.rs

@ -76,14 +76,19 @@ impl Stack {
let l = self.stack.len(); let l = self.stack.len();
self.stack[l - 1] = d; 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() { 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<u8> {
pub fn execute(
&mut self,
code: &[u8],
calldata: &[u8],
debug: bool,
) -> Result<Vec<u8>, String> {
self.pc = 0; self.pc = 0;
self.calldata_i = 0; self.calldata_i = 0;
let l = code.len(); let l = code.len();
@ -91,7 +96,7 @@ impl Stack {
while self.pc < l { while self.pc < l {
let opcode = code[self.pc]; let opcode = code[self.pc];
if !self.opcodes.contains_key(&opcode) { if !self.opcodes.contains_key(&opcode) {
panic!("invalid opcode {:x}", opcode);
return Err(format!("invalid opcode {:x}", opcode));
} }
if debug { if debug {
@ -113,20 +118,20 @@ impl Stack {
match opcode { match opcode {
0x00 => { 0x00 => {
println!("0x00: STOP"); 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(), // 0x0b => self.sign_extend(),
_ => panic!("unimplemented {:x}", opcode),
_ => return Err(format!("unimplemented {:x}", opcode)),
} }
self.pc += 1; self.pc += 1;
} }
@ -134,21 +139,21 @@ impl Stack {
match opcode { match opcode {
0x35 => self.calldata_load(&calldata), 0x35 => self.calldata_load(&calldata),
0x36 => self.calldata_size(&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; self.pc += 1;
} }
0x50 => { 0x50 => {
self.pc += 1; self.pc += 1;
match opcode { 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 => { 0x60 | 0x70 => {
@ -181,18 +186,18 @@ impl Stack {
} }
0xf0 => { 0xf0 => {
if opcode == 0xf3 { 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; self.gas -= self.opcodes.get(&opcode).unwrap().gas;
} }
Vec::new()
Ok(Vec::new())
} }
} }
pub fn vec_u8_to_hex(bytes: Vec<u8>) -> String { pub fn vec_u8_to_hex(bytes: Vec<u8>) -> String {

+ 111
- 96
src/opcodes.rs

@ -58,81 +58,81 @@ pub fn new_opcodes() -> HashMap {
opcodes.insert(0x02, new_opcode("MUL", 2, 1, 5)); opcodes.insert(0x02, new_opcode("MUL", 2, 1, 5));
opcodes.insert(0x03, new_opcode("SUB", 2, 1, 3)); opcodes.insert(0x03, new_opcode("SUB", 2, 1, 3));
opcodes.insert(0x04, new_opcode("DIV", 2, 1, 5)); 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(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(0x08, new_opcode("ADDMOD", 3, 1, 8));
opcodes.insert(0x09, new_opcode("MULMOD", 3, 1, 8)); opcodes.insert(0x09, new_opcode("MULMOD", 3, 1, 8));
opcodes.insert(0x0a, new_opcode("EXP", 2, 1, 10)); 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 // 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 // crypto
// opcodes.insert(0x20, new_opcode("SHA3", 2, 1, 30));
opcodes.insert(0x20, new_opcode("SHA3", 2, 1, 30));
// contract context // 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(0x35, new_opcode("CALLDATALOAD", 1, 1, 3));
opcodes.insert(0x36, new_opcode("CALLDATASIZE", 0, 1, 2)); 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(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 // 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 // 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(0x51, new_opcode("MLOAD", 1, 1, 3));
opcodes.insert(0x52, new_opcode("MSTORE", 2, 0, 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(0x55, new_opcode("SSTORE", 2, 0, 0));
opcodes.insert(0x56, new_opcode("JUMP", 1, 0, 8)); opcodes.insert(0x56, new_opcode("JUMP", 1, 0, 8));
opcodes.insert(0x57, new_opcode("JUMPI", 2, 0, 10)); 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)); opcodes.insert(0x5b, new_opcode("JUMPDEST", 0, 0, 1));
// logging // 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 // 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(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 { for i in 1..33 {
let name = format!("PUSH{}", i); let name = format!("PUSH{}", i);
@ -154,19 +154,21 @@ impl Stack {
// arithmetic // arithmetic
// TODO instead of [u8;32] converted to BigUint, use custom type uint256 that implements all // TODO instead of [u8;32] converted to BigUint, use custom type uint256 that implements all
// the arithmetic // 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()); 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()); 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 { if b0 >= b1 {
self.push_arbitrary(&(b0 - b1).to_bytes_be()); self.push_arbitrary(&(b0 - b1).to_bytes_be());
} else { } else {
@ -177,38 +179,43 @@ impl Stack {
.unwrap(); .unwrap();
self.push_arbitrary(&(max + b0 - b1).to_bytes_be()); 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()); 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()); 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()); 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()); 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::<BigUint>().unwrap(); let mut r = "1".parse::<BigUint>().unwrap();
let zero = "0".parse::<BigUint>().unwrap(); let zero = "0".parse::<BigUint>().unwrap();
@ -233,6 +240,7 @@ impl Stack {
let mut exp_fee = n_bytes * GEXPONENTBYTE; let mut exp_fee = n_bytes * GEXPONENTBYTE;
exp_fee += EXP_SUPPLEMENTAL_GAS * n_bytes; exp_fee += EXP_SUPPLEMENTAL_GAS * n_bytes;
self.gas -= exp_fee as u64; self.gas -= exp_fee as u64;
Ok(())
} }
// boolean // boolean
@ -251,10 +259,10 @@ impl Stack {
let length32 = upper_multiple_of_32(length); let length32 = upper_multiple_of_32(length);
self.gas -= ((GCOPY * length32) / 32) as u64; 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.extend_mem(dest_offset, length);
self.spend_gas_data_copy(length); self.spend_gas_data_copy(length);
@ -267,6 +275,7 @@ impl Stack {
} }
} }
// self.mem[dest_offset..dest_offset+length] = // self.mem[dest_offset..dest_offset+length] =
Ok(())
} }
// blockchain context // blockchain context
@ -285,27 +294,29 @@ impl Stack {
let mut new_bytes: Vec<u8> = vec![0; (new_size - old_size) * 32]; let mut new_bytes: Vec<u8> = vec![0; (new_size - old_size) * 32];
self.mem.append(&mut new_bytes); 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); self.extend_mem(pos as usize, 32);
let mem32 = self.mem[pos..pos + 32].to_vec(); let mem32 = self.mem[pos..pos + 32].to_vec();
self.push_arbitrary(&mem32); 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.extend_mem(pos as usize, 32);
self.mem[pos as usize..].copy_from_slice(&val); 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) { if self.storage.contains_key(&key) {
let old_value = self.storage.get(&key).unwrap(); let old_value = self.storage.get(&key).unwrap();
if &value.to_vec() == old_value { if &value.to_vec() == old_value {
// if the new value is the same as the old one, do not set // 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 // if value (from self.pop()) does not exist in the stack, is a STORAGEKILL TODO
println!("mingas {:?}", GSTORAGEMOD); println!("mingas {:?}", GSTORAGEMOD);
@ -321,24 +332,28 @@ impl Stack {
vec_u8_to_hex(value.to_vec()) vec_u8_to_hex(value.to_vec())
); );
self.storage.insert(key, 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 // 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() { 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 {
self.pc = new_pc; self.pc = new_pc;
} }
} }
// let cont = self.pop(); // let cont = self.pop();
// if cont {} // TODO depends on having impl Err in 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 // TODO
Ok(())
} }
} }

+ 19
- 0
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::<BigUint>().unwrap().to_bytes_be();
let mut r: [u8; 32] = [0; 32];
r[32 - bi.len()..].copy_from_slice(&bi[..]);
r
}

+ 21
- 27
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("1"));
s.push(u256::str_to_u256("2")); s.push(u256::str_to_u256("2"));
s.push(u256::str_to_u256("3")); 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 // arithmetic
@ -25,8 +19,8 @@ fn execute_opcodes_0() {
let calldata = vec![]; let calldata = vec![];
let mut s = Stack::new(); 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.gas, 9999999991);
assert_eq!(s.pc, 5); assert_eq!(s.pc, 5);
} }
@ -37,7 +31,7 @@ fn execute_opcodes_1() {
let calldata = vec![]; let calldata = vec![];
let mut s = Stack::new(); 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!(out[0], 0x09);
assert_eq!(s.gas, 9999999976); assert_eq!(s.gas, 9999999976);
@ -51,12 +45,12 @@ fn execute_opcodes_2() {
let calldata = vec![]; let calldata = vec![];
let mut s = Stack::new(); let mut s = Stack::new();
s.execute(&code, &calldata, false);
s.execute(&code, &calldata, false).unwrap();
// assert_eq!(out[0], 0x09); // assert_eq!(out[0], 0x09);
assert_eq!(s.gas, 9999999991); assert_eq!(s.gas, 9999999991);
assert_eq!(s.pc, 7); 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] #[test]
@ -66,11 +60,11 @@ fn execute_opcodes_3() {
let calldata = hex::decode("00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000004").unwrap(); let calldata = hex::decode("00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000004").unwrap();
let mut s = Stack::new(); let mut s = Stack::new();
s.execute(&code, &calldata, false);
s.execute(&code, &calldata, false).unwrap();
assert_eq!(s.gas, 9999999985); assert_eq!(s.gas, 9999999985);
assert_eq!(s.pc, 7); 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 // storage and execution
@ -82,7 +76,7 @@ fn execute_opcodes_4() {
hex::decode("0000000000000000000000000000000000000000000000000000000000000005").unwrap(); hex::decode("0000000000000000000000000000000000000000000000000000000000000005").unwrap();
let mut s = Stack::new(); let mut s = Stack::new();
s.execute(&code, &calldata, false);
s.execute(&code, &calldata, false).unwrap();
assert_eq!(s.gas, 9999999795); assert_eq!(s.gas, 9999999795);
assert_eq!(s.pc, 22); assert_eq!(s.pc, 22);
@ -96,7 +90,7 @@ fn execute_opcodes_5() {
hex::decode("0000000000000000000000000000000000000000000000000000000000000001").unwrap(); hex::decode("0000000000000000000000000000000000000000000000000000000000000001").unwrap();
let mut s = Stack::new(); let mut s = Stack::new();
s.execute(&code, &calldata, false);
s.execute(&code, &calldata, false).unwrap();
assert_eq!(s.gas, 9999999968); assert_eq!(s.gas, 9999999968);
assert_eq!(s.pc, 12); assert_eq!(s.pc, 12);
@ -106,7 +100,7 @@ fn execute_opcodes_5() {
hex::decode("0000000000000000000000000000000000000000000000000000000000000002").unwrap(); hex::decode("0000000000000000000000000000000000000000000000000000000000000002").unwrap();
let mut s = Stack::new(); let mut s = Stack::new();
s.execute(&code, &calldata, false);
s.execute(&code, &calldata, false).unwrap();
assert_eq!(s.gas, 9999999942); assert_eq!(s.gas, 9999999942);
assert_eq!(s.pc, 12); assert_eq!(s.pc, 12);
@ -116,7 +110,7 @@ fn execute_opcodes_5() {
hex::decode("0000000000000000000000000000000000000000000000000000000000000005").unwrap(); hex::decode("0000000000000000000000000000000000000000000000000000000000000005").unwrap();
let mut s = Stack::new(); let mut s = Stack::new();
s.execute(&code, &calldata, false);
s.execute(&code, &calldata, false).unwrap();
assert_eq!(s.gas, 9999999864); assert_eq!(s.gas, 9999999864);
assert_eq!(s.pc, 12); assert_eq!(s.pc, 12);
@ -128,7 +122,7 @@ fn execute_opcodes_6() {
let calldata = hex::decode("01").unwrap(); let calldata = hex::decode("01").unwrap();
let mut s = Stack::new(); let mut s = Stack::new();
s.execute(&code, &calldata, false);
s.execute(&code, &calldata, false).unwrap();
assert_eq!(s.gas, 9999999892); assert_eq!(s.gas, 9999999892);
assert_eq!(s.pc, 21); assert_eq!(s.pc, 21);
@ -138,7 +132,7 @@ fn execute_opcodes_6() {
let calldata = hex::decode("05").unwrap(); let calldata = hex::decode("05").unwrap();
let mut s = Stack::new(); let mut s = Stack::new();
s.execute(&code, &calldata, false);
s.execute(&code, &calldata, false).unwrap();
assert_eq!(s.gas, 9999999788); assert_eq!(s.gas, 9999999788);
assert_eq!(s.pc, 21); assert_eq!(s.pc, 21);
@ -148,7 +142,7 @@ fn execute_opcodes_6() {
let calldata = hex::decode("0101").unwrap(); let calldata = hex::decode("0101").unwrap();
let mut s = Stack::new(); let mut s = Stack::new();
s.execute(&code, &calldata, false);
s.execute(&code, &calldata, false).unwrap();
assert_eq!(s.gas, 9999993236); assert_eq!(s.gas, 9999993236);
assert_eq!(s.pc, 21); assert_eq!(s.pc, 21);
@ -162,7 +156,7 @@ fn execute_opcodes_7() {
let calldata = hex::decode("").unwrap(); let calldata = hex::decode("").unwrap();
let mut s = Stack::new(); 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.gas, 9999999976);
assert_eq!(s.pc, 10); assert_eq!(s.pc, 10);
@ -181,7 +175,7 @@ fn execute_opcodes_8() {
let calldata = hex::decode("").unwrap(); let calldata = hex::decode("").unwrap();
let mut s = Stack::new(); let mut s = Stack::new();
s.execute(&code, &calldata, false);
s.execute(&code, &calldata, false).unwrap();
assert_eq!(s.gas, 9999999569); assert_eq!(s.gas, 9999999569);
assert_eq!(s.pc, 6); assert_eq!(s.pc, 6);
@ -196,7 +190,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);
s.execute(&code, &calldata, true).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

Loading…
Cancel
Save