diff --git a/Cargo.lock b/Cargo.lock index 9d3b53697..38285a9de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1742,7 +1742,6 @@ dependencies = [ "rs_merkle", "rustc_version_runtime", "secp256k1", - "sequencer-client", "serde", "serde_json", "sha2", @@ -1784,11 +1783,12 @@ dependencies = [ "prover-services", "rand 0.8.5", "rayon", + "reth-primitives", "rs_merkle", - "sequencer-client", "serde", "sha2", "sov-db", + "sov-ledger-rpc", "sov-mock-da", "sov-mock-zkvm", "sov-modules-api", @@ -1918,12 +1918,13 @@ dependencies = [ "hex", "jsonrpsee", "rand 0.8.5", + "reth-primitives", "rs_merkle", - "sequencer-client", "serde", "serde_json", "sha2", "sov-db", + "sov-ledger-rpc", "sov-mock-da", "sov-modules-api", "sov-modules-stf-blueprint", @@ -1950,8 +1951,9 @@ dependencies = [ "citrea-primitives", "hex", "jsonrpsee", - "sequencer-client", + "reth-primitives", "sov-db", + "sov-ledger-rpc", "sov-mock-da", "sov-mock-zkvm", "sov-modules-api", @@ -2824,6 +2826,7 @@ dependencies = [ "borsh", "citrea-evm", "citrea-primitives", + "citrea-sequencer", "futures", "jsonrpsee", "parking_lot", @@ -2833,10 +2836,10 @@ dependencies = [ "reth-rpc-types-compat", "rustc_version_runtime", "schnellru", - "sequencer-client", "serde", "serde_json", "sov-db", + "sov-ledger-rpc", "sov-modules-api", "sov-rollup-interface", "tokio", @@ -7066,24 +7069,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" -[[package]] -name = "sequencer-client" -version = "0.5.0-rc.1" -dependencies = [ - "anyhow", - "borsh", - "citrea-primitives", - "hex", - "jsonrpsee", - "reth-primitives", - "reth-rpc-types", - "serde", - "serde_json", - "sov-rollup-interface", - "tokio", - "tracing", -] - [[package]] name = "serde" version = "1.0.215" diff --git a/Cargo.toml b/Cargo.toml index 738ed3fdf..7c2470576 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,6 @@ members = [ "crates/pruning", "crates/risc0", "crates/sequencer", - "crates/sequencer-client", "crates/soft-confirmation-rule-enforcer", # "crates/sp1", # Sovereign sdk diff --git a/bin/citrea/Cargo.toml b/bin/citrea/Cargo.toml index 1f0f926cc..de0c37333 100644 --- a/bin/citrea/Cargo.toml +++ b/bin/citrea/Cargo.toml @@ -26,7 +26,6 @@ citrea-sequencer = { path = "../../crates/sequencer" } citrea-stf = { path = "../../crates/citrea-stf", features = ["native"] } ethereum-rpc = { path = "../../crates/ethereum-rpc" } prover-services = { path = "../../crates/prover-services" } -sequencer-client = { path = "../../crates/sequencer-client" } # Sovereign-SDK deps soft-confirmation-rule-enforcer = { path = "../../crates/soft-confirmation-rule-enforcer" } diff --git a/crates/batch-prover/Cargo.toml b/crates/batch-prover/Cargo.toml index 83cdd5b68..1d7d9d1e9 100644 --- a/crates/batch-prover/Cargo.toml +++ b/crates/batch-prover/Cargo.toml @@ -12,10 +12,10 @@ repository.workspace = true # Citrea Deps citrea-common = { path = "../common" } citrea-primitives = { path = "../primitives", features = ["native"] } -sequencer-client = { path = "../sequencer-client" } # Sov SDK deps sov-db = { path = "../sovereign-sdk/full-node/db/sov-db" } +sov-ledger-rpc = { path = "../sovereign-sdk/full-node/sov-ledger-rpc", features = ["client"] } sov-modules-api = { path = "../sovereign-sdk/module-system/sov-modules-api", default-features = false } sov-modules-core = { path = "../sovereign-sdk/module-system/sov-modules-core" } sov-modules-stf-blueprint = { path = "../sovereign-sdk/module-system/sov-modules-stf-blueprint", features = ["native"] } @@ -35,6 +35,7 @@ num_cpus = { workspace = true } parking_lot = { workspace = true } rand = { workspace = true } rayon = { workspace = true } +reth-primitives = { workspace = true } rs_merkle = { workspace = true } serde = { workspace = true } tokio = { workspace = true } diff --git a/crates/batch-prover/src/runner.rs b/crates/batch-prover/src/runner.rs index a001626a8..00c9184db 100644 --- a/crates/batch-prover/src/runner.rs +++ b/crates/batch-prover/src/runner.rs @@ -14,16 +14,19 @@ use citrea_common::utils::{create_shutdown_signal, soft_confirmation_to_receipt} use citrea_common::{BatchProverConfig, RollupPublicKeys, RpcConfig, RunnerConfig}; use citrea_primitives::types::SoftConfirmationHash; use jsonrpsee::core::client::Error as JsonrpseeError; +use jsonrpsee::http_client::{HttpClient, HttpClientBuilder}; use jsonrpsee::server::{BatchRequestConfig, ServerBuilder}; use jsonrpsee::RpcModule; -use sequencer_client::{GetSoftConfirmationResponse, SequencerClient}; +use reth_primitives::U64; use sov_db::ledger_db::BatchProverLedgerOps; use sov_db::schema::types::{BatchNumber, SlotNumber}; +use sov_ledger_rpc::LedgerRpcClient; use sov_modules_api::{Context, SignedSoftConfirmation, SlotData, Spec}; use sov_modules_stf_blueprint::{Runtime, StfBlueprint}; use sov_prover_storage_manager::{ProverStorage, ProverStorageManager, SnapshotManager}; -use sov_rollup_interface::da::{BlockHeaderTrait, DaSpec}; +use sov_rollup_interface::da::BlockHeaderTrait; use sov_rollup_interface::fork::ForkManager; +use sov_rollup_interface::rpc::SoftConfirmationResponse; use sov_rollup_interface::services::da::DaService; use sov_rollup_interface::spec::SpecId; use sov_rollup_interface::stf::StateTransitionFunction; @@ -60,7 +63,7 @@ where batch_hash: SoftConfirmationHash, rpc_config: RpcConfig, prover_service: Arc, - sequencer_client: SequencerClient, + sequencer_client: HttpClient, sequencer_pub_key: Vec, sequencer_da_pub_key: Vec, phantom: std::marker::PhantomData, @@ -143,7 +146,8 @@ where batch_hash: prev_batch_hash, rpc_config, prover_service, - sequencer_client: SequencerClient::new(runner_config.sequencer_client_url), + sequencer_client: HttpClientBuilder::default() + .build(runner_config.sequencer_client_url)?, sequencer_pub_key: public_keys.sequencer_public_key, sequencer_da_pub_key: public_keys.sequencer_da_pub_key, phantom: std::marker::PhantomData, @@ -279,7 +283,7 @@ where let start_l1_height = match last_scanned_l1_height { Some(height) => height.0, - None => get_initial_slot_height::(&self.sequencer_client).await, + None => get_initial_slot_height(&self.sequencer_client).await, }; let ledger_db = self.ledger_db.clone(); @@ -325,13 +329,12 @@ where let sequencer_client = self.sequencer_client.clone(); let sync_blocks_count = self.sync_blocks_count; - let l2_sync_worker = - sync_l2::(start_l2_height, sequencer_client, l2_tx, sync_blocks_count); + let l2_sync_worker = sync_l2(start_l2_height, sequencer_client, l2_tx, sync_blocks_count); tokio::pin!(l2_sync_worker); // Store L2 blocks and make sure they are processed in order. // Otherwise, processing N+1 L2 block before N would emit prev_hash mismatch. - let mut pending_l2_blocks: VecDeque<(u64, GetSoftConfirmationResponse)> = VecDeque::new(); + let mut pending_l2_blocks = VecDeque::new(); let mut interval = tokio::time::interval(Duration::from_secs(1)); interval.tick().await; @@ -349,7 +352,7 @@ where if let Err(e) = self.process_l2_block(*l2_height, l2_block).await { error!("Could not process L2 block: {}", e); // This block failed to process, add remaining L2 blocks to queue including this one. - let remaining_l2s: Vec<(u64, GetSoftConfirmationResponse)> = l2_blocks[index..].to_vec(); + let remaining_l2s = l2_blocks[index..].to_vec(); pending_l2_blocks.extend(remaining_l2s); } } @@ -389,7 +392,7 @@ where async fn process_l2_block( &mut self, l2_height: u64, - soft_confirmation: &GetSoftConfirmationResponse, + soft_confirmation: &SoftConfirmationResponse, ) -> anyhow::Result<()> { let current_l1_block = get_da_block_at_height( &self.da_service, @@ -492,14 +495,12 @@ where } } -async fn sync_l2( +async fn sync_l2( start_l2_height: u64, - sequencer_client: SequencerClient, - sender: mpsc::Sender>, + sequencer_client: HttpClient, + sender: mpsc::Sender>, sync_blocks_count: u64, -) where - Da: DaService, -{ +) { let mut l2_height = start_l2_height; info!("Starting to sync from L2 height {}", l2_height); loop { @@ -510,44 +511,44 @@ async fn sync_l2( .build(); let inner_client = &sequencer_client; - let soft_confirmations: Vec = - match retry_backoff(exponential_backoff.clone(), || async move { - let soft_confirmations = inner_client - .get_soft_confirmation_range::( - l2_height..=l2_height + sync_blocks_count - 1, - ) - .await; - - match soft_confirmations { - Ok(soft_confirmations) => { - Ok(soft_confirmations.into_iter().flatten().collect::>()) - } - Err(e) => match e.downcast_ref::() { - Some(JsonrpseeError::Transport(e)) => { - let error_msg = format!( - "Soft Confirmation: connection error during RPC call: {:?}", - e - ); - debug!(error_msg); - Err(backoff::Error::Transient { - err: error_msg, - retry_after: None, - }) - } - _ => Err(backoff::Error::Transient { - err: format!("Soft Confirmation: unknown error from RPC call: {:?}", e), - retry_after: None, - }), - }, - } - }) - .await - { - Ok(soft_confirmations) => soft_confirmations, - Err(_) => { - continue; + let soft_confirmations = match retry_backoff(exponential_backoff.clone(), || async move { + let soft_confirmations = inner_client + .get_soft_confirmation_range( + U64::from(l2_height), + U64::from(l2_height + sync_blocks_count - 1), + ) + .await; + + match soft_confirmations { + Ok(soft_confirmations) => { + Ok(soft_confirmations.into_iter().flatten().collect::>()) } - }; + Err(e) => match e { + JsonrpseeError::Transport(e) => { + let error_msg = format!( + "Soft Confirmation: connection error during RPC call: {:?}", + e + ); + debug!(error_msg); + Err(backoff::Error::Transient { + err: error_msg, + retry_after: None, + }) + } + _ => Err(backoff::Error::Transient { + err: format!("Soft Confirmation: unknown error from RPC call: {:?}", e), + retry_after: None, + }), + }, + } + }) + .await + { + Ok(soft_confirmations) => soft_confirmations, + Err(_) => { + continue; + } + }; if soft_confirmations.is_empty() { debug!( @@ -559,7 +560,7 @@ async fn sync_l2( continue; } - let soft_confirmations: Vec<(u64, GetSoftConfirmationResponse)> = (l2_height + let soft_confirmations: Vec<(u64, SoftConfirmationResponse)> = (l2_height ..l2_height + soft_confirmations.len() as u64) .zip(soft_confirmations) .collect(); @@ -572,9 +573,9 @@ async fn sync_l2( } } -async fn get_initial_slot_height(client: &SequencerClient) -> u64 { +async fn get_initial_slot_height(client: &HttpClient) -> u64 { loop { - match client.get_soft_confirmation::(1).await { + match client.get_soft_confirmation_by_number(U64::from(1)).await { Ok(Some(batch)) => return batch.da_slot_height, _ => { // sleep 1 diff --git a/crates/ethereum-rpc/Cargo.toml b/crates/ethereum-rpc/Cargo.toml index 9704c7a8e..2055fcbb0 100644 --- a/crates/ethereum-rpc/Cargo.toml +++ b/crates/ethereum-rpc/Cargo.toml @@ -17,12 +17,12 @@ anyhow = { workspace = true } borsh = { workspace = true } citrea-evm = { path = "../evm", features = ["native"] } citrea-primitives = { path = "../primitives" } +citrea-sequencer = { path = "../sequencer" } futures = { workspace = true } jsonrpsee = { workspace = true, features = ["http-client", "server"] } parking_lot = { workspace = true } rustc_version_runtime = { workspace = true } schnellru = "0.2.1" -sequencer-client = { path = "../sequencer-client" } serde = { workspace = true } serde_json = { workspace = true } tokio = { workspace = true } @@ -36,6 +36,7 @@ reth-rpc-types-compat = { workspace = true } # Sovereign-SDK deps sov-db = { path = "../../crates/sovereign-sdk/full-node/db/sov-db" } +sov-ledger-rpc = { path = "../sovereign-sdk/full-node/sov-ledger-rpc", features = ["client"] } sov-modules-api = { path = "../sovereign-sdk/module-system/sov-modules-api", default-features = false } sov-rollup-interface = { path = "../sovereign-sdk/rollup-interface", features = ["native"] } diff --git a/crates/ethereum-rpc/src/ethereum.rs b/crates/ethereum-rpc/src/ethereum.rs index 387e895d9..9e2c9b31d 100644 --- a/crates/ethereum-rpc/src/ethereum.rs +++ b/crates/ethereum-rpc/src/ethereum.rs @@ -3,11 +3,11 @@ use std::sync::{Arc, Mutex}; #[cfg(feature = "local")] use citrea_evm::DevSigner; use citrea_evm::Evm; +use jsonrpsee::http_client::HttpClient; use reth_primitives::U256; use reth_rpc_types::trace::geth::GethTrace; use rustc_version_runtime::version; use schnellru::{ByLength, LruMap}; -use sequencer_client::SequencerClient; use sov_db::ledger_db::LedgerDB; use sov_modules_api::WorkingSet; use sov_rollup_interface::services::da::DaService; @@ -38,7 +38,7 @@ pub struct Ethereum { pub(crate) eth_signer: DevSigner, pub(crate) storage: C::Storage, pub(crate) ledger_db: LedgerDB, - pub(crate) sequencer_client: Option, + pub(crate) sequencer_client: Option, pub(crate) web3_client_version: String, pub(crate) trace_cache: Mutex, ByLength>>, pub(crate) subscription_manager: Option, @@ -53,7 +53,7 @@ impl Ethereum { #[cfg(feature = "local")] eth_signer: DevSigner, storage: C::Storage, ledger_db: LedgerDB, - sequencer_client: Option, + sequencer_client: Option, soft_confirmation_rx: Option>, ) -> Self { let evm = Evm::::default(); diff --git a/crates/ethereum-rpc/src/lib.rs b/crates/ethereum-rpc/src/lib.rs index 516d1378e..e65ba19ea 100644 --- a/crates/ethereum-rpc/src/lib.rs +++ b/crates/ethereum-rpc/src/lib.rs @@ -8,18 +8,20 @@ use std::sync::Arc; #[cfg(feature = "local")] pub use citrea_evm::DevSigner; use citrea_evm::{Evm, Filter}; +use citrea_sequencer::SequencerRpcClient; pub use ethereum::{EthRpcConfig, Ethereum}; pub use gas_price::fee_history::FeeHistoryCacheConfig; pub use gas_price::gas_oracle::GasPriceOracleConfig; +use jsonrpsee::http_client::HttpClientBuilder; use jsonrpsee::types::ErrorObjectOwned; use jsonrpsee::RpcModule; use reth_primitives::{keccak256, BlockNumberOrTag, Bytes, B256, U256}; use reth_rpc_eth_types::EthApiError; use reth_rpc_types::trace::geth::{GethDebugTracingOptions, GethTrace}; use reth_rpc_types::{FeeHistory, Index}; -use sequencer_client::SequencerClient; use serde_json::json; use sov_db::ledger_db::{LedgerDB, SharedLedgerOps}; +use sov_ledger_rpc::LedgerRpcClient; use sov_modules_api::da::BlockHeaderTrait; use sov_modules_api::utils::to_jsonrpsee_error_object; use sov_modules_api::WorkingSet; @@ -75,7 +77,7 @@ pub fn get_ethereum_rpc( eth_signer, storage, ledger_db, - sequencer_client_url.map(SequencerClient::new), + sequencer_client_url.map(|url| HttpClientBuilder::default().build(url).unwrap()), soft_confirmation_rx, )); @@ -513,7 +515,7 @@ fn register_rpc_methods( .sequencer_client .as_ref() .unwrap() - .send_raw_tx(data) + .eth_send_raw_transaction(data) .await; match tx_hash { @@ -541,7 +543,7 @@ fn register_rpc_methods( .sequencer_client .as_ref() .unwrap() - .get_tx_by_hash(hash, Some(true)) + .eth_get_transaction_by_hash(hash, Some(true)) .await { Ok(tx) => Ok(tx), @@ -563,7 +565,7 @@ fn register_rpc_methods( .sequencer_client .as_ref() .unwrap() - .get_tx_by_hash(hash, Some(true)) + .eth_get_transaction_by_hash(hash, Some(true)) .await { Ok(tx) => Ok(tx), @@ -592,7 +594,11 @@ fn register_rpc_methods( // sequencer client should send latest l2 height // da service should send latest finalized l1 block header let (sequencer_response, da_response) = join!( - ethereum.sequencer_client.as_ref().unwrap().block_number(), + ethereum + .sequencer_client + .as_ref() + .unwrap() + .get_head_soft_confirmation_height(), ethereum.da_service.get_last_finalized_block_header() ); // handle sequencer response diff --git a/crates/fullnode/Cargo.toml b/crates/fullnode/Cargo.toml index 57b192c8a..4bcd728d1 100644 --- a/crates/fullnode/Cargo.toml +++ b/crates/fullnode/Cargo.toml @@ -13,10 +13,10 @@ repository.workspace = true citrea-common = { path = "../common" } citrea-primitives = { path = "../primitives", features = ["native"] } citrea-pruning = { path = "../pruning" } -sequencer-client = { path = "../sequencer-client" } # Sov SDK deps sov-db = { path = "../sovereign-sdk/full-node/db/sov-db" } +sov-ledger-rpc = { path = "../sovereign-sdk/full-node/sov-ledger-rpc", features = ["client"] } sov-modules-api = { path = "../sovereign-sdk/module-system/sov-modules-api", default-features = false } sov-modules-stf-blueprint = { path = "../sovereign-sdk/module-system/sov-modules-stf-blueprint", features = ["native"] } sov-prover-storage-manager = { path = "../sovereign-sdk/full-node/sov-prover-storage-manager" } @@ -31,6 +31,7 @@ futures = { workspace = true } hex = { workspace = true } jsonrpsee = { workspace = true } rand = { workspace = true } +reth-primitives = { workspace = true } rs_merkle = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } diff --git a/crates/fullnode/src/runner.rs b/crates/fullnode/src/runner.rs index 0df88158a..49460c7df 100644 --- a/crates/fullnode/src/runner.rs +++ b/crates/fullnode/src/runner.rs @@ -13,16 +13,19 @@ use citrea_common::{RollupPublicKeys, RpcConfig, RunnerConfig}; use citrea_primitives::types::SoftConfirmationHash; use citrea_pruning::{Pruner, PruningConfig}; use jsonrpsee::core::client::Error as JsonrpseeError; +use jsonrpsee::http_client::{HttpClient, HttpClientBuilder}; use jsonrpsee::server::{BatchRequestConfig, RpcServiceBuilder, ServerBuilder}; use jsonrpsee::RpcModule; -use sequencer_client::{GetSoftConfirmationResponse, SequencerClient}; +use reth_primitives::U64; use sov_db::ledger_db::NodeLedgerOps; use sov_db::schema::types::{BatchNumber, SlotNumber}; +use sov_ledger_rpc::LedgerRpcClient; use sov_modules_api::{Context, SignedSoftConfirmation, Spec}; use sov_modules_stf_blueprint::{Runtime, StfBlueprint}; use sov_prover_storage_manager::{ProverStorage, ProverStorageManager, SnapshotManager}; -use sov_rollup_interface::da::{BlockHeaderTrait, DaSpec}; +use sov_rollup_interface::da::BlockHeaderTrait; use sov_rollup_interface::fork::ForkManager; +use sov_rollup_interface::rpc::SoftConfirmationResponse; use sov_rollup_interface::services::da::{DaService, SlotData}; use sov_rollup_interface::spec::SpecId; use sov_rollup_interface::stf::StateTransitionFunction; @@ -56,7 +59,7 @@ where state_root: StateRoot, batch_hash: SoftConfirmationHash, rpc_config: RpcConfig, - sequencer_client: SequencerClient, + sequencer_client: HttpClient, sequencer_pub_key: Vec, sequencer_da_pub_key: Vec, prover_da_pub_key: Vec, @@ -133,7 +136,8 @@ where state_root: prev_state_root, batch_hash: prev_batch_hash, rpc_config, - sequencer_client: SequencerClient::new(runner_config.sequencer_client_url), + sequencer_client: HttpClientBuilder::default() + .build(runner_config.sequencer_client_url)?, sequencer_pub_key: public_keys.sequencer_public_key, sequencer_da_pub_key: public_keys.sequencer_da_pub_key, prover_da_pub_key: public_keys.prover_da_pub_key, @@ -218,7 +222,7 @@ where async fn process_l2_block( &mut self, l2_height: u64, - soft_confirmation: &GetSoftConfirmationResponse, + soft_confirmation: &SoftConfirmationResponse, ) -> anyhow::Result<()> { let current_l1_block = get_da_block_at_height( &self.da_service, @@ -320,7 +324,7 @@ where match last_scanned_l1_height { Some(height) => height.0, - None => get_initial_slot_height::(&self.sequencer_client).await, + None => get_initial_slot_height(&self.sequencer_client).await, } }; @@ -362,7 +366,7 @@ where }); let (l2_tx, mut l2_rx) = mpsc::channel(1); - let l2_sync_worker = sync_l2::( + let l2_sync_worker = sync_l2( self.start_l2_height, self.sequencer_client.clone(), l2_tx, @@ -372,7 +376,7 @@ where // Store L2 blocks and make sure they are processed in order. // Otherwise, processing N+1 L2 block before N would emit prev_hash mismatch. - let mut pending_l2_blocks: VecDeque<(u64, GetSoftConfirmationResponse)> = VecDeque::new(); + let mut pending_l2_blocks = VecDeque::new(); let mut interval = tokio::time::interval(Duration::from_secs(1)); interval.tick().await; @@ -390,7 +394,7 @@ where if let Err(e) = self.process_l2_block(*l2_height, l2_block).await { error!("Could not process L2 block: {}", e); // This block failed to process, add remaining L2 blocks to queue including this one. - let remaining_l2s: Vec<(u64, GetSoftConfirmationResponse)> = l2_blocks[index..].to_vec(); + let remaining_l2s = l2_blocks[index..].to_vec(); pending_l2_blocks.extend(remaining_l2s); break; } @@ -434,14 +438,12 @@ where } } -async fn sync_l2( +async fn sync_l2( start_l2_height: u64, - sequencer_client: SequencerClient, - sender: mpsc::Sender>, + sequencer_client: HttpClient, + sender: mpsc::Sender>, sync_blocks_count: u64, -) where - Da: DaService, -{ +) { let mut l2_height = start_l2_height; info!("Starting to sync from L2 height {}", l2_height); loop { @@ -451,43 +453,43 @@ async fn sync_l2( .build(); let inner_client = &sequencer_client; - let soft_confirmations: Vec = - match retry_backoff(exponential_backoff.clone(), || async move { - match inner_client - .get_soft_confirmation_range::( - l2_height..=l2_height + sync_blocks_count - 1, - ) - .await - { - Ok(soft_confirmations) => { - Ok(soft_confirmations.into_iter().flatten().collect::>()) - } - Err(e) => match e.downcast_ref::() { - Some(JsonrpseeError::Transport(e)) => { - let error_msg = format!( - "Soft Confirmation: connection error during RPC call: {:?}", - e - ); - debug!(error_msg); - Err(backoff::Error::Transient { - err: error_msg, - retry_after: None, - }) - } - _ => Err(backoff::Error::Transient { - err: format!("Soft Confirmation: unknown error from RPC call: {:?}", e), - retry_after: None, - }), - }, - } - }) - .await + let soft_confirmations = match retry_backoff(exponential_backoff.clone(), || async move { + match inner_client + .get_soft_confirmation_range( + U64::from(l2_height), + U64::from(l2_height + sync_blocks_count - 1), + ) + .await { - Ok(soft_confirmations) => soft_confirmations, - Err(_) => { - continue; + Ok(soft_confirmations) => { + Ok(soft_confirmations.into_iter().flatten().collect::>()) } - }; + Err(e) => match e { + JsonrpseeError::Transport(e) => { + let error_msg = format!( + "Soft Confirmation: connection error during RPC call: {:?}", + e + ); + debug!(error_msg); + Err(backoff::Error::Transient { + err: error_msg, + retry_after: None, + }) + } + _ => Err(backoff::Error::Transient { + err: format!("Soft Confirmation: unknown error from RPC call: {:?}", e), + retry_after: None, + }), + }, + } + }) + .await + { + Ok(soft_confirmations) => soft_confirmations, + Err(_) => { + continue; + } + }; if soft_confirmations.is_empty() { debug!( @@ -499,7 +501,7 @@ async fn sync_l2( continue; } - let mut soft_confirmations: Vec<(u64, GetSoftConfirmationResponse)> = (l2_height + let mut soft_confirmations: Vec<(u64, SoftConfirmationResponse)> = (l2_height ..l2_height + soft_confirmations.len() as u64) .zip(soft_confirmations) .collect(); @@ -516,9 +518,9 @@ async fn sync_l2( } } -async fn get_initial_slot_height(client: &SequencerClient) -> u64 { +async fn get_initial_slot_height(client: &HttpClient) -> u64 { loop { - match client.get_soft_confirmation::(1).await { + match client.get_soft_confirmation_by_number(U64::from(1)).await { Ok(Some(soft_confirmation)) => return soft_confirmation.da_slot_height, _ => { // sleep 1 diff --git a/crates/light-client-prover/Cargo.toml b/crates/light-client-prover/Cargo.toml index f8c07dc71..df53c7a23 100644 --- a/crates/light-client-prover/Cargo.toml +++ b/crates/light-client-prover/Cargo.toml @@ -12,10 +12,10 @@ repository.workspace = true # Citrea Deps citrea-common = { path = "../common", optional = true } citrea-primitives = { path = "../primitives", optional = true } -sequencer-client = { path = "../sequencer-client", optional = true } # Sov SDK deps sov-db = { path = "../sovereign-sdk/full-node/db/sov-db", optional = true } +sov-ledger-rpc = { path = "../sovereign-sdk/full-node/sov-ledger-rpc", features = ["client"], optional = true } sov-modules-api = { path = "../sovereign-sdk/module-system/sov-modules-api", default-features = false } sov-modules-rollup-blueprint = { path = "../sovereign-sdk/module-system/sov-modules-rollup-blueprint", optional = true } sov-rollup-interface = { path = "../sovereign-sdk/rollup-interface" } @@ -28,6 +28,7 @@ bincode = { workspace = true } borsh = { workspace = true } hex = { workspace = true } jsonrpsee = { workspace = true, optional = true, features = ["http-client", "server", "client"] } +reth-primitives = { workspace = true, optional = true } tokio = { workspace = true, optional = true } tokio-util = { workspace = true, optional = true } tower = { workspace = true, optional = true } @@ -43,14 +44,14 @@ default = [] native = [ "dep:citrea-primitives", "dep:citrea-common", - "dep:sequencer-client", "dep:sov-db", "dep:sov-modules-rollup-blueprint", "dep:sov-stf-runner", - + "dep:sov-ledger-rpc", "dep:anyhow", "dep:async-trait", "dep:jsonrpsee", + "dep:reth-primitives", "dep:tokio", "dep:tokio-util", "dep:tower", diff --git a/crates/light-client-prover/src/da_block_handler.rs b/crates/light-client-prover/src/da_block_handler.rs index b2e64c903..a5c06c829 100644 --- a/crates/light-client-prover/src/da_block_handler.rs +++ b/crates/light-client-prover/src/da_block_handler.rs @@ -7,9 +7,11 @@ use citrea_common::cache::L1BlockCache; use citrea_common::da::get_da_block_at_height; use citrea_common::LightClientProverConfig; use citrea_primitives::forks::FORKS; -use sequencer_client::SequencerClient; +use jsonrpsee::http_client::HttpClient; +use reth_primitives::U64; use sov_db::ledger_db::{LightClientProverLedgerOps, SharedLedgerOps}; use sov_db::schema::types::{SlotNumber, StoredLightClientProofOutput}; +use sov_ledger_rpc::LedgerRpcClient; use sov_modules_api::fork::fork_from_block_number; use sov_modules_api::{BatchProofCircuitOutput, BlobReaderTrait, DaSpec, Zkvm}; use sov_rollup_interface::da::{BlockHeaderTrait, DaDataLightClient, DaNamespace}; @@ -42,7 +44,7 @@ where light_client_proof_elfs: HashMap>, l1_block_cache: Arc>>, queued_l1_blocks: VecDeque<::FilteredBlock>, - sequencer_client: Arc, + sequencer_client: Arc, } impl L1BlockHandler @@ -62,7 +64,7 @@ where batch_proof_code_commitments: HashMap, light_client_proof_code_commitments: HashMap, light_client_proof_elfs: HashMap>, - sequencer_client: Arc, + sequencer_client: Arc, ) -> Self { Self { _prover_config: prover_config, @@ -194,7 +196,7 @@ where None => { let soft_confirmation = self .sequencer_client - .get_soft_confirmation::(1) + .get_soft_confirmation_by_number(U64::from(1)) .await? .unwrap(); let initial_l1_height = soft_confirmation.da_slot_height; diff --git a/crates/light-client-prover/src/runner.rs b/crates/light-client-prover/src/runner.rs index 4b8b63124..1675eeb5a 100644 --- a/crates/light-client-prover/src/runner.rs +++ b/crates/light-client-prover/src/runner.rs @@ -4,12 +4,13 @@ use std::sync::Arc; use citrea_common::tasks::manager::TaskManager; use citrea_common::{LightClientProverConfig, RollupPublicKeys, RpcConfig, RunnerConfig}; +use jsonrpsee::http_client::{HttpClient, HttpClientBuilder}; use jsonrpsee::server::{BatchRequestConfig, ServerBuilder}; use jsonrpsee::RpcModule; -use sequencer_client::SequencerClient; +use reth_primitives::U64; use sov_db::ledger_db::{LedgerDB, LightClientProverLedgerOps, SharedLedgerOps}; use sov_db::schema::types::SlotNumber; -use sov_modules_api::DaSpec; +use sov_ledger_rpc::LedgerRpcClient; use sov_modules_rollup_blueprint::RollupBlueprint; use sov_rollup_interface::services::da::DaService; use sov_rollup_interface::spec::SpecId; @@ -69,7 +70,7 @@ where rpc_config: RpcConfig, da_service: Arc, ledger_db: DB, - sequencer_client: SequencerClient, + sequencer_client: HttpClient, prover_service: Arc, prover_config: LightClientProverConfig, task_manager: TaskManager<()>, @@ -106,7 +107,7 @@ where rpc_config, da_service, ledger_db, - sequencer_client: SequencerClient::new(sequencer_client_url), + sequencer_client: HttpClientBuilder::default().build(sequencer_client_url)?, prover_service, prover_config, task_manager, @@ -185,7 +186,7 @@ where let last_l1_height_scanned = match self.ledger_db.get_last_scanned_l1_height()? { Some(l1_height) => l1_height, // If not found, start from the first L2 block's L1 height - None => SlotNumber(get_initial_da_height::(&self.sequencer_client).await), + None => SlotNumber(get_initial_da_height(&self.sequencer_client).await), }; let prover_config = self.prover_config.clone(); @@ -250,9 +251,9 @@ where } } -async fn get_initial_da_height(client: &SequencerClient) -> u64 { +async fn get_initial_da_height(client: &HttpClient) -> u64 { loop { - match client.get_soft_confirmation::(1).await { + match client.get_soft_confirmation_by_number(U64::from(1)).await { Ok(Some(batch)) => return batch.da_slot_height, _ => { // sleep 1 diff --git a/crates/sequencer-client/Cargo.toml b/crates/sequencer-client/Cargo.toml deleted file mode 100644 index 9cb8e654a..000000000 --- a/crates/sequencer-client/Cargo.toml +++ /dev/null @@ -1,41 +0,0 @@ -[package] -name = "sequencer-client" -authors = { workspace = true } -edition = { workspace = true } -homepage = { workspace = true } -license = { workspace = true } -repository = { workspace = true } - -version = { workspace = true } -publish = false -readme = "README.md" -resolver = "2" - -[dependencies] -# 3rd-party dependencies -anyhow = { workspace = true } -borsh = { workspace = true } -hex = { workspace = true } -jsonrpsee = { workspace = true, features = ["http-client"] } -serde = { workspace = true } -serde_json = { workspace = true } -tokio = { workspace = true } -tracing = { workspace = true } - -# Reth Deps -reth-primitives = { workspace = true } -reth-rpc-types = { workspace = true } - -# Sovereign-SDK deps -sov-rollup-interface = { path = "../sovereign-sdk/rollup-interface" } - -# Citrea Deps -citrea-primitives = { path = "../primitives" } - -[dev-dependencies] -tokio = { workspace = true } - -[features] -default = [] -local = [] -native = ["sov-rollup-interface/native"] diff --git a/crates/sequencer-client/README.md b/crates/sequencer-client/README.md deleted file mode 100644 index 14099a1d5..000000000 --- a/crates/sequencer-client/README.md +++ /dev/null @@ -1,3 +0,0 @@ -## Sequencer Client - -An HTTP client to connect to the [Citrea Sequencer](../sequencer/README.md), used by the full nodes, along with some utils for Soft Confirmations. diff --git a/crates/sequencer-client/src/lib.rs b/crates/sequencer-client/src/lib.rs deleted file mode 100644 index aa81ee5af..000000000 --- a/crates/sequencer-client/src/lib.rs +++ /dev/null @@ -1,175 +0,0 @@ -use std::fmt::Debug; -use std::ops::RangeInclusive; - -use borsh::BorshDeserialize; -use citrea_primitives::types::SoftConfirmationHash; -use jsonrpsee::core::client::{ClientT, Error}; -use jsonrpsee::http_client::{HttpClient, HttpClientBuilder}; -use jsonrpsee::rpc_params; -use reth_primitives::{Bytes, B256}; -use serde::Deserialize; -use sov_rollup_interface::rpc::HexTx; -use sov_rollup_interface::soft_confirmation::SignedSoftConfirmation; -use tracing::instrument; - -/// Configuration for SequencerClient. -#[derive(Debug, Clone)] -pub struct SequencerClient { - /// Host config for soft confirmation - pub rpc_url: String, - /// Client object for soft confirmation - pub client: HttpClient, -} - -impl SequencerClient { - /// Creates the sequencer client - #[instrument(level = "trace")] - pub fn new(rpc_url: String) -> Self { - let client = HttpClientBuilder::default().build(&rpc_url).unwrap(); - Self { rpc_url, client } - } - - /// Gets l2 block given l2 height - #[instrument(level = "trace", skip(self), ret)] - pub async fn get_soft_confirmation( - &self, - num: u64, - ) -> anyhow::Result> { - let res: Result, Error> = self - .client - .request("ledger_getSoftConfirmationByNumber", rpc_params![num]) - .await; - - match res { - Ok(res) => Ok(res), - Err(e) => match e { - Error::Transport(e) => anyhow::Result::Err(Error::Transport(e).into()), - _ => Err(anyhow::anyhow!(e)), - }, - } - } - - /// Gets l2 blocks given a range - #[instrument(level = "trace", skip(self), ret)] - pub async fn get_soft_confirmation_range( - &self, - range: RangeInclusive, - ) -> anyhow::Result>> { - let res: Result>, Error> = self - .client - .request( - "ledger_getSoftConfirmationRange", - rpc_params![range.start(), range.end()], - ) - .await; - - match res { - Ok(res) => Ok(res), - Err(e) => match e { - Error::Transport(e) => anyhow::Result::Err(Error::Transport(e).into()), - _ => Err(anyhow::anyhow!(e)), - }, - } - } - - /// Gets l2 block height - #[instrument(level = "trace", skip(self), ret)] - pub async fn block_number(&self) -> Result { - self.client - .request("ledger_getHeadSoftConfirmationHeight", rpc_params![]) - .await - } - - /// Sends raw tx to sequencer - #[instrument(level = "trace", skip_all, ret)] - pub async fn send_raw_tx(&self, tx: Bytes) -> Result { - self.client - .request("eth_sendRawTransaction", rpc_params![tx]) - .await - } - - #[instrument(level = "trace", skip(self), ret)] - pub async fn get_tx_by_hash( - &self, - tx_hash: B256, - mempool_only: Option, - ) -> Result, Error> { - self.client - .request( - "eth_getTransactionByHash", - rpc_params![tx_hash, mempool_only], - ) - .await - } - - #[instrument(level = "trace", skip(self), ret)] - pub async fn get_l2_genesis_state_root(&self) -> Result>, Error> { - self.client - .request("ledger_getL2GenesisStateRoot", rpc_params![]) - .await - } -} - -#[derive(Deserialize, Debug, Clone)] -#[serde(rename_all = "camelCase")] -pub struct GetSoftConfirmationResponse { - pub l2_height: u64, - #[serde(with = "hex::serde")] - pub hash: SoftConfirmationHash, - #[serde(with = "hex::serde")] - pub prev_hash: SoftConfirmationHash, - pub da_slot_height: u64, - #[serde(with = "hex::serde")] - pub da_slot_hash: [u8; 32], - #[serde(with = "hex::serde")] - pub da_slot_txs_commitment: [u8; 32], - #[serde(skip_serializing_if = "Option::is_none")] - pub txs: Option>, - #[serde(with = "hex::serde")] - pub state_root: Vec, - #[serde(with = "hex::serde")] - pub soft_confirmation_signature: Vec, - pub deposit_data: Vec, // Vec wrapper around deposit data - #[serde(with = "hex::serde")] - pub pub_key: Vec, - pub l1_fee_rate: u128, - pub timestamp: u64, -} - -impl<'txs, Tx> TryFrom for SignedSoftConfirmation<'txs, Tx> -where - Tx: Clone + BorshDeserialize, -{ - type Error = borsh::io::Error; - fn try_from(val: GetSoftConfirmationResponse) -> Result { - let parsed_txs = val - .txs - .iter() - .flatten() - .map(|tx| { - let body = &tx.tx; - borsh::from_slice::(body) - }) - .collect::, Self::Error>>()?; - let res = SignedSoftConfirmation::new( - val.l2_height, - val.hash, - val.prev_hash, - val.da_slot_height, - val.da_slot_hash, - val.da_slot_txs_commitment, - val.l1_fee_rate, - val.txs - .unwrap_or_default() - .into_iter() - .map(|tx| tx.tx) - .collect(), - parsed_txs.into(), - val.deposit_data.into_iter().map(|tx| tx.tx).collect(), - val.soft_confirmation_signature, - val.pub_key, - val.timestamp, - ); - Ok(res) - } -} diff --git a/crates/sovereign-sdk/rollup-interface/src/node/rpc/mod.rs b/crates/sovereign-sdk/rollup-interface/src/node/rpc/mod.rs index 0788a0d29..5d7e18205 100644 --- a/crates/sovereign-sdk/rollup-interface/src/node/rpc/mod.rs +++ b/crates/sovereign-sdk/rollup-interface/src/node/rpc/mod.rs @@ -12,6 +12,7 @@ use borsh::{BorshDeserialize, BorshSerialize}; use serde::{Deserialize, Serialize}; use crate::da::SequencerCommitment; +use crate::soft_confirmation::SignedSoftConfirmation; use crate::zk::{BatchProofInfo, CumulativeStateDiff}; /// A struct containing enough information to uniquely specify single batch. @@ -83,6 +84,44 @@ pub struct SoftConfirmationResponse { pub timestamp: u64, } +impl<'txs, Tx> TryFrom for SignedSoftConfirmation<'txs, Tx> +where + Tx: Clone + BorshDeserialize, +{ + type Error = borsh::io::Error; + fn try_from(val: SoftConfirmationResponse) -> Result { + let parsed_txs = val + .txs + .iter() + .flatten() + .map(|tx| { + let body = &tx.tx; + borsh::from_slice::(body) + }) + .collect::, Self::Error>>()?; + let res = SignedSoftConfirmation::new( + val.l2_height, + val.hash, + val.prev_hash, + val.da_slot_height, + val.da_slot_hash, + val.da_slot_txs_commitment, + val.l1_fee_rate, + val.txs + .unwrap_or_default() + .into_iter() + .map(|tx| tx.tx) + .collect(), + parsed_txs.into(), + val.deposit_data.into_iter().map(|tx| tx.tx).collect(), + val.soft_confirmation_signature, + val.pub_key, + val.timestamp, + ); + Ok(res) + } +} + /// The response to a JSON-RPC request for sequencer commitments on a DA Slot. #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")]