Skip to content

Commit

Permalink
alll arithmetic tests and mem buffer tests passing
Browse files Browse the repository at this point in the history
  • Loading branch information
max-wickham committed Mar 30, 2024
1 parent ec80504 commit a481743
Show file tree
Hide file tree
Showing 18 changed files with 550 additions and 624 deletions.
18 changes: 15 additions & 3 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# TODO

- [_] Refactor errors to not use execution results for success
- [x] Fix memory problems on the return (when size is 0)
- [x] Refactor create and create 2, also get create to work
- [x] Fix calling costs and split up function
Expand All @@ -9,20 +10,31 @@
- [x] Refactor where macros and functions are
- [x] Remove lambdas
- [x] Move costs into a config
- [_] Separate gas cost logic from main logic
- [x] Separate gas cost logic from main logic
- [x] Get Memory Buffer tests to work
- Check CODECOPY
- Check CALLDATACOPY
- Check initial costs
- [_] Make gas refunds handle reverts
- [x] Make gas refunds handle reverts
- [_] Change to H256 instead of U256 where needed (and H160)
- [_] Only pass JSON once in tests, (maybe pass in the proc macro and then directly insert in the code)
- [x] Replace macro with method in decoder?
- [x] Replace closure with macro
- [x] Move entire decode step into inline function
- [?] Restructure code into a folder system
- [x] More specific error handling
- [x] Create better gas tracking, (especially for memory)
- [x] Create better gas tracking, (esplet success = 's: {
// Try to send value two times.
for _ in 0..2 {
value = match send(value) {
Ok(()) => break 's true,
Err(SendError(value)) => value,
}
}
false
};

ecially for memory)
- [x] Created gas tracker
- [x] Apply gas tracker to memory operations
- [x] Apply gas tracker to all other operations
Expand Down
69 changes: 43 additions & 26 deletions src/configs/gas_costs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::ops::Div;

use primitive_types::{H256, U256};

use crate::evm_logic::util::ZERO;
use crate::evm_logic::util::{ZERO, ZERO_H256};

pub mod static_costs {
pub const G_ZERO: u64 = 0;
Expand All @@ -19,7 +19,7 @@ pub mod static_costs {
pub const G_COLDS_LOAD: u64 = 2100;
pub const G_SSET: u64 = 20000;
pub const G_SRESET: u64 = 2900;
pub const R_SCLEAR: u64 = 4800;
pub const R_SCLEAR: u64 = 15000;
pub const G_SELF_DESTRUCT: u64 = 5000;
pub const G_CREATE: u64 = 32000;
pub const G_CODE_DEPOSIT: u64 = 200;
Expand Down Expand Up @@ -66,16 +66,6 @@ pub enum DynamicCosts {
/// Whether the target exists.
target_exists: bool,
},
SStore {
/// Original value.
original: H256,
/// Current value.
current: H256,
/// New value.
new: H256,
/// True if target has not been previously accessed in this transaction
target_is_cold: bool,
},
/// Gas cost for `SHA3`.
Keccak256 {
/// Length of the data.
Expand Down Expand Up @@ -105,6 +95,12 @@ pub enum DynamicCosts {
/// True if target has not been previously accessed in this transaction
target_is_cold: bool,
},
SStore {
original: H256,
current: H256,
new: H256,
target_is_cold: bool,
},
Copy {
size_bytes: usize,
},
Expand All @@ -118,14 +114,14 @@ impl DynamicCosts {
// TODO add error here
pub fn cost(&self) -> u64 {
match self {
DynamicCosts::ExtCodeSize { target_is_cold } => {
DynamicCosts::Balance { target_is_cold } => {
if *target_is_cold {
static_costs::G_COLDS_LOAD
} else {
static_costs::G_WARM_ACCESS
}
}
DynamicCosts::Balance { target_is_cold } => {
DynamicCosts::ExtCodeSize { target_is_cold } => {
if *target_is_cold {
static_costs::G_COLDS_LOAD
} else {
Expand Down Expand Up @@ -158,18 +154,6 @@ impl DynamicCosts {
static_costs::G_NEW_ACCOUNT
} else {0}
}
DynamicCosts::SStore {
original,
current,
new,
target_is_cold,
} => {
if *original == *current && *current != *new {
static_costs::G_SSET
} else {
static_costs::G_SRESET
}
}
DynamicCosts::Keccak256 { len } => {
println!("Len in Keccak256: {}", len);
static_costs::G_KECCAK256 + (len.div_ceil(32)) * static_costs::G_KECCAK256_WORD
Expand Down Expand Up @@ -205,6 +189,39 @@ impl DynamicCosts {
println!("Code Size {}",deployed_code_size);
static_costs::G_CREATE + static_costs::G_KECCAK256_WORD * (*deployed_code_size as u64).div_ceil(32)
}
DynamicCosts::SLoad { target_is_cold } => {
println!("Is cold: {}", target_is_cold);
if *target_is_cold {
static_costs::G_COLDS_LOAD
} else {
static_costs::G_WARM_ACCESS
}
}
DynamicCosts::SStore { original, current, new, target_is_cold } => {
let mut gas_cost = if *target_is_cold { static_costs::G_COLDS_LOAD } else { 0};
gas_cost += if current.eq(&new) | !original.eq(&current) {
println!("Warm access");
static_costs::G_WARM_ACCESS
} else if original.eq(&ZERO_H256) {
static_costs::G_SSET
} else {
static_costs::G_SRESET
};
gas_cost

}
_ => 0,
}
}
pub fn refund(&self) -> u64 {
match self {
DynamicCosts::SStore { original, current, new, target_is_cold } => {
if !original.eq(&ZERO_H256) && new.eq(&ZERO_H256) {
static_costs::R_SCLEAR
} else {
0
}
}
_ => 0,
}
}
Expand Down
151 changes: 67 additions & 84 deletions src/evm_logic/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ mod create;
mod decoder;
pub mod macros;

use std::f32::consts::E;

use crate::configs::gas_costs::static_costs;
use crate::evm_logic::gas_calculator::GasRecorder;
use crate::result::{Error, ExecutionResult, ExecutionSuccess};
use crate::evm_logic::gas_recorder::GasRecorder;
use crate::result::{ExecutionError, ExecutionResult, ExecutionSuccess};
use crate::runtime::Runtime;

use super::state::memory::Memory;
Expand Down Expand Up @@ -42,47 +44,6 @@ pub struct EVMContext {
}

impl EVMContext {
#[inline]
pub fn execute_transaction(
runtime: &mut impl Runtime,
contract: U256,
origin: U256,
gas: u64,
gas_price: U256,
value: U256,
data: Vec<u8>,
debug: bool,
) -> (ExecutionResult, usize) {
let message = Message {
caller: contract,
value: value,
data: data,
};
let transaction = Transaction {
origin: origin,
gas_price: gas_price,
};
let mut evm = EVMContext::create_sub_context(
contract,
message,
gas,
runtime.code(contract),
transaction,
gas_price,
0,
false,
);
evm.gas_recorder.record_gas_usage(static_costs::G_TRANSACTION);
evm.gas_recorder.record_call_data_gas_usage(&evm.message.data);
if debug {
println!("Call Data Gas Cost: {:x}", evm.gas_recorder.gas_usage);
}
let result = evm.execute_program(runtime, debug);
// TODO move this into gas_recorder
let gas_usage = evm.gas_recorder.gas_usage
- usize::min(evm.gas_recorder.gas_refunds, evm.gas_recorder.gas_usage / 2);
return (result, gas_usage);
}

#[inline]
fn create_sub_context(
Expand All @@ -99,7 +60,7 @@ impl EVMContext {
stack: Stack::new(),
memory: Memory::new(),
program: Memory::from(
code,
&code,
Some(&mut GasRecorder {
gas_input: gas as usize,
gas_usage: 0,
Expand Down Expand Up @@ -128,51 +89,37 @@ impl EVMContext {
fn execute_program(&mut self, runtime: &mut impl Runtime, debug: bool) -> ExecutionResult {
runtime.add_context();

let result = {
let mut result;
if self.program.len() != 0 {
loop {
result = self.execute_next_instruction(runtime, debug);
match &result {
ExecutionResult::Err(_) => {
break;
}
ExecutionResult::Success(success) => match success {
ExecutionSuccess::Return(_) | ExecutionSuccess::Stop => {
break;
}
_ => {}
},
}
let mut result;
if self.program.len() != 0 {
loop {
result = self.execute_next_instruction(runtime, debug);
match &result {
ExecutionResult::InProgress => {},
_ => {break;}
}
} else {
result = ExecutionResult::Err(Error::InvalidMemSize);
}
if debug {
println!(
"Program Gas Usage : {:x}",
if self.gas_recorder.gas_usage > self.gas_input as usize {
self.gas_input as u64
} else {
self.gas_input - self.gas_recorder.gas_usage as u64
}
);
}
result
};
} else {
result = ExecutionResult::Error(ExecutionError::InvalidMemSize);
}
// TODO move this into gas_recorder
self.gas_recorder.gas_usage = if self.gas_recorder.gas_usage > self.gas_input as usize {
self.gas_input as u64
} else {
self.gas_recorder.gas_usage as u64
} as usize;
println!("Sub Gas Usage {:x}", self.gas_recorder.gas_usage);
if debug {
println!("Sub Gas Usage {:x}", self.gas_recorder.gas_usage);
}
match result {
ExecutionResult::Success(_) => {
runtime.merge_context();
}
ExecutionResult::Err(_) => {
ExecutionResult::Error(_) => {
runtime.revert_context();
}
ExecutionResult::InProgress => {
panic!("Program shouldn't have excited in progress");
}
}

result
Expand All @@ -189,15 +136,10 @@ impl EVMContext {

#[inline]
fn check_gas_usage(&self) -> ExecutionResult {
match (self.gas_recorder.gas_usage
- self
.gas_recorder
.gas_refunds
.min(self.gas_recorder.gas_usage))
> self.gas_input as usize
match !self.gas_recorder.is_valid_with_refunds()
{
true => ExecutionResult::Err(crate::result::Error::InsufficientGas),
false => ExecutionResult::Success(ExecutionSuccess::Unknown),
true => ExecutionResult::Error(ExecutionError::InsufficientGas),
false => ExecutionResult::InProgress,
}
}
}
Expand All @@ -206,3 +148,44 @@ impl EVMContext {
// message data
// program data
// mem data
#[inline]
pub fn execute_transaction(
runtime: &mut impl Runtime,
contract_address: U256,
origin: U256,
gas: u64,
gas_price: U256,
value: U256,
data: &[u8],
debug: bool,
) -> (ExecutionResult, usize) {
let message = Message {
caller: contract_address,
value: value,
data: data.to_vec(),
};
let transaction = Transaction {
origin: origin,
gas_price: gas_price,
};
let mut evm = EVMContext::create_sub_context(
contract_address,
message,
gas,
runtime.code(contract_address),
transaction,
gas_price,
0,
false,
);
evm.gas_recorder
.record_gas_usage(static_costs::G_TRANSACTION);
evm.gas_recorder
.record_call_data_gas_usage(&evm.message.data);
if debug {
println!("Call Data Gas Cost: {:x}", evm.gas_recorder.gas_usage);
}
let result = evm.execute_program(runtime, debug);
let gas_usage = evm.gas_recorder.usage_with_refunds();
return (result, gas_usage);
}
Loading

0 comments on commit a481743

Please sign in to comment.