Skip to content

Commit

Permalink
195 tests now passing, 24 failing
Browse files Browse the repository at this point in the history
  • Loading branch information
max-wickham committed Mar 24, 2024
1 parent 8d62eec commit 646a29f
Show file tree
Hide file tree
Showing 8 changed files with 241 additions and 81 deletions.
6 changes: 6 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# TODO

- [_] Create better gas tracking, especially for memory
- [_] Fix test proc to auto detect if a file or folder and auto search sub directories
- [_] Allow specifying of a specific test in a file
- [_] Get all arithmetic tests to pass
- [_] Fix SSTORE and CALL costs (still not very clear)
- [_] Implement better system for reverts etc.
Expand All @@ -26,4 +29,7 @@
- [_] Implement Create
- [_] Define tests for mem and stack

## External

- [_] Submit fix for py eth vm, check that the address is hot
- [_] Submit fix for num256 conversion
117 changes: 88 additions & 29 deletions src/evm.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
use std::ops::{Add, Div, Mul, Sub};
use std::ops::{Add, Div, Mul, Rem, Sub};

use crate::gas_calculator::call_data_gas_cost;
use crate::runtime;
// use crate::main;
use crate::state::memory::Memory;
use crate::state::stack::Stack;
use crate::util::{self, h256_to_u256, keccak256, u256_to_array, u256_to_h256};
use crate::util::{self, h256_to_u256, int256_to_uint256, keccak256, u256_to_array, u256_to_h256, u256_to_uint256, uint256_to_int256};
use crate::{bytecode_spec::opcodes, runtime::Runtime};
use num256::{Int256, Uint256};
use paste::paste;
use primitive_types::U256;

const ZERO: U256 = U256::zero();
#[derive(Clone)]
struct Transaction {
pub origin: U256,
Expand Down Expand Up @@ -126,6 +126,9 @@ impl EVMContext {
return false;
}
}
if debug {
println!("Gas : {:x}", self.gas_input - self.gas_usage);
}

true
}
Expand Down Expand Up @@ -156,6 +159,7 @@ impl EVMContext {
#[allow(unreachable_code)]
#[allow(unused_variables)]{
{
print!("PC: {} ", self.program_counter);
let current_gas_usage = self.gas_usage;
if !(stringify!($pat).contains("PUSH") ||
stringify!($pat).contains("DUP") ||
Expand All @@ -176,7 +180,6 @@ impl EVMContext {
}

let opcode: u8 = self.program[self.program_counter];
let x = U256::zero();
debug_match!(opcode, {

opcodes::STOP => {
Expand Down Expand Up @@ -204,52 +207,96 @@ impl EVMContext {

opcodes::DIV => {
let (a, b) = (self.stack.pop(), self.stack.pop());
self.stack.push(a.div_mod(b).0);
match b {
ZERO => {
self.stack.push(U256::zero());
},
_ => {
self.stack.push(a.div_mod(b).0);
}
}
self.gas_usage += 5;
},

opcodes::SDIV => {
let (a, b) = (self.stack.pop(), self.stack.pop());
let a : Int256 = Uint256::from(TryInto::<[u8;32]>::try_into(u256_to_array(a)).unwrap()).try_into().unwrap();
let b : Int256 = Uint256::from(TryInto::<[u8;32]>::try_into(u256_to_array(b)).unwrap()).try_into().unwrap();
let result: Uint256 = (a / b).try_into().unwrap();
let result = U256::from(result.to_be_bytes());
self.stack.push(result);
match b {
ZERO => {
self.stack.push(U256::zero());
},
_ => {
let a : Int256 = Uint256::from(TryInto::<[u8;32]>::try_into(u256_to_array(a)).unwrap()).try_into().unwrap();
let b : Int256 = Uint256::from(TryInto::<[u8;32]>::try_into(u256_to_array(b)).unwrap()).try_into().unwrap();
let result: Uint256 = int256_to_uint256(a / b);
let result = U256::from(result.to_be_bytes());
self.stack.push(result);
}
}
self.gas_usage += 5;
},

opcodes::MOD => {
let (a, b) = (self.stack.pop(), self.stack.pop());
self.stack.push(a.div_mod(b).1);
match b {
ZERO => {
self.stack.push(U256::zero());
},
_ => {
self.stack.push(a.rem(b));
}
}
self.gas_usage += 5;
},

opcodes::SMOD => {
let (a, b) = (self.stack.pop(), self.stack.pop());
let a : Int256 = Uint256::from(TryInto::<[u8;32]>::try_into(u256_to_array(a)).unwrap()).try_into().unwrap();
let b : Int256 = Uint256::from(TryInto::<[u8;32]>::try_into(u256_to_array(b)).unwrap()).try_into().unwrap();
let result: Uint256 = (a % b).try_into().unwrap();
let result = U256::from(result.to_be_bytes());
self.stack.push(result);
match b {
ZERO => {
self.stack.push(U256::zero());
},
_ => {
let a = uint256_to_int256(u256_to_uint256(a));
let b = uint256_to_int256(u256_to_uint256(b));
println!("a: {}, b: {}, {}", a, b, (a.rem(b) + b).rem(b));
let result: Uint256 = int256_to_uint256((a.rem(b) + b).rem(b));
let result = U256::from(result.to_be_bytes());
self.stack.push(result);
}
}
self.gas_usage += 5;

},

opcodes::ADDMOD => {
let (a, b, c) = (self.stack.pop(), self.stack.pop(), self.stack.pop());
self.stack.push((a + b) % c);
match c {
ZERO => {
self.stack.push(U256::zero());
},
_ => {
self.stack.push(a.checked_rem(c).unwrap().overflowing_add(b.checked_rem(c).unwrap()).0);
}
}
self.gas_usage += 8;
},

opcodes::MULMOD => {
let (a, b, c) = (self.stack.pop(), self.stack.pop(), self.stack.pop());
self.stack.push((a * b) % c);
match c {
ZERO => {
self.stack.push(U256::zero());
},
_ => {
self.stack.push(a.checked_rem(c).unwrap().overflowing_mul(b.checked_rem(c).unwrap()).0.checked_rem(c).unwrap());
}
}
// println!("a: {}, b: {}, c: {}", a, b, c);
self.gas_usage += 8;
},

opcodes::EXP => {
let (a, exponent) = (self.stack.pop(), self.stack.pop());
self.stack.push(a.pow(exponent));
self.stack.push(a.overflowing_pow(exponent).0);
self.gas_usage += 10 + 50 * (util::bytes_for_u256(&exponent) as u64);
},

Expand Down Expand Up @@ -413,7 +460,7 @@ impl EVMContext {
);
let current_memory_usage = self.memory.memory_cost;
self.memory
.copy_from(&self.message.data, offset, dest_offset, length);
.copy_from(&mut self.message.data, offset, dest_offset, length);
let new_usage = self.memory.memory_cost;
self.gas_usage +=
3 + 3 * (length as u64 + 31 / 32) + (new_usage - current_memory_usage).as_u64();
Expand All @@ -433,7 +480,7 @@ impl EVMContext {

let current_memory_usage = self.memory.memory_cost;
self.memory
.copy_from(&self.program, offset, dest_offset, length);
.copy_from(&mut self.program, offset, dest_offset, length);
let new_usage = self.memory.memory_cost;
self.gas_usage +=
3 + 3 * (length as u64 + 31 / 32) + (new_usage - current_memory_usage).as_u64();
Expand Down Expand Up @@ -461,7 +508,7 @@ impl EVMContext {

let current_memory_usage = self.memory.memory_cost;
self.memory.copy_from(
&Memory::from(runtime.code(addr)),
&mut Memory::from(runtime.code(addr)),
offset,
dest_offset,
length,
Expand All @@ -487,7 +534,7 @@ impl EVMContext {
);
let current_memory_usage = self.memory.memory_cost;
self.memory
.copy_from(&self.last_return_data, offset, dest_offset, length);
.copy_from(&mut self.last_return_data, offset, dest_offset, length);
let new_usage = self.memory.memory_cost;
self.gas_usage +=
3 + 3 * (length as u64 + 31 / 32) + (new_usage - current_memory_usage).as_u64();
Expand Down Expand Up @@ -620,15 +667,21 @@ impl EVMContext {
},

opcodes::JUMP => {

println!("Jumping");
let destination = self.stack.pop().as_usize();
println!("Destination: {}", destination);
self.program_counter = destination;
self.program_counter -= 1;
println!("Program Counter: {}", self.program_counter);
self.gas_usage += 8;
},


opcodes::JUMPI => {
let (destination, condition) = (self.stack.pop().as_usize(), self.stack.pop());
if !condition.eq(&U256::zero()) {
self.program_counter = destination;
self.program_counter = destination - 1;
}
self.gas_usage += 10;
},
Expand All @@ -648,6 +701,10 @@ impl EVMContext {
self.gas_usage += 2;
},

opcodes::JUMPDEST => {
self.gas_usage += 1;
},

opcodes::PUSH_1..=opcodes::PUSH_32 => {
let push_number = opcode - opcodes::PUSH_1 + 1;
debug!("opcodes::PUSH_{}", push_number);
Expand Down Expand Up @@ -685,9 +742,12 @@ impl EVMContext {

opcodes::RETURN => {
let (offset, size) = (self.stack.pop().as_usize(), self.stack.pop().as_usize());
println!("Return: {}, {}", offset, size);
self.result.set_length(size);
self.result.copy_from(&self.memory, offset, 0, size);
self.gas_usage += 0;
// self.result.copy_from(&mut self.memory, offset, 0, size);
self.gas_usage += self.result.copy_from(&mut self.memory, offset, 0, size) as u64;
self.stopped = true;
return true;
},

opcodes::DELEGATECALL => {
Expand Down Expand Up @@ -774,7 +834,6 @@ impl EVMContext {
100
} else {
runtime.mark_hot(address);
println!("Is not hot");
2600
};
// TODO check gas is okay
Expand All @@ -788,7 +847,7 @@ impl EVMContext {
caller: self.contract_address,
data: {
let mut memory: Memory = Memory::new();
memory.copy_from(&self.memory, args_offset, 0, args_size);
memory.copy_from(&mut self.memory, args_offset, 0, args_size);
memory
},
value: value,
Expand All @@ -804,7 +863,7 @@ impl EVMContext {
self.last_return_data = sub_evm.result;
let current_memory_cost = self.memory.memory_cost;
self.memory
.copy_from(&self.last_return_data, 0, ret_offset, ret_size);
.copy_from(&mut self.last_return_data, 0, ret_offset, ret_size);
let new_memory_cost = self.memory.memory_cost;
self.stack.push(U256::from(response as u64));
let memory_expansion_cost = (new_memory_cost - current_memory_cost).as_u64();
Expand Down
16 changes: 13 additions & 3 deletions src/state/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,23 @@ impl Memory {
#[inline]
pub fn copy_from(
&mut self,
memory: &Memory,
memory: &mut Memory,
read_address: usize,
write_address: usize,
length: usize,
) {
) -> usize {
if write_address > self.max_index {
self.expand(write_address)
}
println!("Memory {:?}", memory.bytes);
let start_cost= memory.compute_memory_cost();
if memory.bytes.len() < read_address + length {
memory.expand(read_address + length)
}
let cost = memory.compute_memory_cost() - start_cost;
self.bytes[write_address..write_address + length]
.copy_from_slice(&memory.bytes[read_address..read_address + length]);
.copy_from_slice(&memory.bytes[read_address..(read_address + length)]);
cost
}

#[inline]
Expand Down Expand Up @@ -99,6 +106,9 @@ impl Memory {

#[inline]
fn compute_memory_cost(&mut self) -> usize {
if self.bytes.len() == 0 {
return 0;
}
self.max_index = self.bytes.len() - 1;
let memory_size_word = (self.max_index / 4) as u64;
self.memory_cost =
Expand Down
35 changes: 35 additions & 0 deletions src/util.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
use std::{ops::Not, str::FromStr};

use num256::{Int256, Uint256};
use primitive_types::{H256,U256};
use sha3::{Digest, Keccak256};

Expand Down Expand Up @@ -42,6 +45,38 @@ pub fn u256_to_array(v: U256) -> [u8; 32] {
x
}

pub fn u256_to_uint256(v: U256) -> Uint256 {
Uint256::from(TryInto::<[u8;32]>::try_into(u256_to_array(v)).unwrap()).try_into().unwrap()
}

pub fn uint256_to_int256(v: Uint256) -> Int256 {
if v > Uint256::from_str("57896044618658097711785492504343953926634992332820282019728792003956564819967").unwrap() {
let mut twos_complement = v.to_be_bytes();
for elem in twos_complement.iter_mut() {
*elem = !*elem;
}
let twos_complement = Uint256::from(twos_complement) + Uint256::from(1 as u64);

twos_complement.to_int256().unwrap() * Int256::from(-1)
} else {
v.to_int256().unwrap()
}
}

pub fn int256_to_uint256(v: Int256) -> Uint256 {
if v < Int256::from(0 as i64) {
let twos_complement = v * Int256::from(-1);
let twos_complement = twos_complement.to_uint256().unwrap();
let mut twos_complement = twos_complement.to_be_bytes();
for elem in twos_complement.iter_mut() {
*elem = !*elem;
}
let twos_complement = Uint256::from(twos_complement) + Uint256::from(1 as u64);
twos_complement
} else {
v.to_uint256().unwrap()
}
}


#[macro_export]
Expand Down
Loading

0 comments on commit 646a29f

Please sign in to comment.