Skip to content

Commit

Permalink
use reth-alloy
Browse files Browse the repository at this point in the history
  • Loading branch information
yash-atreya committed Oct 3, 2024
1 parent a12c7db commit 13a2e95
Show file tree
Hide file tree
Showing 2 changed files with 5 additions and 156 deletions.
6 changes: 1 addition & 5 deletions examples/advanced/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,7 @@ revm-primitives.workspace = true
revm.workspace = true

# reth
reth-db = { git = "https://github.com/paradigmxyz/reth", package = "reth-db", rev = "b66e4f5" }
reth-provider = { git = "https://github.com/paradigmxyz/reth", package = "reth-provider", rev = "b66e4f5" }
reth-node-types = { git = "https://github.com/paradigmxyz/reth", package = "reth-node-types", rev = "b66e4f5" }
reth-chainspec = { git = "https://github.com/paradigmxyz/reth", package = "reth-chainspec", rev = "b66e4f5" }
reth-node-ethereum = { git = "https://github.com/paradigmxyz/reth", package = "reth-node-ethereum", rev = "b66e4f5" }
reth-alloy = { git = "https://github.com/paradigmxyz/reth", package = "reth-alloy", rev = "327d072" }

eyre.workspace = true
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
Expand Down
155 changes: 4 additions & 151 deletions examples/advanced/examples/reth_db_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,14 @@
//! their own implementation of the `Provider` trait and fetch results from any source.
//!
//! Learn more about `ProviderCall` [here](https://github.com/alloy-rs/alloy/pull/788).
use std::{marker::PhantomData, path::PathBuf, sync::Arc};

use alloy::{
eips::{BlockId, BlockNumberOrTag},
eips::BlockId,
node_bindings::{utils::run_with_tempdir, Reth},
primitives::{address, Address, U64},
providers::{
Provider, ProviderBuilder, ProviderCall, ProviderLayer, RootProvider, RpcWithBlock,
},
rpc::client::NoParams,
transports::{Transport, TransportErrorKind},
primitives::address,
providers::{Provider, ProviderBuilder},
};
use eyre::Result;

use reth_chainspec::ChainSpecBuilder;
use reth_db::{open_db_read_only, DatabaseEnv};
use reth_node_ethereum::EthereumNode;
use reth_node_types::NodeTypesWithDBAdapter;
use reth_provider::{
providers::StaticFileProvider, BlockNumReader, DatabaseProviderFactory, ProviderError,
ProviderFactory, StateProvider, TryIntoHistoricalStateProvider,
};
mod reth_db_layer;
use reth_db_layer::RethDbLayer;
use reth_alloy::RethDbLayer;

#[tokio::main]
async fn main() -> Result<()> {
Expand Down Expand Up @@ -93,134 +77,3 @@ async fn main() -> Result<()> {

Ok(())
}

/// Implement the `ProviderLayer` trait for the `RethDBLayer` struct.
impl<P, T> ProviderLayer<P, T> for RethDbLayer
where
P: Provider<T>,
T: Transport + Clone,
{
type Provider = RethDbProvider<P, T>;

fn layer(&self, inner: P) -> Self::Provider {
RethDbProvider::new(inner, self.db_path().clone())
}
}

/// A provider that overrides the vanilla `Provider` trait to get results from the reth-db.
///
/// It holds the `reth_provider::ProviderFactory` that enables read-only access to the database
/// tables and static files.
#[derive(Clone, Debug)]
pub struct RethDbProvider<P, T> {
inner: P,
db_path: PathBuf,
provider_factory: DbAccessor,
_pd: PhantomData<T>,
}

impl<P, T> RethDbProvider<P, T> {
/// Create a new `RethDbProvider` instance.
pub fn new(inner: P, db_path: PathBuf) -> Self {
let db = open_db_read_only(&db_path, Default::default()).unwrap();
let chain_spec = ChainSpecBuilder::mainnet().build();
let static_file_provider =
StaticFileProvider::read_only(db_path.join("static_files"), false).unwrap();

let provider_factory =
ProviderFactory::new(db.into(), chain_spec.into(), static_file_provider);

let db_accessor: DbAccessor<
ProviderFactory<NodeTypesWithDBAdapter<EthereumNode, Arc<DatabaseEnv>>>,
> = DbAccessor::new(provider_factory);
Self { inner, db_path, provider_factory: db_accessor, _pd: PhantomData }
}

const fn factory(&self) -> &DbAccessor {
&self.provider_factory
}

/// Get the DB Path
pub fn db_path(&self) -> PathBuf {
self.db_path.clone()
}
}

/// Implement the `Provider` trait for the `RethDbProvider` struct.
///
/// This is where we override specific RPC methods to fetch from the reth-db.
impl<P, T> Provider<T> for RethDbProvider<P, T>
where
P: Provider<T>,
T: Transport + Clone,
{
fn root(&self) -> &RootProvider<T> {
self.inner.root()
}

/// Override the `get_block_number` method to fetch the latest block number from the reth-db.
fn get_block_number(&self) -> ProviderCall<T, NoParams, U64, u64> {
let provider = self.factory().provider().map_err(TransportErrorKind::custom).unwrap();

let best = provider.best_block_number().map_err(TransportErrorKind::custom);

ProviderCall::ready(best)
}

/// Override the `get_transaction_count` method to fetch the transaction count of an address.
///
/// `RpcWithBlock` uses `ProviderCall` under the hood.
fn get_transaction_count(&self, address: Address) -> RpcWithBlock<T, Address, U64, u64> {
let this = self.factory().clone();
RpcWithBlock::new_provider(move |block_id| {
let provider = this.provider_at(block_id).map_err(TransportErrorKind::custom).unwrap();

let maybe_acc =
provider.basic_account(address).map_err(TransportErrorKind::custom).unwrap();

let nonce = maybe_acc.map(|acc| acc.nonce).unwrap_or_default();

ProviderCall::ready(Ok(nonce))
})
}
}

/// A helper type to get the appropriate DB provider.
#[derive(Debug, Clone)]
struct DbAccessor<DB = ProviderFactory<NodeTypesWithDBAdapter<EthereumNode, Arc<DatabaseEnv>>>>
where
DB: DatabaseProviderFactory<Provider: TryIntoHistoricalStateProvider + BlockNumReader>,
{
inner: DB,
}

impl<DB> DbAccessor<DB>
where
DB: DatabaseProviderFactory<Provider: TryIntoHistoricalStateProvider + BlockNumReader>,
{
const fn new(inner: DB) -> Self {
Self { inner }
}

fn provider(&self) -> Result<DB::Provider, ProviderError> {
self.inner.database_provider_ro()
}

fn provider_at(&self, block_id: BlockId) -> Result<Box<dyn StateProvider>, ProviderError> {
let provider = self.inner.database_provider_ro()?;

let block_number = match block_id {
BlockId::Hash(hash) => {
if let Some(num) = provider.block_number(hash.into())? {
num
} else {
return Err(ProviderError::BlockHashNotFound(hash.into()));
}
}
BlockId::Number(BlockNumberOrTag::Number(num)) => num,
_ => provider.best_block_number()?,
};

provider.try_into_history_at_block(block_number)
}
}

0 comments on commit 13a2e95

Please sign in to comment.