Skip to content
Closed
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
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@ members = [
"examples/exex/op-bridge/",
"testing/ef-tests/",
"testing/testing-utils",

# bitfinity
"bin/reth/src/bitfinity_readonly.rs",
]
default-members = ["bin/reth"]

Expand Down
4 changes: 4 additions & 0 deletions bin/reth/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ repository.workspace = true
description = "Reth node implementation"
default-run = "reth"

[[bin]]
name = "reth-readonly"
path = "src/bitfinity_readonly.rs"

[lints]
workspace = true

Expand Down
179 changes: 179 additions & 0 deletions bin/reth/src/bitfinity_readonly.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
//! Bitfinity Readonly Node

use std::hash::Hash;
use std::sync::Arc;
use std::time::Duration;
use tokio::time;

use reth::blockchain_tree::BlockchainTreeEngine;
use reth_db::DatabaseEnv;
use reth_errors::ProviderError;
use reth_provider::providers::BlockchainProvider;
use reth_provider::{
BlockNumReader, BlockReader, CanonChainTracker, DatabaseProviderFactory, HeaderProvider,
HeaderSyncGapProvider,
};
use reth_stages::Pipeline;
// We use jemalloc for performance reasons.
#[cfg(all(feature = "jemalloc", unix))]
#[global_allocator]
static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;

#[cfg(all(feature = "optimism", not(test)))]
compile_error!("Cannot build the `reth` binary with the `optimism` feature flag enabled. Did you mean to build `op-reth`?");

#[cfg(not(feature = "optimism"))]
fn main() {
use lightspeed_scheduler::job::Job;
use lightspeed_scheduler::scheduler::Scheduler;
use lightspeed_scheduler::JobExecutor;
use reth::cli::Cli;

use reth_node_ethereum::EthereumNode;

reth::sigsegv_handler::install();

// Enable backtraces unless a RUST_BACKTRACE value has already been explicitly provided.
if std::env::var_os("RUST_BACKTRACE").is_none() {
std::env::set_var("RUST_BACKTRACE", "1");
}

if let Err(err) = Cli::parse_args().run(|builder, _| async {
let handle = builder.launch_readonly_node(EthereumNode::default()).await?;

// Schedule for refetching the chain info
let job_executor = JobExecutor::new_with_local_tz();

// Schedule the import job
{
let interval = Duration::from_secs(5);
job_executor
.add_job_with_scheduler(
Scheduler::Interval { interval_duration: interval, execute_at_startup: false },
Job::new("update_chain_info", "update chain info", None, move || {
let blockchain_provider = handle.node.provider.clone();
Box::pin(async move {
start_chain_info_updater(blockchain_provider)
.expect("Failed to update chain info");

Ok(())
})
}),
)
.await;
}

let _job_executor = job_executor.run().await.expect("Failed to run job executor");

handle.node_exit_future.await
}) {
eprintln!("Error: {err:?}");
std::process::exit(1);
}
}

fn start_chain_info_updater(
blockchain_provider: BlockchainProvider<Arc<DatabaseEnv>>,
) -> eyre::Result<()> {
// Get a read-only database provider
let provider = blockchain_provider.database_provider_ro()?;

// Get the current chain info from database
let chain_info = provider.chain_info()?;

// Get the current provider's chain info
let current_info = blockchain_provider.chain_info()?;

// Only update if the database has a newer block
if chain_info.best_number > current_info.best_number {
println!(
"Found new blocks: current={} new={}",
current_info.best_number, chain_info.best_number
);

// First, update the block hashes and clear any buffered blocks
if let Ok(updated_hashes) = blockchain_provider.update_block_hashes_and_clear_buffered() {
println!("Updated block hashes in the tree");

// Now walk through all new blocks and update the provider's state
for block_number in (current_info.best_number + 1)..=chain_info.best_number {
if let Ok(Some(header)) = provider.header_by_number(block_number) {
let block_hash = header.hash_slow();

// Try to get all the block data
match (provider.block(block_hash), provider.receipt(block_number)) {
(Ok(Some(block)), Ok(Some(receipts))) => {
println!(
"Processing block {}: hash={:?} txns={}",
block_number,
block_hash,
block.body.len()
);

// Get the sealed header for chain info updates
if let Ok(Some(sealed_header)) = provider.sealed_header(block_number) {
// Update the chain info tracker
blockchain_provider.set_canonical_head(sealed_header.clone());
blockchain_provider.set_finalized(sealed_header.clone());
blockchain_provider.set_safe(sealed_header);

// Get a read-write provider to update the database view
if let Ok(mut provider_rw) =
blockchain_provider.database_provider_rw()
{
// Update block tables
if let Err(e) = provider_rw.insert_block(block.clone(), None) {
println!(
"Failed to insert block {}: {:?}",
block_number, e
);
continue;
}

// Update receipts
if let Err(e) =
provider_rw.insert_receipts(block_number, receipts)
{
println!(
"Failed to insert receipts for block {}: {:?}",
block_number, e
);
continue;
}

// Commit changes
if let Err(e) = provider_rw.commit() {
println!(
"Failed to commit changes for block {}: {:?}",
block_number, e
);
continue;
}

println!(
"Successfully updated state for block {}",
block_number
);
}
}
}
_ => {
println!("Incomplete data for block {}, skipping", block_number);
continue;
}
}
}
}

// Verify the final state
if let Ok(final_info) = blockchain_provider.chain_info() {
println!(
"Final provider state: number={} hash={:?}",
final_info.best_number, final_info.best_hash
);
}
}
}

Ok(())
}
12 changes: 7 additions & 5 deletions bin/reth/src/commands/node/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
//! Main node command for launching a node

use crate::args::{
utils::parse_socket_address,
DatabaseArgs, DatadirArgs, DebugArgs, DevArgs, NetworkArgs, PayloadBuilderArgs, PruningArgs,
RpcServerArgs, TxPoolArgs,
utils::parse_socket_address, DatabaseArgs, DatadirArgs, DebugArgs, DevArgs, NetworkArgs,
PayloadBuilderArgs, PruningArgs, RpcServerArgs, TxPoolArgs,
};
use clap::{value_parser, Args, Parser};
use reth_cli_runner::CliContext;
Expand Down Expand Up @@ -32,7 +31,6 @@ pub struct NodeCommand<Ext: clap::Args + fmt::Debug = NoArgs> {
// required = false,
// )]
// pub chain: Arc<ChainSpec>,

/// Enable Prometheus metrics.
///
/// The metrics will be served at the given interface and port.
Expand Down Expand Up @@ -188,7 +186,11 @@ impl<Ext: clap::Args + fmt::Debug> NodeCommand<Ext> {
let db_path = data_dir.db();

tracing::info!(target: "reth::cli", path = ?db_path, "Opening database");
let database = Arc::new(init_db(db_path.clone(), self.db.database_args())?.with_metrics());
let database = if node_config.bitfinity_import_arg.readonly {
Arc::new(reth_db::open_db_read_only(&db_path.clone(), self.db.database_args())?)
} else {
Arc::new(init_db(db_path.clone(), self.db.database_args())?.with_metrics())
};

if with_unused_ports {
node_config = node_config.with_unused_ports();
Expand Down
1 change: 1 addition & 0 deletions bin/reth/tests/commands/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ pub async fn bitfinity_import_config_data(
backup_rpc_url: backup_evm_datasource_url,
max_retries: 3,
retry_delay_secs: 3,
readonly: false,
};

Ok((
Expand Down
58 changes: 58 additions & 0 deletions crates/node/builder/src/builder/bitfinity_builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use reth_db::database::Database;
use reth_db::database_metrics::{DatabaseMetadata, DatabaseMetrics};
use reth_node_api::NodeTypes;

use crate::bitfinity_launch::{DefaultReadOnlyNodeLauncher, ReadOnlyLaunchNode};
use crate::components::NodeComponentsBuilder;
use crate::{Node, NodeHandle};

use super::{
NodeAdapter, NodeBuilder, NodeBuilderWithComponents, RethFullAdapter, WithLaunchContext,
};

impl<DB> WithLaunchContext<NodeBuilder<DB>>
where
DB: Database + DatabaseMetrics + DatabaseMetadata + Clone + Unpin + 'static,
{
/// Launches a preconfigured [Node]
///
/// This bootstraps the node internals, creates all the components with the given [Node]
///
/// Returns a [`NodeHandle`] that can be used to interact with the node.
pub async fn launch_readonly_node<N>(
self,
node: N,
) -> eyre::Result<
NodeHandle<
NodeAdapter<
RethFullAdapter<DB, N>,
<N::ComponentsBuilder as NodeComponentsBuilder<RethFullAdapter<DB, N>>>::Components,
>,
>,
>
where
N: Node<RethFullAdapter<DB, N>>,
{
self.node(node).launch_readonly_node().await
}
}

impl<T, DB, CB> WithLaunchContext<NodeBuilderWithComponents<RethFullAdapter<DB, T>, CB>>
where
DB: Database + DatabaseMetrics + DatabaseMetadata + Clone + Unpin + 'static,
T: NodeTypes,
CB: NodeComponentsBuilder<RethFullAdapter<DB, T>>,
{
/// Launches the node and returns a handle to it.
pub async fn launch_readonly_node(
self,
) -> eyre::Result<NodeHandle<NodeAdapter<RethFullAdapter<DB, T>, CB::Components>>> {
let Self { builder, task_executor } = self;

let launcher = DefaultReadOnlyNodeLauncher::new(task_executor, builder.config.datadir());

builder
.launch_with_fn(|builder| async move { launcher.launch_readonly_node(builder).await })
.await
}
}
1 change: 1 addition & 0 deletions crates/node/builder/src/builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub use states::*;
use std::sync::Arc;

mod states;
pub mod bitfinity_builder;

/// The adapter type for a reth node with the builtin provider type
// Note: we need to hardcode this because custom components might depend on it in associated types.
Expand Down
Loading
Loading