Skip to content

Commit

Permalink
arithmetic tests now failing need to confirm why, but some buffer tes…
Browse files Browse the repository at this point in the history
…ts passing
  • Loading branch information
max-wickham committed Mar 27, 2024
1 parent b96a552 commit 300fadb
Show file tree
Hide file tree
Showing 10 changed files with 425 additions and 221 deletions.
7 changes: 4 additions & 3 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@
- [_] Fix Calldata load, Code load etc.
- [_] Do general clean up
- [_] Better error handling
- [_] Refactor where macros and functions are
- [x] Refactor where macros and functions are
- [_] Remove lambdas
- [_] Move costs into a config
- [x] 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
- [_] Change to H256 instead of U256 where needed
- [_] 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 Expand Up @@ -57,4 +58,4 @@
## External

- [_] Submit fix for py eth vm, check that the address is hot
- [_] Submit fix for num256 conversion
- [_] Submit fix for num256 conversion between signed and unsigned
File renamed without changes.
209 changes: 209 additions & 0 deletions src/configs/gas_costs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
pub mod static_costs {
pub const G_ZERO: u64 = 0;
pub const G_JUMP_DEST: u64 = 1;
pub const G_BASE: u64 = 2;
pub const G_VERY_LOW: u64 = 3;
pub const G_LOW: u64 = 5;
pub const G_MID: u64 = 8;
pub const G_HIGH: u64 = 10;
pub const G_WARM_ACCESS: u64 = 100;
pub const G_ACCESS_LIST_ADDRESS: u64 = 2400;
pub const G_ACCESS_LIST_STORAGE: u64 = 1900;
pub const G_COLD_ACCOUNT_ACCESS: u64 = 2600;
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 G_SELF_DESTRUCT: u64 = 5000;
pub const G_CREATE: u64 = 32000;
pub const G_CODE_DEPOSIT: u64 = 200;
pub const G_CALL_VALUE: u64 = 9000;
pub const G_CALL_STIPEND: u64 = 2300;
pub const G_NEW_ACCOUNT: u64 = 25000;
pub const G_EXP: u64 = 10;
pub const G_EXP_BYTE: u64 = 50;
pub const G_MEMORY: u64 = 3;
pub const G_TX_CREATE: u64 = 32000;
pub const G_TX_DATA_ZERO: u64 = 4;
pub const G_TX_DATA_NON_ZERO: u64 = 16;
pub const G_TRANSACTION: u64 = 21000;
pub const G_LOG: u64 = 375;
pub const G_LOG_DATA: u64 = 8;
pub const G_LOG_TOPIC: u64 = 375;
pub const G_KECCAK256: u64 = 30;
pub const G_KECCAK256_WORD: u64 = 6;
pub const G_COPY: u64 = 3;
pub const G_BLOCK_HASH: u64 = 20;
}

pub mod dyn_costs {
enum DynamicCosts {
ExtCodeSize {
target_is_cold: bool,
},
Balance {
target_is_cold: bool,
},
ExtCodeHash {
target_is_cold: bool,
},
Call {
value: U256,
gas: U256,
target_is_cold: bool,
target_exists: bool,
},
CallCode {
/// Call value.
value: U256,
/// Call gas.
gas: U256,
/// True if target has not been previously accessed in this transaction
target_is_cold: bool,
/// Whether the target exists.
target_exists: bool,
},
DelegateCall {
/// Call gas.
gas: U256,
/// True if target has not been previously accessed in this transaction
target_is_cold: bool,
/// Whether the target exists.
target_exists: bool,
},
StaticCall {
/// Call gas.
gas: U256,
/// True if target has not been previously accessed in this transaction
target_is_cold: bool,
/// 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`.
Sha3 {
/// Length of the data.
len: U256,
},
/// Gas cost for `LOG`.
Log {
/// Topic length.
n: u8,
/// Data length.
len: U256,
},
/// Gas cost for `EXTCODECOPY`.
ExtCodeCopy {
/// True if target has not been previously accessed in this transaction
target_is_cold: bool,
/// Length.
len: U256,
},
Exp {
/// Power of `EXP`.
power: U256,
},
Create2 {
/// Length.
len: U256,
},
/// Gas cost for `SLOAD`.
SLoad {
/// True if target has not been previously accessed in this transaction
target_is_cold: bool,
},
}
}

impl GasCost {
// TODO add error here
pub fn cost(&self) -> u64 {
match self {
GasCost::ExtCodeSize { target_is_cold } => {
if *target_is_cold {
static_costs::G_COLDS_LOAD
} else {
static_costs::G_WARM_ACCESS
}
}
GasCost::Balance { target_is_cold } => {
if *target_is_cold {
static_costs::G_COLDS_LOAD
} else {
static_costs::G_WARM_ACCESS
}
}
GasCost::ExtCodeHash { target_is_cold } => {
if *target_is_cold {
static_costs::G_COLDS_LOAD
} else {
static_costs::G_WARM_ACCESS
}
}
GasCost::Call {
value,
gas,
target_is_cold,
target_exists,
} => {
if value != U256::zero() {
static_costs::G_CALL_VALUE
} else {
static_costs::G_CALL_STIPEND
}
}
GasCost::CallCode {
value,
gas,
target_is_cold,
target_exists,
} => {
if value != U256::zero() {
static_costs::G_CALL_VALUE
} else {
static_costs::G_CALL_STIPEND
}
}
GasCost::DelegateCall {
gas,
target_is_cold,
target_exists,
} => static_costs::G_CALL_STIPEND,
GasCost::StaticCall {
gas,
target_is_cold,
target_exists,
} => static_costs::G_CALL_STIPEND,
GasCost::SStore {
original,
current,
new,
target_is_cold,
} => {
if *original == *current && *current != *new {
static_costs::G_SSET
} else {
static_costs::G_SRESET
}
}
GasCost::Sha3 { len } => {
static_costs::G_KECCAK256 + (len.as_u64() / 32) * static_costs::G_KECCAK256_WORD
}
GasCost::Log { n, len } => {
static_costs::G_LOG
+ static_costs::G_LOG_TOPIC * (*n as u64)
+ static_costs::G_LOG_DATA * (len.as_u64() / 32)
}
_ => 0,
}
}
}
1 change: 1 addition & 0 deletions src/configs/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod bytecode_spec;
2 changes: 2 additions & 0 deletions src/evm_logic/evm.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
mod decoder;
mod macros;
mod call;

use crate::evm_logic::gas_calculator::{call_data_gas_cost, GasRecorder};
use crate::state::memory::Memory;
Expand Down
86 changes: 86 additions & 0 deletions src/evm_logic/evm/call.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
Convenient to keep this as a macro as allows for early returns and error handling
Should be converted to function once proper error handling is introduced
*/

use primitive_types::U256;

use crate::runtime::Runtime;
use super::{macros::pop, EVMContext, Message};

#[inline]
pub fn make_call(evm: &mut EVMContext, runtime: &mut impl Runtime, debug: bool, maintain_storage: bool) -> bool {
let (mut gas, address, value, args_offset, args_size, ret_offset, ret_size) = (
pop!(evm).as_u64(),
pop!(evm),
pop!(evm),
pop!(evm).as_usize(),
pop!(evm).as_usize(),
pop!(evm).as_usize(),
pop!(evm).as_usize(),
);
let code: Vec<u8> = runtime.code(address);
if !value.eq(&U256::zero()) {
evm.gas_recorder.record_gas(2300);
}
let one_64th_value =
(evm.gas_input - evm.gas_recorder.gas_usage.clone() as u64) * 63 / 64;
if gas > one_64th_value {
gas = one_64th_value;
}
let address_access_cost = if runtime.is_hot(address) {
100
} else {
runtime.mark_hot(address);
2600
};
// TODO check gas is okay
let mut sub_evm = EVMContext::create_sub_context(
if maintain_storage {
evm.contract_address
} else {
address
},
Message {
caller: evm.contract_address,
data: evm.memory.bytes[args_offset..args_offset + args_size].to_vec(),
value: value,
},
gas,
code,
evm.transaction.clone(),
evm.gas_price,
evm.nested_index + 1,
);
// TODO calculate cost of call data

let response = sub_evm.execute_program(runtime, debug);
evm.last_return_data = sub_evm.result;
// let current_memory_cost = evm.memory.memory_cost;
evm.memory.copy_from(
&mut evm.last_return_data,
0,
ret_offset,
ret_size,
&mut evm.gas_recorder,
);
evm.stack.push(U256::from(response as u64));
let code_execution_cost = sub_evm.gas_recorder.gas_usage;
let positive_value_cost = if !value.eq(&U256::zero()) { 6700 } else { 0 };
let value_to_empty_account_cost = if !value.eq(&U256::zero())
&& runtime.nonce(address).eq(&U256::zero())
&& runtime.code_size(address).eq(&U256::zero())
&& runtime.balance(address).eq(&U256::zero())
{
25000
} else {
0
};
evm.gas_recorder.record_gas(
(code_execution_cost
+ address_access_cost
+ positive_value_cost
+ value_to_empty_account_cost) as usize,
);
response
}
Loading

0 comments on commit 300fadb

Please sign in to comment.