Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

External cost recorder #170

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
- uses: actions/checkout@v2
- name: Build
run: cargo build --verbose
- name: Build for feature
- name: Build for feature (tracing)
run: cargo build --features tracing --verbose
- name: Run tests
run: cargo test --verbose
Expand Down
13 changes: 13 additions & 0 deletions core/src/external.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use primitive_types::H160;

/// Operations for recording external costs
pub enum ExternalOperation {
/// Reading basic account from storage. Fixed size.
AccountBasicRead,
/// Reading address code from storage. Dynamic size.
AddressCodeRead(H160),
/// Basic check for account emptiness. Fixed size.
IsEmpty,
/// Writing to storage. Fixed size.
Write,
}
2 changes: 2 additions & 0 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ extern crate alloc;

mod error;
mod eval;
mod external;
mod memory;
mod opcode;
mod stack;
mod utils;
mod valids;

pub use crate::error::{Capture, ExitError, ExitFatal, ExitReason, ExitRevert, ExitSucceed, Trap};
pub use crate::external::ExternalOperation;
pub use crate::memory::Memory;
pub use crate::opcode::Opcode;
pub use crate::stack::Stack;
Expand Down
25 changes: 20 additions & 5 deletions gasometer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,10 @@ pub fn dynamic_opcode_cost<H: Handler>(
value: U256::from_big_endian(&stack.peek(2)?[..]),
gas: U256::from_big_endian(&stack.peek(0)?[..]),
target_is_cold: handler.is_cold(target, None)?,
target_exists: handler.exists(target),
target_exists: {
handler.record_external_operation(evm_core::ExternalOperation::IsEmpty)?;
handler.exists(target)
},
}
}
Opcode::STATICCALL => {
Expand All @@ -519,7 +522,10 @@ pub fn dynamic_opcode_cost<H: Handler>(
GasCost::StaticCall {
gas: U256::from_big_endian(&stack.peek(0)?[..]),
target_is_cold: handler.is_cold(target, None)?,
target_exists: handler.exists(target),
target_exists: {
handler.record_external_operation(evm_core::ExternalOperation::IsEmpty)?;
handler.exists(target)
},
}
}
Opcode::SHA3 => GasCost::Sha3 {
Expand Down Expand Up @@ -553,7 +559,10 @@ pub fn dynamic_opcode_cost<H: Handler>(
GasCost::DelegateCall {
gas: U256::from_big_endian(&stack.peek(0)?[..]),
target_is_cold: handler.is_cold(target, None)?,
target_exists: handler.exists(target),
target_exists: {
handler.record_external_operation(evm_core::ExternalOperation::IsEmpty)?;
handler.exists(target)
},
}
}
Opcode::DELEGATECALL => GasCost::Invalid(opcode),
Expand Down Expand Up @@ -606,7 +615,10 @@ pub fn dynamic_opcode_cost<H: Handler>(
GasCost::Suicide {
value: handler.balance(address),
target_is_cold: handler.is_cold(target, None)?,
target_exists: handler.exists(target),
target_exists: {
handler.record_external_operation(evm_core::ExternalOperation::IsEmpty)?;
handler.exists(target)
},
already_removed: handler.deleted(address),
}
}
Expand All @@ -620,7 +632,10 @@ pub fn dynamic_opcode_cost<H: Handler>(
value: U256::from_big_endian(&stack.peek(2)?[..]),
gas: U256::from_big_endian(&stack.peek(0)?[..]),
target_is_cold: handler.is_cold(target, None)?,
target_exists: handler.exists(target),
target_exists: {
handler.record_external_operation(evm_core::ExternalOperation::IsEmpty)?;
handler.exists(target)
},
}
}

Expand Down
40 changes: 29 additions & 11 deletions runtime/src/eval/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,34 +90,52 @@ pub fn base_fee<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
Control::Continue
}

pub fn extcodesize<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
pub fn extcodesize<H: Handler>(runtime: &mut Runtime, handler: &mut H) -> Control<H> {
pop!(runtime, address);
push_u256!(runtime, handler.code_size(address.into()));
if let Err(e) =
handler.record_external_operation(crate::ExternalOperation::AddressCodeRead(address.into()))
{
return Control::Exit(e.into());
}
let code_size = handler.code_size(address.into());
push_u256!(runtime, code_size);

Control::Continue
}

pub fn extcodehash<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
pub fn extcodehash<H: Handler>(runtime: &mut Runtime, handler: &mut H) -> Control<H> {
pop!(runtime, address);
push!(runtime, handler.code_hash(address.into()));
if let Err(e) =
handler.record_external_operation(crate::ExternalOperation::AddressCodeRead(address.into()))
{
return Control::Exit(e.into());
}
let code_hash = handler.code_hash(address.into());
push!(runtime, code_hash);

Control::Continue
}

pub fn extcodecopy<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
pub fn extcodecopy<H: Handler>(runtime: &mut Runtime, handler: &mut H) -> Control<H> {
pop!(runtime, address);
pop_u256!(runtime, memory_offset, code_offset, len);

try_or_fail!(runtime
.machine
.memory_mut()
.resize_offset(memory_offset, len));
match runtime.machine.memory_mut().copy_large(
memory_offset,
code_offset,
len,
&handler.code(address.into()),
) {

if let Err(e) =
handler.record_external_operation(crate::ExternalOperation::AddressCodeRead(address.into()))
{
return Control::Exit(e.into());
}
let code = handler.code(address.into());
match runtime
.machine
.memory_mut()
.copy_large(memory_offset, code_offset, len, &code)
{
Ok(()) => (),
Err(e) => return Control::Exit(e.into()),
};
Expand Down
3 changes: 3 additions & 0 deletions runtime/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,7 @@ pub trait Handler {
fn other(&mut self, opcode: Opcode, _stack: &mut Machine) -> Result<(), ExitError> {
Err(ExitError::InvalidCode(opcode))
}

/// Records some associated `ExternalOperation`.
fn record_external_operation(&mut self, op: crate::ExternalOperation) -> Result<(), ExitError>;
}
12 changes: 9 additions & 3 deletions src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
mod memory;

pub use self::memory::{MemoryAccount, MemoryBackend, MemoryVicinity};

use crate::ExitError;
use alloc::vec::Vec;
use primitive_types::{H160, H256, U256};

/// Basic account information.
#[derive(Clone, Eq, PartialEq, Debug, Default)]
#[cfg_attr(
Expand Down Expand Up @@ -50,7 +49,7 @@ pub enum Apply<I> {
}

/// EVM backend.
#[auto_impl::auto_impl(&, Arc, Box)]
//#[auto_impl::auto_impl(&, Arc, Box)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we still implement this for &mut and Box?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyway, I'm fine keeping this as is for now.

A refactoring we can do is to move record_external_operation into a separate trait Record, and then add yet another type parameter to StackExecutor R: Record. Then we can uncomment this again.

But the changes are already huge so we can do that in a separate PR.

pub trait Backend {
/// Gas price. Unused for London.
fn gas_price(&self) -> U256;
Expand Down Expand Up @@ -85,6 +84,13 @@ pub trait Backend {
fn storage(&self, address: H160, index: H256) -> H256;
/// Get original storage value of address at index, if available.
fn original_storage(&self, address: H160, index: H256) -> Option<H256>;

fn record_external_operation(
&mut self,
_op: crate::ExternalOperation,
) -> Result<(), ExitError> {
Ok(())
}
}

/// EVM backend that can apply changes.
Expand Down
Loading