Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(eth-client): Generalize RPC client #1898

Merged
merged 17 commits into from
May 14, 2024
Merged
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 7 additions & 5 deletions core/bin/block_reverter/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use clap::{Parser, Subcommand};
use tokio::io::{self, AsyncReadExt};
use zksync_block_reverter::{
eth_client::{
clients::{PKSigningClient, QueryClient},
clients::{Client, PKSigningClient},
EthInterface,
},
BlockReverter, BlockReverterEthConfig, NodeRole,
Expand Down Expand Up @@ -129,8 +129,9 @@ async fn main() -> anyhow::Result<()> {
json,
operator_address,
} => {
let eth_client =
QueryClient::new(eth_sender.web3_url.clone()).context("Ethereum client")?;
let eth_client = Client::http(eth_sender.web3_url.clone())
.context("Ethereum client")?
.build();

let suggested_values = block_reverter
.suggested_values(&eth_client, &config, operator_address)
Expand All @@ -146,8 +147,9 @@ async fn main() -> anyhow::Result<()> {
priority_fee_per_gas,
nonce,
} => {
let eth_client =
QueryClient::new(eth_sender.web3_url.clone()).context("Ethereum client")?;
let eth_client = Client::http(eth_sender.web3_url.clone())
.context("Ethereum client")?
.build();
#[allow(deprecated)]
let reverter_private_key = eth_sender
.sender
Expand Down
2 changes: 1 addition & 1 deletion core/bin/external_node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ zksync_snapshots_applier.workspace = true
zksync_object_store.workspace = true
prometheus_exporter.workspace = true
zksync_health_check.workspace = true
zksync_web3_decl.workspace = true
zksync_web3_decl = { workspace = true, features = ["client"] }
zksync_types.workspace = true
zksync_block_reverter.workspace = true
zksync_shared_metrics.workspace = true
Expand Down
6 changes: 3 additions & 3 deletions core/bin/external_node/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use zksync_protobuf_config::proto;
use zksync_snapshots_applier::SnapshotsApplierConfig;
use zksync_types::{api::BridgeAddresses, url::SensitiveUrl, ETHEREUM_ADDRESS};
use zksync_web3_decl::{
client::BoxedL2Client,
client::{DynClient, L2},
error::ClientRpcContext,
jsonrpsee::{core::ClientError, types::error::ErrorCode},
namespaces::{EnNamespaceClient, ZksNamespaceClient},
Expand Down Expand Up @@ -90,7 +90,7 @@ pub(crate) struct RemoteENConfig {
}

impl RemoteENConfig {
pub async fn fetch(client: &BoxedL2Client) -> anyhow::Result<Self> {
pub async fn fetch(client: &DynClient<L2>) -> anyhow::Result<Self> {
let bridges = client
.get_bridge_contracts()
.rpc_context("get_bridge_contracts")
Expand Down Expand Up @@ -826,7 +826,7 @@ impl ExternalNodeConfig {
required: RequiredENConfig,
optional: OptionalENConfig,
observability: ObservabilityENConfig,
main_node_client: &BoxedL2Client,
main_node_client: &DynClient<L2>,
) -> anyhow::Result<Self> {
let experimental = envy::prefixed("EN_EXPERIMENTAL_")
.from_env::<ExperimentalENConfig>()
Expand Down
53 changes: 25 additions & 28 deletions core/bin/external_node/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ use zksync_basic_types::{L1ChainId, L2ChainId};
use zksync_eth_client::EthInterface;
use zksync_health_check::{async_trait, CheckHealth, Health, HealthStatus};
use zksync_web3_decl::{
client::BoxedL2Client,
client::{DynClient, L2},
error::ClientRpcContext,
namespaces::{EthNamespaceClient, ZksNamespaceClient},
};

/// Main node health check.
#[derive(Debug)]
pub(crate) struct MainNodeHealthCheck(BoxedL2Client);
pub(crate) struct MainNodeHealthCheck(Box<DynClient<L2>>);

impl From<BoxedL2Client> for MainNodeHealthCheck {
fn from(client: BoxedL2Client) -> Self {
impl From<Box<DynClient<L2>>> for MainNodeHealthCheck {
fn from(client: Box<DynClient<L2>>) -> Self {
Self(client.for_component("main_node_health_check"))
}
}
Expand Down Expand Up @@ -76,7 +76,7 @@ pub(crate) struct ValidateChainIdsTask {
l1_chain_id: L1ChainId,
l2_chain_id: L2ChainId,
eth_client: Box<dyn EthInterface>,
main_node_client: BoxedL2Client,
main_node_client: Box<DynClient<L2>>,
}

impl ValidateChainIdsTask {
Expand All @@ -86,7 +86,7 @@ impl ValidateChainIdsTask {
l1_chain_id: L1ChainId,
l2_chain_id: L2ChainId,
eth_client: Box<dyn EthInterface>,
main_node_client: BoxedL2Client,
main_node_client: Box<DynClient<L2>>,
) -> Self {
Self {
l1_chain_id,
Expand Down Expand Up @@ -123,7 +123,7 @@ impl ValidateChainIdsTask {
}

async fn check_l1_chain_using_main_node(
main_node_client: BoxedL2Client,
main_node_client: Box<DynClient<L2>>,
expected: L1ChainId,
) -> anyhow::Result<()> {
loop {
Expand Down Expand Up @@ -161,7 +161,7 @@ impl ValidateChainIdsTask {
}

async fn check_l2_chain_using_main_node(
main_node_client: BoxedL2Client,
main_node_client: Box<DynClient<L2>>,
expected: L2ChainId,
) -> anyhow::Result<()> {
loop {
Expand Down Expand Up @@ -220,23 +220,22 @@ impl ValidateChainIdsTask {
mod tests {
use zksync_eth_client::clients::MockEthereum;
use zksync_types::U64;
use zksync_web3_decl::client::MockL2Client;
use zksync_web3_decl::client::MockClient;

use super::*;

#[tokio::test]
async fn validating_chain_ids_errors() {
let main_node_client = MockL2Client::new(|method, _| match method {
"eth_chainId" => Ok(serde_json::json!(U64::from(270))),
"zks_L1ChainId" => Ok(serde_json::json!(U64::from(3))),
_ => panic!("unexpected L2 call: {method}"),
});
let main_node_client = MockClient::builder(L2::default())
.method("eth_chainId", || Ok(U64::from(270)))
.method("zks_L1ChainId", || Ok(U64::from(3)))
.build();

let validation_task = ValidateChainIdsTask::new(
L1ChainId(3), // << mismatch with the Ethereum client
L2ChainId::default(),
Box::<MockEthereum>::default(),
BoxedL2Client::new(main_node_client.clone()),
Box::new(main_node_client.clone()),
);
let (_stop_sender, stop_receiver) = watch::channel(false);
let err = validation_task
Expand All @@ -253,7 +252,7 @@ mod tests {
L1ChainId(9), // << mismatch with the main node client
L2ChainId::from(270),
Box::<MockEthereum>::default(),
BoxedL2Client::new(main_node_client.clone()),
Box::new(main_node_client),
);
let err = validation_task
.run(stop_receiver.clone())
Expand All @@ -265,17 +264,16 @@ mod tests {
"{err}"
);

let main_node_client = MockL2Client::new(|method, _| match method {
"eth_chainId" => Ok(serde_json::json!(U64::from(270))),
"zks_L1ChainId" => Ok(serde_json::json!(U64::from(9))),
_ => panic!("unexpected L2 call: {method}"),
});
let main_node_client = MockClient::builder(L2::default())
.method("eth_chainId", || Ok(U64::from(270)))
.method("zks_L1ChainId", || Ok(U64::from(9)))
.build();

let validation_task = ValidateChainIdsTask::new(
L1ChainId(9),
L2ChainId::from(271), // << mismatch with the main node client
Box::<MockEthereum>::default(),
BoxedL2Client::new(main_node_client.clone()),
Box::new(main_node_client),
);
let err = validation_task
.run(stop_receiver)
Expand All @@ -290,17 +288,16 @@ mod tests {

#[tokio::test]
async fn validating_chain_ids_success() {
let main_node_client = MockL2Client::new(|method, _| match method {
"eth_chainId" => Ok(serde_json::json!(U64::from(270))),
"zks_L1ChainId" => Ok(serde_json::json!(U64::from(9))),
_ => panic!("unexpected L2 call: {method}"),
});
let main_node_client = MockClient::builder(L2::default())
.method("eth_chainId", || Ok(U64::from(270)))
.method("zks_L1ChainId", || Ok(U64::from(9)))
.build();

let validation_task = ValidateChainIdsTask::new(
L1ChainId(9),
L2ChainId::default(),
Box::<MockEthereum>::default(),
BoxedL2Client::new(main_node_client.clone()),
Box::new(main_node_client),
);
let (stop_sender, stop_receiver) = watch::channel(false);
let task = tokio::spawn(validation_task.run(stop_receiver));
Expand Down
4 changes: 2 additions & 2 deletions core/bin/external_node/src/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use zksync_health_check::AppHealthCheck;
use zksync_object_store::ObjectStoreFactory;
use zksync_shared_metrics::{SnapshotRecoveryStage, APP_METRICS};
use zksync_snapshots_applier::{SnapshotsApplierConfig, SnapshotsApplierTask};
use zksync_web3_decl::client::BoxedL2Client;
use zksync_web3_decl::client::{DynClient, L2};

use crate::config::SnapshotsRecoveryConfig;

Expand All @@ -24,7 +24,7 @@ enum InitDecision {

pub(crate) async fn ensure_storage_initialized(
pool: ConnectionPool<Core>,
main_node_client: BoxedL2Client,
main_node_client: Box<DynClient<L2>>,
app_health: &AppHealthCheck,
l2_chain_id: L2ChainId,
consider_snapshot_recovery: bool,
Expand Down
27 changes: 16 additions & 11 deletions core/bin/external_node/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ use zksync_dal::{metrics::PostgresMetrics, ConnectionPool, Core, CoreDal};
use zksync_db_connection::{
connection_pool::ConnectionPoolBuilder, healthcheck::ConnectionPoolHealthCheck,
};
use zksync_eth_client::{clients::QueryClient, EthInterface};
use zksync_eth_client::EthInterface;
use zksync_eth_sender::l1_batch_commit_data_generator::{
L1BatchCommitDataGenerator, RollupModeL1BatchCommitDataGenerator,
ValidiumModeL1BatchCommitDataGenerator,
Expand All @@ -58,7 +58,7 @@ use zksync_storage::RocksDB;
use zksync_types::L2ChainId;
use zksync_utils::wait_for_tasks::ManagedTasks;
use zksync_web3_decl::{
client::{BoxedL2Client, L2Client},
client::{Client, DynClient, L2},
jsonrpsee,
namespaces::EnNamespaceClient,
};
Expand Down Expand Up @@ -89,7 +89,7 @@ async fn build_state_keeper(
state_keeper_db_path: String,
config: &ExternalNodeConfig,
connection_pool: ConnectionPool<Core>,
main_node_client: BoxedL2Client,
main_node_client: Box<DynClient<L2>>,
output_handler: OutputHandler,
stop_receiver: watch::Receiver<bool>,
chain_id: L2ChainId,
Expand Down Expand Up @@ -215,7 +215,7 @@ async fn run_tree(
async fn run_core(
config: &ExternalNodeConfig,
connection_pool: ConnectionPool<Core>,
main_node_client: BoxedL2Client,
main_node_client: Box<DynClient<L2>>,
eth_client: Box<dyn EthInterface>,
task_handles: &mut Vec<task::JoinHandle<anyhow::Result<()>>>,
app_health: &AppHealthCheck,
Expand Down Expand Up @@ -425,7 +425,7 @@ async fn run_api(
stop_receiver: watch::Receiver<bool>,
sync_state: SyncState,
tree_reader: Option<Arc<dyn TreeApiClient>>,
main_node_client: BoxedL2Client,
main_node_client: Box<DynClient<L2>>,
singleton_pool_builder: &ConnectionPoolBuilder<Core>,
fee_params_fetcher: Arc<MainNodeFeeParamsFetcher>,
components: &HashSet<Component>,
Expand Down Expand Up @@ -599,7 +599,7 @@ async fn init_tasks(
config: &ExternalNodeConfig,
connection_pool: ConnectionPool<Core>,
singleton_pool_builder: ConnectionPoolBuilder<Core>,
main_node_client: BoxedL2Client,
main_node_client: Box<DynClient<L2>>,
eth_client: Box<dyn EthInterface>,
task_handles: &mut Vec<JoinHandle<anyhow::Result<()>>>,
app_health: &AppHealthCheck,
Expand Down Expand Up @@ -806,20 +806,25 @@ async fn main() -> anyhow::Result<()> {
// Build L1 and L2 clients.
let main_node_url = &required_config.main_node_url;
tracing::info!("Main node URL is: {main_node_url:?}");
let main_node_client = L2Client::http(main_node_url.clone())
let main_node_client = Client::http(main_node_url.clone())
.context("Failed creating JSON-RPC client for main node")?
.for_network(required_config.l2_chain_id.into())
.with_allowed_requests_per_second(optional_config.main_node_rate_limit_rps)
.build();
let main_node_client = BoxedL2Client::new(main_node_client);
let main_node_client = Box::new(main_node_client) as Box<DynClient<L2>>;

let eth_client_url = &required_config.eth_client_url;
let eth_client = Box::new(QueryClient::new(eth_client_url.clone())?);
let eth_client = Client::http(eth_client_url.clone())
.context("failed creating JSON-RPC client for Ethereum")?
.for_network(required_config.l1_chain_id.into())
.build();
let eth_client = Box::new(eth_client);

let mut config = ExternalNodeConfig::new(
required_config,
optional_config,
observability_config,
&main_node_client,
main_node_client.as_ref(),
)
.await
.context("Failed to load external node config")?;
Expand Down Expand Up @@ -882,7 +887,7 @@ async fn run_node(
config: &ExternalNodeConfig,
connection_pool: ConnectionPool<Core>,
singleton_pool_builder: ConnectionPoolBuilder<Core>,
main_node_client: BoxedL2Client,
main_node_client: Box<DynClient<L2>>,
eth_client: Box<dyn EthInterface>,
) -> anyhow::Result<()> {
tracing::warn!("The external node is in the alpha phase, and should be used with caution.");
Expand Down
Loading
Loading