Skip to content

Commit

Permalink
some buffer tests now passing
Browse files Browse the repository at this point in the history
  • Loading branch information
max-wickham committed Mar 27, 2024
1 parent f3ad15f commit b96a552
Show file tree
Hide file tree
Showing 11 changed files with 113 additions and 66 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/target
*.test
8 changes: 8 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
# TODO

- [_] Fix Calldata load, Code load etc.
- [_] Do general clean up
- [_] Better error handling
- [_] Refactor where macros and functions are
- [_] Remove lambdas
- [_] Move costs into a config
- [_] Separate gas cost logic from main logic
- [_] Get Memory Buffer tests to work
- Check CODECOPY
- Check CALLDATACOPY
- Check initial costs
- [_] Make gas refunds handle reverts
- [_] Only pass JSON once in tests, (maybe pass in the proc macro and then directly insert in the code)
- [_] Replace macro with method in decoder?
- [x] Replace closure with macro
Expand Down
21 changes: 11 additions & 10 deletions src/evm_logic/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ struct Transaction {
struct Message {
pub caller: U256,
pub value: U256,
pub data: Memory,
pub data: Vec<u8>,
}

pub struct EVMContext {
Expand Down Expand Up @@ -51,7 +51,7 @@ impl EVMContext {
let message = Message {
caller: contract,
value: value,
data: Memory::from(data, &mut GasRecorder { gas_usage: 0 }),
data: data,
};
let transaction = Transaction {
origin: origin,
Expand All @@ -68,7 +68,7 @@ impl EVMContext {
);
evm.gas_recorder.record_gas(21000);
evm.execute_program(runtime, debug);
evm.gas_recorder.gas_usage
evm.gas_recorder.gas_usage - usize::min(evm.gas_recorder.gas_refunds, evm.gas_recorder.gas_usage / 2)
}

#[inline]
Expand All @@ -84,7 +84,7 @@ impl EVMContext {
EVMContext {
stack: Stack::new(),
memory: Memory::new(),
program: Memory::from(code, &mut GasRecorder { gas_usage: 0 }),
program: Memory::from(code, &mut GasRecorder { gas_usage: 0, gas_refunds: 0 }),
program_counter: 0,
contract_address: address,
// TODO remove need to clone here
Expand All @@ -96,7 +96,7 @@ impl EVMContext {
gas_price: gas_price,
stopped: false,
nested_index: nested_index,
gas_recorder: GasRecorder { gas_usage: 0 },
gas_recorder: GasRecorder { gas_usage: 0 , gas_refunds: 0},
}
}

Expand All @@ -105,13 +105,14 @@ impl EVMContext {
runtime.add_context();

let result = || -> bool {
println!("Message data size : {}", self.message.data.bytes.len());
if self.message.data.bytes.len() != 0{
println!("Message data size : {:?}", self.message.data);
println!("Message data size : {:?}", self.message.data.len());
if self.message.data.len() != 0{
self.gas_recorder
.record_gas(call_data_gas_cost(&self.message.data.bytes));
.record_gas(call_data_gas_cost(&self.message.data));
}
if debug {
println!("Call Data Gas Cost: {}", self.gas_recorder.gas_usage);
println!("Call Data Gas Cost: {:x}", self.gas_recorder.gas_usage);
}
while !self.stopped {
let result = self.execute_next_instruction(runtime, debug);
Expand Down Expand Up @@ -142,7 +143,7 @@ impl EVMContext {
}
#[inline]
fn check_gas_usage(&self) -> bool {
self.gas_recorder.gas_usage > self.gas_input as usize
(self.gas_recorder.gas_usage - self.gas_recorder.gas_refunds) > self.gas_input as usize
}
}

Expand Down
97 changes: 62 additions & 35 deletions src/evm_logic/evm/decoder.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::bytecode_spec::opcodes;
use crate::evm_logic::evm::{EVMContext, Message};
use crate::runtime::Runtime;
use crate::state::memory::Memory;
use crate::evm_logic::util::{
self, h256_to_u256, int256_to_uint256, keccak256, u256_to_h256, u256_to_uint256,
uint256_to_int256, MAX_UINT256, MAX_UINT256_COMPLEMENT, ZERO,
uint256_to_int256, MAX_UINT256, MAX_UINT256_COMPLEMENT, ZERO, ZERO_H256,
};
use crate::runtime::Runtime;
use crate::state::memory::Memory;

use num256::Uint256;
use primitive_types::U256;
Expand All @@ -16,7 +16,7 @@ pub fn decode_instruction(evm: &mut EVMContext, runtime: &mut impl Runtime, debu
/*
Run the next instruction, adjusting gas usage and return a bool that is true if okay, false if exception
*/

// Should be put into a separate macros file
// Not a function as need to be able to return from caller function
macro_rules! pop {
($($input:tt)*) => {{
Expand Down Expand Up @@ -68,17 +68,7 @@ pub fn decode_instruction(evm: &mut EVMContext, runtime: &mut impl Runtime, debu
},
Message {
caller: evm.contract_address,
data: {
let mut memory: Memory = Memory::new();
memory.copy_from(
&mut evm.memory,
args_offset,
0,
args_size,
&mut evm.gas_recorder,
);
memory
},
data: evm.memory.bytes[args_offset..args_offset + args_size].to_vec(),
value: value,
},
gas,
Expand Down Expand Up @@ -151,6 +141,7 @@ pub fn decode_instruction(evm: &mut EVMContext, runtime: &mut impl Runtime, debu
debug_match!(opcode, {

opcodes::STOP => {
println!("STOP");
evm.stopped = true;
return true;
},
Expand Down Expand Up @@ -403,10 +394,11 @@ pub fn decode_instruction(evm: &mut EVMContext, runtime: &mut impl Runtime, debu

opcodes::KECCAK256 => {
let (offset, length) = (pop!().as_usize(), pop!().as_usize());
println!("offset: {}, length: {}", offset, length);
let bytes = evm.memory.read_bytes(offset, length, &mut evm.gas_recorder);
evm.stack.push(U256::from(keccak256(&bytes).as_bytes()));
// As of the Ethereum Yellow Paper (EIP-62), the gas cost for the KECCAK256 instruction is 30 gas plus an additional 6 gas for each 256-bit word (or part thereof) of input data.
evm.gas_recorder.record_gas(30 + (length.div_ceil(256) as u64 * 6) as usize);
evm.gas_recorder.record_gas(30 + (length.div_ceil(32) as u64 * 6) as usize);
},

opcodes::ADDRESS => {
Expand Down Expand Up @@ -439,7 +431,17 @@ pub fn decode_instruction(evm: &mut EVMContext, runtime: &mut impl Runtime, debu
opcodes::CALLDATALOAD => {
// TODO fix
let index = pop!().as_u64() as usize;
evm.stack.push(evm.message.data.read(index, &mut evm.gas_recorder));
if index > evm.message.data.len() - 32 {
evm.stack.push_bytes(
&{
let mut bytes = evm.message.data.clone();
bytes.append(&mut vec![0; 32 - (evm.message.data.len() - index)]);
bytes
}
);
} else {
evm.stack.push_bytes(&evm.message.data[index..index + 32].to_vec());
}
evm.gas_recorder.record_gas(3);
},

Expand All @@ -449,14 +451,15 @@ pub fn decode_instruction(evm: &mut EVMContext, runtime: &mut impl Runtime, debu
},

opcodes::CALLDATACOPY => {
// TODO fix
let (dest_offset, offset, length) = (
pop!().as_usize(),
pop!().as_usize(),
pop!().as_usize(),
);
// let current_memory_usage = evm.memory.memory_cost;
evm.memory
.copy_from(&mut evm.message.data, offset, dest_offset, length, &mut evm.gas_recorder);
// evm.memory
// .copy_from(&mut evm.message.data, offset, dest_offset, length, &mut evm.gas_recorder);
// let new_usage = evm.memory.memory_cost;
// evm.gas_usage +=
// 3 + 3 * (length as u64 + 31 / 32) + (new_usage - current_memory_usage).as_u64();
Expand Down Expand Up @@ -609,7 +612,7 @@ pub fn decode_instruction(evm: &mut EVMContext, runtime: &mut impl Runtime, debu
runtime.mark_hot_index(evm.contract_address, key);
}
evm.stack
.push(h256_to_u256(runtime.storage(evm.contract_address)[&u256_to_h256(key)]));
.push(h256_to_u256(runtime.read_storage(evm.contract_address, key)));
// evm.gas_usage += if runtime.is_hot(evm.contract_address) {
// 100
// } else {
Expand All @@ -620,26 +623,50 @@ pub fn decode_instruction(evm: &mut EVMContext, runtime: &mut impl Runtime, debu

opcodes::SSTORE => {
let (key, value) = (pop!(), pop!());
println!("ket: {}, value: {}", key, value);
if !runtime.is_hot_index(evm.contract_address, key){
evm.gas_recorder.record_gas(2100);
runtime.mark_hot_index(evm.contract_address, key);
}
let base_dynamic_gas;
if !runtime.storage(evm.contract_address).contains_key(&u256_to_h256(key)) && value.eq(&U256::zero()) {
base_dynamic_gas = 100;
}
else {
base_dynamic_gas = if (runtime.storage(evm.contract_address).contains_key(&u256_to_h256(key))
&& !h256_to_u256(runtime.storage(evm.contract_address)[&u256_to_h256(key)]).eq(&U256::zero())) || value.eq(&U256::zero())
{
5000
} else {
20000
};
runtime.set_storage(evm.contract_address, key, u256_to_h256(value));
}
let (v_org, v_cur, v_new) = (
runtime.read_original_storage(evm.contract_address,key),
runtime.read_storage(evm.contract_address,key),
u256_to_h256(value),
);
println!("v_org: {}, v_cur: {}, v_new: {}", v_org, v_cur, v_new);
let dynamic_gas = if (v_cur.eq(&v_new) | !v_org.eq(&v_cur)) {
100
} else if v_org.eq(&ZERO_H256) {
20000
} else {
2900
};
let refund = if !v_org.eq(&ZERO_H256) && v_new.eq(&ZERO_H256) {
println!("Refund");
15000
} else {
0
};
runtime.set_storage(evm.contract_address, key, u256_to_h256(value));
evm.gas_recorder.record_gas(dynamic_gas);
evm.gas_recorder.subtract_gas(refund);
// let base_dynamic_gas;
// if !runtime.storage(evm.contract_address).contains_key(&u256_to_h256(key)) && value.eq(&U256::zero()) {
// println!("Deleting key");
// base_dynamic_gas = 100;
// }
// else {
// base_dynamic_gas = if (runtime.storage(evm.contract_address).contains_key(&u256_to_h256(key))
// && !h256_to_u256(runtime.storage(evm.contract_address)[&u256_to_h256(key)]).eq(&U256::zero())) || value.eq(&U256::zero())
// {
// 5000
// } else {
// 20000
// };
// runtime.set_storage(evm.contract_address, key, u256_to_h256(value));
// }
// TODO already written slot should always be 100
evm.gas_recorder.record_gas(base_dynamic_gas);
// evm.gas_recorder.record_gas(base_dynamic_gas);
},

opcodes::JUMP => {
Expand Down
5 changes: 5 additions & 0 deletions src/evm_logic/gas_calculator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub fn call_data_gas_cost(data: &Vec<u8>) -> usize {
#[derive(Copy,Clone)]
pub struct GasRecorder {
pub gas_usage: usize,
pub gas_refunds: usize,
}

impl GasRecorder {
Expand All @@ -38,6 +39,10 @@ impl GasRecorder {
self.gas_usage += memory_expansion_cost;
}

pub fn subtract_gas(&mut self, gas: usize) {
self.gas_refunds += gas;
}

fn memory_cost(current_memory_size_bytes: usize) -> usize {
if current_memory_size_bytes == 0 {
return 0;
Expand Down
1 change: 1 addition & 0 deletions src/evm_logic/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ lazy_static! {
"-57896044618658097711785492504343953926634992332820282019728792003956564819968"
)
.unwrap();
pub static ref ZERO_H256: H256 = u256_to_h256(U256::zero());
}

fn vec_to_fixed_array(bytes: Vec<u8>) -> [u8; 32] {
Expand Down
4 changes: 2 additions & 2 deletions src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ pub trait Runtime {
fn code(&self, address: U256) -> Vec<u8>;
fn exists(&self, address: U256) -> bool;
fn nonce(&self, address: U256) -> U256;
fn storage(&mut self, address: U256) -> &BTreeMap<H256, H256>;
fn original_storage(&mut self, address: U256) -> &BTreeMap<H256, H256>;
fn read_storage(&self, address: U256, index: U256) -> H256;
fn read_original_storage(&self, address: U256, index: U256) -> H256;

// Modify Contract State
fn is_deleted(&self, address: U256) -> bool;
Expand Down
4 changes: 2 additions & 2 deletions test_gen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,8 @@ pub fn generate_official_tests_from_file(input: TokenStream) -> TokenStream {
panic!("Expected a JSON object at the root");
}
}

for i in 0..num_tests {
// for i in 0..10 {
let test_name = Ident::new(
format!("run_test_{}", i).as_str(),
proc_macro2::Span::call_site(),
Expand All @@ -232,7 +232,7 @@ pub fn generate_official_tests_from_file(input: TokenStream) -> TokenStream {
#[test]
fn #test_name() {
let filename = #file_name;
run_test_file(filename.to_string(), true, #i);
run_test_file(filename.to_string(), true, #i as usize);
}
});
}
Expand Down
Loading

0 comments on commit b96a552

Please sign in to comment.