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

feat: environment logs #911

Merged
merged 12 commits into from
Feb 29, 2024
231 changes: 111 additions & 120 deletions Cargo.lock

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions core/src/database/inspector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,16 @@ impl ArbiterInspector {
}
}

impl<DB: Database> Inspector<DB> for ArbiterInspector {
impl Inspector<ArbiterDB> for ArbiterInspector {
#[inline]
fn initialize_interp(&mut self, interp: &mut Interpreter, context: &mut EvmContext<DB>) {
fn initialize_interp(&mut self, interp: &mut Interpreter, context: &mut EvmContext<ArbiterDB>) {
if let Some(gas) = &mut self.gas {
gas.initialize_interp(interp, context);
}
}

#[inline]
fn step_end(&mut self, interp: &mut Interpreter, context: &mut EvmContext<DB>) {
fn step_end(&mut self, interp: &mut Interpreter, context: &mut EvmContext<ArbiterDB>) {
if let Some(gas) = &mut self.gas {
gas.step_end(interp, context);
}
Expand All @@ -60,7 +60,7 @@ impl<DB: Database> Inspector<DB> for ArbiterInspector {
#[inline]
fn call(
&mut self,
context: &mut EvmContext<DB>,
context: &mut EvmContext<ArbiterDB>,
inputs: &mut CallInputs,
return_memory_offset: Range<usize>,
) -> Option<CallOutcome> {
Expand All @@ -74,7 +74,7 @@ impl<DB: Database> Inspector<DB> for ArbiterInspector {
#[inline]
fn call_end(
&mut self,
context: &mut EvmContext<DB>,
context: &mut EvmContext<ArbiterDB>,
inputs: &CallInputs,
outcome: CallOutcome,
) -> CallOutcome {
Expand All @@ -88,7 +88,7 @@ impl<DB: Database> Inspector<DB> for ArbiterInspector {
#[inline]
fn create_end(
&mut self,
_context: &mut EvmContext<DB>,
_context: &mut EvmContext<ArbiterDB>,
_inputs: &CreateInputs,
outcome: CreateOutcome,
) -> CreateOutcome {
Expand Down
66 changes: 49 additions & 17 deletions core/src/database/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,42 @@ use super::*;
pub mod fork;
pub mod inspector;

/// A [`ArbiterDB`] is a wrapper around a [`CacheDB`] that is used to provide
/// access to the [`environment::Environment`]'s database to multiple
/// A [`ArbiterDB`] is contains both a [`CacheDB`] that is used to provide
/// state for the [`environment::Environment`]'s as well as for multiple
/// [`coprocessor::Coprocessor`]s.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ArbiterDB(pub Arc<RwLock<CacheDB<EmptyDB>>>);
/// The `logs` field is a [`HashMap`] to store [`ethers::types::Log`]s that can
/// be queried from at any point.
#[derive(Debug, Serialize, Deserialize)]
pub struct ArbiterDB {
/// The state of the `ArbiterDB`. This is a `CacheDB` that is used to
/// provide a db for the `Environment` to use.
pub state: Arc<RwLock<CacheDB<EmptyDB>>>,

/// The logs of the `ArbiterDB`. This is a `HashMap` that is used to store
/// logs that can be queried from at any point.
pub logs: Arc<RwLock<HashMap<U256, Vec<eLog>>>>,
}

// Implement `Clone` by hand so we utilize the `Arc`'s `Clone` implementation.
impl Clone for ArbiterDB {
fn clone(&self) -> Self {
Self {
state: self.state.clone(),
logs: self.logs.clone(),
}
}
}

impl ArbiterDB {
/// Create a new `ArbiterDB`.
pub fn new() -> Self {
Self(Arc::new(RwLock::new(CacheDB::new(EmptyDB::new()))))
Self {
state: Arc::new(RwLock::new(CacheDB::new(EmptyDB::new()))),
logs: Arc::new(RwLock::new(HashMap::new())),
}
}

/// Write the `ArbiterDB` to a file at the given path.
/// Write the `ArbiterDB` to a file at the given path.``
pub fn write_to_file(&self, path: &str) -> io::Result<()> {
// Serialize the ArbiterDB
let serialized = serde_json::to_string(self)?;
Expand All @@ -49,9 +72,18 @@ impl ArbiterDB {
let mut file = fs::File::open(path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;

// Deserialize the content into ArbiterDB
let cache_db = serde_json::from_str(&contents)?;
Ok(Self(Arc::new(RwLock::new(cache_db))))
#[derive(Deserialize)]
struct TempDB {
state: Option<CacheDB<EmptyDB>>,
logs: Option<HashMap<U256, Vec<eLog>>>,
}
let temp_db: TempDB = serde_json::from_str(&contents)?;
Ok(Self {
state: Arc::new(RwLock::new(temp_db.state.unwrap_or_default())),
logs: Arc::new(RwLock::new(temp_db.logs.unwrap_or_default())),
})
}
}

Expand All @@ -77,23 +109,23 @@ impl Database for ArbiterDB {
&mut self,
address: revm::primitives::Address,
) -> Result<Option<AccountInfo>, Self::Error> {
self.0.write().unwrap().basic(address)
self.state.write().unwrap().basic(address)
}

fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
self.0.write().unwrap().code_by_hash(code_hash)
self.state.write().unwrap().code_by_hash(code_hash)
}

fn storage(
&mut self,
address: revm::primitives::Address,
index: U256,
) -> Result<U256, Self::Error> {
self.0.write().unwrap().storage(address, index)
self.state.write().unwrap().storage(address, index)
}

fn block_hash(&mut self, number: U256) -> Result<B256, Self::Error> {
self.0.write().unwrap().block_hash(number)
self.state.write().unwrap().block_hash(number)
}
}

Expand All @@ -104,23 +136,23 @@ impl DatabaseRef for ArbiterDB {
&self,
address: revm::primitives::Address,
) -> Result<Option<AccountInfo>, Self::Error> {
self.0.read().unwrap().basic_ref(address)
self.state.read().unwrap().basic_ref(address)
}

fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
self.0.read().unwrap().code_by_hash_ref(code_hash)
self.state.read().unwrap().code_by_hash_ref(code_hash)
}

fn storage_ref(
&self,
address: revm::primitives::Address,
index: U256,
) -> Result<U256, Self::Error> {
self.0.read().unwrap().storage_ref(address, index)
self.state.read().unwrap().storage_ref(address, index)
}

fn block_hash_ref(&self, number: U256) -> Result<B256, Self::Error> {
self.0.read().unwrap().block_hash_ref(number)
self.state.read().unwrap().block_hash_ref(number)
}
}

Expand All @@ -129,7 +161,7 @@ impl DatabaseCommit for ArbiterDB {
&mut self,
changes: hashbrown::HashMap<revm::primitives::Address, revm::primitives::Account>,
) {
self.0.write().unwrap().commit(changes)
self.state.write().unwrap().commit(changes)
}
}

Expand Down
7 changes: 7 additions & 0 deletions core/src/environment/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ pub(crate) enum Outcome {
/// Currently this may be the block number, block timestamp, gas price, or
/// balance of an account.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[allow(clippy::large_enum_variant)]
pub(crate) enum EnvironmentData {
/// The query is for the block number of the [`EVM`].
BlockNumber,
Expand All @@ -161,6 +162,12 @@ pub(crate) enum EnvironmentData {
// TODO: Rename this to `Nonce`?
/// The query is for the nonce of an account given by the inner `Address`.
TransactionCount(eAddress),

/// Query for logs in a range of blocks.
Logs {
/// The filter to use to query for logs
filter: Filter,
},
}

/// [`ReceiptData`] is a structure that holds the block number, transaction
Expand Down
Loading
Loading