Skip to content

Commit

Permalink
feat: save block compacted changes in inmemory storage
Browse files Browse the repository at this point in the history
  • Loading branch information
dinhani-cw committed Feb 23, 2024
1 parent 4f5faaa commit 3b61e33
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 55 deletions.
9 changes: 0 additions & 9 deletions src/eth/primitives/execution_value_change.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use crate::ext::not;

/// Changes that happened to an account value during a transaction.
#[derive(Debug, Clone, PartialEq, Eq, fake::Dummy, serde::Serialize, serde::Deserialize)]
pub struct ExecutionValueChange<T>
Expand All @@ -22,10 +20,6 @@ impl<T> ValueState<T> {
matches!(self, Self::Set(_))
}

pub fn is_not_set(&self) -> bool {
not(self.is_set())
}

pub fn take(self) -> Option<T> {
if let Self::Set(value) = self {
Some(value)
Expand Down Expand Up @@ -65,9 +59,6 @@ where

/// Sets the modified value of an original value.
pub fn set_modified(&mut self, value: T) {
if self.original.is_not_set() {
tracing::warn!("setting modified value without original value present.");
}
self.modified = ValueState::Set(value);
}

Expand Down
67 changes: 27 additions & 40 deletions src/eth/storage/inmemory/inmemory_permanent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::eth::primitives::Block;
use crate::eth::primitives::BlockNumber;
use crate::eth::primitives::BlockSelection;
use crate::eth::primitives::Bytes;
use crate::eth::primitives::Execution;
use crate::eth::primitives::ExecutionAccountChanges;
use crate::eth::primitives::ExecutionConflicts;
use crate::eth::primitives::ExecutionConflictsBuilder;
use crate::eth::primitives::Hash;
Expand Down Expand Up @@ -69,9 +69,8 @@ impl InMemoryPermanentStorage {
state.logs.clear();
}

async fn save_account_changes(state: &mut InMemoryPermanentStorageState, number: BlockNumber, execution: Execution) {
let is_success = execution.is_success();
for changes in execution.changes {
async fn save_account_changes(state: &mut InMemoryPermanentStorageState, number: BlockNumber, account_changes: Vec<ExecutionAccountChanges>) {
for changes in account_changes {
let account = state
.accounts
.entry(changes.address.clone())
Expand All @@ -85,33 +84,31 @@ impl InMemoryPermanentStorage {
account.balance.push(number, balance);
}

if is_success {
// bytecode
if let Some(Some(bytecode)) = changes.bytecode.take_modified() {
account.bytecode.push(number, Some(bytecode));
}
// bytecode
if let Some(Some(bytecode)) = changes.bytecode.take_modified() {
account.bytecode.push(number, Some(bytecode));
}

// slots
for (_, slot) in changes.slots {
if let Some(slot) = slot.take_modified() {
match account.slots.get_mut(&slot.index) {
Some(slot_history) => {
slot_history.push(number, slot);
}
None => {
account.slots.insert(slot.index.clone(), InMemoryHistory::new(number, slot));
}
// slots
for (_, slot) in changes.slots {
if let Some(slot) = slot.take_modified() {
match account.slots.get_mut(&slot.index) {
Some(slot_history) => {
slot_history.push(number, slot);
}
None => {
account.slots.insert(slot.index.clone(), InMemoryHistory::new(number, slot));
}
}
}
}
}
}

async fn check_conflicts(state: &InMemoryPermanentStorageState, execution: &Execution) -> Option<ExecutionConflicts> {
async fn check_conflicts(state: &InMemoryPermanentStorageState, account_changes: &[ExecutionAccountChanges]) -> Option<ExecutionConflicts> {
let mut conflicts = ExecutionConflictsBuilder::default();

for change in &execution.changes {
for change in account_changes {
let address = &change.address;

if let Some(account) = state.accounts.get(address) {
Expand Down Expand Up @@ -287,8 +284,11 @@ impl PermanentStorage for InMemoryPermanentStorage {
async fn save_block(&self, block: Block) -> anyhow::Result<(), StorageError> {
let mut state = self.lock_write().await;

// keep track of current block if we need to rollback
let current_block = self.read_current_block_number().await?;
// check conflicts before persisting any state changes
let account_changes = block.compact_execution_changes();
if let Some(conflicts) = Self::check_conflicts(&state, &account_changes).await {
return Err(StorageError::Conflict(conflicts));
}

// save block
tracing::debug!(number = %block.number(), "saving block");
Expand All @@ -299,30 +299,17 @@ impl PermanentStorage for InMemoryPermanentStorage {
// save transactions
for transaction in block.transactions.clone() {
tracing::debug!(hash = %transaction.input.hash, "saving transaction");

// check conflicts after each transaction because a transaction can depend on the previous from the same block
if let Some(conflicts) = Self::check_conflicts(&state, &transaction.execution).await {
// release lock and rollback to previous block
drop(state);
self.reset_at(current_block).await?;

// inform error
return Err(StorageError::Conflict(conflicts));
}

// save transaction
state.transactions.insert(transaction.input.hash.clone(), transaction.clone());

// save logs
if transaction.is_success() {
for log in transaction.logs {
state.logs.push(log);
}
}

// save execution changes
Self::save_account_changes(&mut state, *block.number(), transaction.execution).await;
}

// save block execution changes
Self::save_account_changes(&mut state, *block.number(), block.compact_execution_changes()).await;

Ok(())
}

Expand Down
9 changes: 3 additions & 6 deletions src/eth/storage/inmemory/inmemory_temporary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ impl TemporaryStorage for InMemoryTemporaryStorage {

async fn save_account_changes(&self, execution: Execution) -> anyhow::Result<()> {
let mut state = self.lock_write().await;
let is_success = execution.is_success();
for changes in execution.changes {
let account = state
.accounts
Expand All @@ -107,11 +106,9 @@ impl TemporaryStorage for InMemoryTemporaryStorage {
}

// slots
if is_success {
for (_, slot) in changes.slots {
if let Some(slot) = slot.take() {
account.slots.insert(slot.index.clone(), slot);
}
for (_, slot) in changes.slots {
if let Some(slot) = slot.take() {
account.slots.insert(slot.index.clone(), slot);
}
}
}
Expand Down

0 comments on commit 3b61e33

Please sign in to comment.