Skip to content

Commit

Permalink
fix: Prevent contiguous blockchain storage from bitrotting
Browse files Browse the repository at this point in the history
  • Loading branch information
Xanewok committed Sep 10, 2024
1 parent f6f22d2 commit 198c847
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 16 deletions.
6 changes: 5 additions & 1 deletion crates/edr_evm/src/blockchain/storage.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
mod contiguous;
mod reservable;
mod sparse;

use edr_eth::B256;

pub use self::{reservable::ReservableSparseBlockchainStorage, sparse::SparseBlockchainStorage};
pub use self::{
contiguous::ContiguousBlockchainStorage, reservable::ReservableSparseBlockchainStorage,
sparse::SparseBlockchainStorage,
};

/// An error that occurs when trying to insert a block into storage.
#[derive(Debug, thiserror::Error)]
Expand Down
52 changes: 37 additions & 15 deletions crates/edr_evm/src/blockchain/storage/contiguous.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,40 @@
use std::sync::Arc;
//! A more cache-friendly block storage implementation.
//!
//! While this does not support block reservations, which we require[^1], it
//! still may be useful for applications that do not.
//!
//! [^1]: for that, we internally use the sparse implementation via
//! [`SparseBlockchainStorage`](super::sparse::SparseBlockchainStorage).
use edr_eth::{receipt::BlockReceipt, B256, U256};
use std::{marker::PhantomData, sync::Arc};

use edr_eth::{receipt::BlockReceipt, transaction::Transaction, B256, U256};
use revm::primitives::HashMap;

use crate::{Block, LocalBlock};
use crate::{chain_spec::ChainSpec, Block, LocalBlock};

use super::InsertError;

/// A storage solution for storing a Blockchain's blocks contiguously in-memory.
#[derive(Clone, Default, Debug)]
pub struct ContiguousBlockchainStorage<BlockT: Block + Clone + ?Sized> {
pub struct ContiguousBlockchainStorage<BlockT, ChainSpecT>
where
BlockT: Block<ChainSpecT> + Clone + ?Sized,
ChainSpecT: ChainSpec,
{
blocks: Vec<BlockT>,
hash_to_block: HashMap<B256, BlockT>,
total_difficulties: Vec<U256>,
transaction_hash_to_block: HashMap<B256, BlockT>,
transaction_hash_to_receipt: HashMap<B256, Arc<BlockReceipt>>,
phantom: PhantomData<ChainSpecT>,
}

impl<BlockT: Block + Clone> ContiguousBlockchainStorage<BlockT> {
impl<BlockT, ChainSpecT> ContiguousBlockchainStorage<BlockT, ChainSpecT>
where
BlockT: Block<ChainSpecT> + Clone,
ChainSpecT: ChainSpec,
{
/// Retrieves the instance's blocks.
pub fn blocks(&self) -> &[BlockT] {
&self.blocks
Expand Down Expand Up @@ -101,10 +118,14 @@ impl<BlockT: Block + Clone> ContiguousBlockchainStorage<BlockT> {
}
}

impl<BlockT: Block + Clone + From<LocalBlock>> ContiguousBlockchainStorage<BlockT> {
impl<BlockT, ChainSpecT> ContiguousBlockchainStorage<BlockT, ChainSpecT>
where
BlockT: Block<ChainSpecT> + Clone + From<LocalBlock<ChainSpecT>>,
ChainSpecT: ChainSpec,
{
/// Constructs a new instance with the provided block.
pub fn with_block(block: LocalBlock, total_difficulty: U256) -> Self {
let block_hash = block.hash();
pub fn with_block(block: LocalBlock<ChainSpecT>, total_difficulty: U256) -> Self {
let block_hash = *block.hash();

let transaction_hash_to_receipt = block
.transaction_receipts()
Expand All @@ -117,25 +138,26 @@ impl<BlockT: Block + Clone + From<LocalBlock>> ContiguousBlockchainStorage<Block
let transaction_hash_to_block = block
.transactions()
.iter()
.map(|transaction| (transaction.hash(), block.clone()))
.map(|transaction| (*transaction.transaction_hash(), block.clone()))
.collect();

let mut hash_to_block = HashMap::new();
hash_to_block.insert(*block_hash, block.clone());
hash_to_block.insert(block_hash, block.clone());

Self {
total_difficulties: vec![total_difficulty],
blocks: vec![block],
hash_to_block,
transaction_hash_to_block,
transaction_hash_to_receipt,
phantom: PhantomData,
}
}

/// Inserts a block, failing if a block with the same hash already exists.
pub fn insert_block(
&mut self,
block: LocalBlock,
block: LocalBlock<ChainSpecT>,
total_difficulty: U256,
) -> Result<&BlockT, InsertError> {
let block_hash = block.hash();
Expand All @@ -151,10 +173,10 @@ impl<BlockT: Block + Clone + From<LocalBlock>> ContiguousBlockchainStorage<Block

if let Some(transaction) = block.transactions().iter().find(|transaction| {
self.transaction_hash_to_block
.contains_key(&transaction.hash())
.contains_key(transaction.transaction_hash())
}) {
return Err(InsertError::DuplicateTransaction {
hash: transaction.hash(),
hash: *transaction.transaction_hash(),
});
}

Expand All @@ -170,7 +192,7 @@ impl<BlockT: Block + Clone + From<LocalBlock>> ContiguousBlockchainStorage<Block
/// any transactions with the same hash.
pub unsafe fn insert_block_unchecked(
&mut self,
block: LocalBlock,
block: LocalBlock<ChainSpecT>,
total_difficulty: U256,
) -> &BlockT {
self.transaction_hash_to_receipt.extend(
Expand All @@ -186,7 +208,7 @@ impl<BlockT: Block + Clone + From<LocalBlock>> ContiguousBlockchainStorage<Block
block
.transactions()
.iter()
.map(|transaction| (transaction.hash(), block.clone())),
.map(|transaction| (*transaction.transaction_hash(), block.clone())),
);

self.blocks.push(block.clone());
Expand Down

0 comments on commit 198c847

Please sign in to comment.