diff --git a/bin/reth/tests/commands/bitfinity_node_it.rs b/bin/reth/tests/commands/bitfinity_node_it.rs index 839614b5161..02113d85832 100644 --- a/bin/reth/tests/commands/bitfinity_node_it.rs +++ b/bin/reth/tests/commands/bitfinity_node_it.rs @@ -14,6 +14,7 @@ use reth::{ args::{DatadirArgs, RpcServerArgs}, dirs::{DataDirPath, MaybePlatformPath}, }; +use reth_chainspec::bitfinity_spec::BitfinitySpec; use reth_consensus::FullConsensus; use reth_db::test_utils::TempDatabase; use reth_db::DatabaseEnv; @@ -339,7 +340,10 @@ pub async fn start_reth_node( node_config.dev.dev = false; let mut chain = node_config.chain.as_ref().clone(); - chain.bitfinity_evm_url = bitfinity_evm_url; + chain.bitfinity_spec = BitfinitySpec { + rpc_url: bitfinity_evm_url.to_owned().unwrap_or_default(), + send_transaction_url: Some(bitfinity_evm_url.unwrap_or_default()), + }; let mut node_config = node_config.with_chain(chain); let database = if let Some(import_data) = import_data { diff --git a/crates/chainspec/src/bitfinity_spec.rs b/crates/chainspec/src/bitfinity_spec.rs new file mode 100644 index 00000000000..a85828b5940 --- /dev/null +++ b/crates/chainspec/src/bitfinity_spec.rs @@ -0,0 +1,8 @@ +/// Bitfinity specific configuration +#[derive(Debug, Clone, PartialEq, Eq, Default)] +pub struct BitfinitySpec { + /// URL of the Bitfinity EVM node + pub rpc_url: String, + /// Send transaction to the Bitfinity EVM node + pub send_transaction_url: Option, +} diff --git a/crates/chainspec/src/lib.rs b/crates/chainspec/src/lib.rs index 96df5002503..6c1dc6db56d 100644 --- a/crates/chainspec/src/lib.rs +++ b/crates/chainspec/src/lib.rs @@ -13,6 +13,7 @@ extern crate alloc; /// Chain specific constants mod constants; +pub mod bitfinity_spec; pub use constants::*; mod api; diff --git a/crates/chainspec/src/spec.rs b/crates/chainspec/src/spec.rs index cac955b04a5..a8ff5a2fff8 100644 --- a/crates/chainspec/src/spec.rs +++ b/crates/chainspec/src/spec.rs @@ -1,6 +1,7 @@ pub use alloy_eips::eip1559::BaseFeeParams; use alloy_evm::eth::spec::EthExecutorSpec; +use crate::bitfinity_spec::BitfinitySpec; use crate::{ constants::{MAINNET_DEPOSIT_CONTRACT, MAINNET_PRUNE_DELETE_LIMIT}, EthChainSpec, @@ -113,7 +114,7 @@ pub static MAINNET: LazyLock> = LazyLock::new(|| { base_fee_params: BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()), prune_delete_limit: MAINNET_PRUNE_DELETE_LIMIT, blob_params: HardforkBlobParams::default(), - bitfinity_evm_url: Default::default(), + bitfinity_spec: Default::default(), }; spec.genesis.config.dao_fork_support = true; spec.into() @@ -143,7 +144,7 @@ pub static SEPOLIA: LazyLock> = LazyLock::new(|| { base_fee_params: BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()), prune_delete_limit: 10000, blob_params: HardforkBlobParams::default(), - bitfinity_evm_url: Default::default(), + bitfinity_spec: Default::default(), }; spec.genesis.config.dao_fork_support = true; spec.into() @@ -171,7 +172,7 @@ pub static HOLESKY: LazyLock> = LazyLock::new(|| { base_fee_params: BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()), prune_delete_limit: 10000, blob_params: HardforkBlobParams::default(), - bitfinity_evm_url: Default::default(), + bitfinity_spec: Default::default(), }; spec.genesis.config.dao_fork_support = true; spec.into() @@ -201,7 +202,7 @@ pub static HOODI: LazyLock> = LazyLock::new(|| { base_fee_params: BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()), prune_delete_limit: 10000, blob_params: HardforkBlobParams::default(), - bitfinity_evm_url: Default::default(), + bitfinity_spec: Default::default(), }; spec.genesis.config.dao_fork_support = true; spec.into() @@ -335,9 +336,9 @@ pub struct ChainSpec { /// The settings passed for blob configurations for specific hardforks. pub blob_params: HardforkBlobParams, - - /// The URL of the Bitfinity EVM RPC endpoint - pub bitfinity_evm_url: Option, + + /// Bitfinity Specific Configuration + pub bitfinity_spec: BitfinitySpec, } impl Default for ChainSpec { @@ -352,7 +353,7 @@ impl Default for ChainSpec { base_fee_params: BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()), prune_delete_limit: MAINNET_PRUNE_DELETE_LIMIT, blob_params: Default::default(), - bitfinity_evm_url: Default::default(), + bitfinity_spec: Default::default(), } } } @@ -423,7 +424,7 @@ impl ChainSpec { // given timestamp. for (fork, params) in bf_params.iter().rev() { if self.hardforks.is_fork_active_at_timestamp(fork.clone(), timestamp) { - return *params + return *params; } } @@ -442,7 +443,7 @@ impl ChainSpec { // given timestamp. for (fork, params) in bf_params.iter().rev() { if self.hardforks.is_fork_active_at_block(fork.clone(), block_number) { - return *params + return *params; } } @@ -516,8 +517,8 @@ impl ChainSpec { // We filter out TTD-based forks w/o a pre-known block since those do not show up in the // fork filter. Some(match condition { - ForkCondition::Block(block) | - ForkCondition::TTD { fork_block: Some(block), .. } => ForkFilterKey::Block(block), + ForkCondition::Block(block) + | ForkCondition::TTD { fork_block: Some(block), .. } => ForkFilterKey::Block(block), ForkCondition::Timestamp(time) => ForkFilterKey::Time(time), _ => return None, }) @@ -544,8 +545,8 @@ impl ChainSpec { for (_, cond) in self.hardforks.forks_iter() { // handle block based forks and the sepolia merge netsplit block edge case (TTD // ForkCondition with Some(block)) - if let ForkCondition::Block(block) | - ForkCondition::TTD { fork_block: Some(block), .. } = cond + if let ForkCondition::Block(block) + | ForkCondition::TTD { fork_block: Some(block), .. } = cond { if head.number >= block { // skip duplicated hardforks: hardforks enabled at genesis block @@ -556,7 +557,7 @@ impl ChainSpec { } else { // we can return here because this block fork is not active, so we set the // `next` value - return ForkId { hash: forkhash, next: block } + return ForkId { hash: forkhash, next: block }; } } } @@ -578,7 +579,7 @@ impl ChainSpec { // can safely return here because we have already handled all block forks and // have handled all active timestamp forks, and set the next value to the // timestamp that is known but not active yet - return ForkId { hash: forkhash, next: timestamp } + return ForkId { hash: forkhash, next: timestamp }; } } diff --git a/crates/cli/commands/src/node.rs b/crates/cli/commands/src/node.rs index 9c3f71dacc7..35ade2e89b6 100644 --- a/crates/cli/commands/src/node.rs +++ b/crates/cli/commands/src/node.rs @@ -176,8 +176,9 @@ impl< let chain = { let mut chain = reth_downloaders::bitfinity_evm_client::BitfinityEvmClient::fetch_chain_spec_with_fallback(bitfinity.rpc_url.to_owned(), bitfinity.backup_rpc_url.clone()).await?; + if let Some(send_raw_transaction_rpc_url) = &bitfinity.send_raw_transaction_rpc_url { - chain.bitfinity_evm_url = Some(send_raw_transaction_rpc_url.to_owned()); + chain.bitfinity_spec.send_transaction_url = Some(send_raw_transaction_rpc_url.to_owned()); } Arc::new(chain) }; diff --git a/crates/net/downloaders/src/bitfinity_evm_client.rs b/crates/net/downloaders/src/bitfinity_evm_client.rs index 78b3f9bbb7f..89fd93348aa 100644 --- a/crates/net/downloaders/src/bitfinity_evm_client.rs +++ b/crates/net/downloaders/src/bitfinity_evm_client.rs @@ -10,8 +10,10 @@ use ic_certificate_verification::VerifyCertificate; use ic_certification::{Certificate, HashTree, LookupResult}; use itertools::Either; use rayon::iter::{IntoParallelIterator, ParallelIterator as _}; +use reth_chainspec::bitfinity_spec::BitfinitySpec; use reth_chainspec::{ - make_genesis_header, BaseFeeParams, BaseFeeParamsKind, Chain, ChainHardforks, ChainSpec, EthereumHardfork, Hardfork + make_genesis_header, BaseFeeParams, BaseFeeParamsKind, Chain, ChainHardforks, ChainSpec, + EthereumHardfork, Hardfork, }; use alloy_rlp::Decodable; @@ -429,7 +431,10 @@ impl BitfinityEvmClient { base_fee_params: BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()), prune_delete_limit: 0, blob_params: Default::default(), - bitfinity_evm_url: Some(rpc), + bitfinity_spec: BitfinitySpec { + rpc_url: rpc.clone(), + send_transaction_url: None, + }, }; tracing::info!("downloaders::bitfinity_evm_client - Bitfinity chain_spec: {:?}", spec); diff --git a/crates/rpc/rpc-eth-api/src/helpers/bitfinity_evm_rpc.rs b/crates/rpc/rpc-eth-api/src/helpers/bitfinity_evm_rpc.rs index 6a35e63e200..468a57f40c0 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/bitfinity_evm_rpc.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/bitfinity_evm_rpc.rs @@ -29,7 +29,7 @@ pub trait BitfinityEvmRpc { async move { // TODO: Expecting that client node would be the active data sorce at this time // it could be primary or backup URL - let (rpc_url, client) = get_client(&chain_spec)?; + let (rpc_url, client) = client(&chain_spec)?; let block_number = client.get_block_number().await.map_err(|e| { internal_rpc_err(format!( @@ -46,7 +46,7 @@ pub trait BitfinityEvmRpc { fn btf_gas_price(&self) -> impl Future> + Send { let chain_spec = self.chain_spec(); async move { - let (rpc_url, client) = get_client(&chain_spec)?; + let (rpc_url, client) = client(&chain_spec)?; let gas_price = client.gas_price().await.map_err(|e| { internal_rpc_err(format!( @@ -63,7 +63,7 @@ pub trait BitfinityEvmRpc { fn btf_max_priority_fee_per_gas(&self) -> impl Future> + Send { let chain_spec = self.chain_spec(); async move { - let (rpc_url, client) = get_client(&chain_spec)?; + let (rpc_url, client) = client(&chain_spec)?; let priority_fee = client.max_priority_fee_per_gas().await.map_err(|e| { internal_rpc_err(format!( @@ -84,7 +84,7 @@ pub trait BitfinityEvmRpc { let chain_spec = self.chain_spec(); async move { - let (rpc_url, client) = get_client(&chain_spec)?; + let (rpc_url, client) = client(&chain_spec)?; let Some(tx) = client.get_transaction_by_hash(hash.into()).await.map_err(|e| { internal_rpc_err(format!( "failed to forward eth_transactionByHash request to {}: {}", @@ -106,9 +106,10 @@ pub trait BitfinityEvmRpc { .map_err(|e| internal_rpc_err(format!("failed to decode BitfinityEvmRpc::Transaction from received did::Transaction: {e}")))?; let signer = self_tx.recover_signer().map_err(|err| { - internal_rpc_err( - format!("failed to recover signer from decoded BitfinityEvmRpc::Transaction: {:?}", err) - ) + internal_rpc_err(format!( + "failed to recover signer from decoded BitfinityEvmRpc::Transaction: {:?}", + err + )) })?; let recovered_tx = Recovered::new_unchecked(self_tx, signer); @@ -135,7 +136,7 @@ pub trait BitfinityEvmRpc { fn btf_send_raw_transaction(&self, tx: Bytes) -> impl Future> + Send { let chain_spec = self.chain_spec(); async move { - let (rpc_url, client) = get_client(&chain_spec)?; + let (rpc_url, client) = send_transaction_client(&chain_spec)?; let tx_hash = client.send_raw_transaction_bytes(&tx).await.map_err(|e| { internal_rpc_err(format!( @@ -152,7 +153,7 @@ pub trait BitfinityEvmRpc { fn get_genesis_balances(&self) -> impl Future>> + Send { let chain_spec = self.chain_spec(); async move { - let (rpc_url, client) = get_client(&chain_spec)?; + let (rpc_url, client) = client(&chain_spec)?; let balances = client.get_genesis_balances().await.map_err(|e| { internal_rpc_err(format!( @@ -171,7 +172,7 @@ pub trait BitfinityEvmRpc { ) -> impl Future>>> + Send { let chain_spec = self.chain_spec(); async move { - let (rpc_url, client) = get_client(&chain_spec)?; + let (rpc_url, client) = client(&chain_spec)?; let certified_block = client.get_last_certified_block().await.map_err(|e| { internal_rpc_err(format!( @@ -186,8 +187,20 @@ pub trait BitfinityEvmRpc { } /// Returns a client for the Bitfinity EVM RPC. -fn get_client(chain_spec: &ChainSpec) -> RpcResult<(&String, EthJsonRpcClient)> { - let Some(rpc_url) = &chain_spec.bitfinity_evm_url else { +fn client(chain_spec: &ChainSpec) -> RpcResult<(&String, EthJsonRpcClient)> { + let rpc_url = &chain_spec.bitfinity_spec.rpc_url; + + let client = ethereum_json_rpc_client::EthJsonRpcClient::new( + ethereum_json_rpc_client::reqwest::ReqwestClient::new(rpc_url.to_string()), + ); + + Ok((&rpc_url, client)) +} + +fn send_transaction_client( + chain_spec: &ChainSpec, +) -> RpcResult<(&String, EthJsonRpcClient)> { + let Some(rpc_url) = &chain_spec.bitfinity_spec.send_transaction_url else { return Err(internal_rpc_err("bitfinity_evm_url not found in chain spec")); };