From e68dcfe426df5ee77f449b6d7461e4646ffecf9c Mon Sep 17 00:00:00 2001 From: Sapin Bajracharya Date: Fri, 17 Jan 2025 15:28:23 +0545 Subject: [PATCH 1/4] bitcoinclient: make retry count and retry interval configurable --- bin/bridge-client/src/args.rs | 11 ++++++ .../src/modes/operator/bootstrap.rs | 10 ++++-- bin/prover-client/src/args.rs | 11 ++++++ bin/prover-client/src/main.rs | 2 ++ bin/strata-client/src/args.rs | 19 +++++++++++ bin/strata-client/src/helpers.rs | 2 ++ crates/btcio/src/rpc/client.rs | 34 +++++++++++++++---- crates/btcio/src/test_utils.rs | 2 +- crates/config/src/config.rs | 4 +++ crates/util/python-utils/src/drt.rs | 12 ++++--- 10 files changed, 94 insertions(+), 13 deletions(-) diff --git a/bin/bridge-client/src/args.rs b/bin/bridge-client/src/args.rs index 1c4bf35ef..900df402f 100644 --- a/bin/bridge-client/src/args.rs +++ b/bin/bridge-client/src/args.rs @@ -66,6 +66,17 @@ pub(crate) struct Cli { #[argh(option, description = "password for bitcoin RPC")] pub btc_pass: String, + /// Max retries for Bitcoin RPC calls. + #[argh(option, description = "max retries for bitcoin RPC (default: 3)")] + pub btc_retry_count: Option, + + /// Timeout duration for btc request retries in ms. Defaults to `1000`. + #[argh( + option, + description = "max interval between bitcoin RPC retries in ms (default: 1000)" + )] + pub btc_retry_interval: Option, + /// URL for the Rollup RPC server. #[argh(option, description = "url for the rollup RPC server")] pub rollup_url: String, diff --git a/bin/bridge-client/src/modes/operator/bootstrap.rs b/bin/bridge-client/src/modes/operator/bootstrap.rs index bf0c8836e..4fe34cb35 100644 --- a/bin/bridge-client/src/modes/operator/bootstrap.rs +++ b/bin/bridge-client/src/modes/operator/bootstrap.rs @@ -65,8 +65,14 @@ pub(crate) async fn bootstrap(args: Cli) -> anyhow::Result<()> { // Setup RPC clients. let l1_rpc_client = Arc::new( - BitcoinClient::new(args.btc_url, args.btc_user, args.btc_pass) - .expect("error creating the bitcoin client"), + BitcoinClient::new( + args.btc_url, + args.btc_user, + args.btc_pass, + args.btc_retry_count, + args.btc_retry_interval, + ) + .expect("error creating the bitcoin client"), ); let config = WsClientConfig { diff --git a/bin/prover-client/src/args.rs b/bin/prover-client/src/args.rs index 59951d44d..a41960fe4 100644 --- a/bin/prover-client/src/args.rs +++ b/bin/prover-client/src/args.rs @@ -61,6 +61,17 @@ pub struct Args { #[argh(option, description = "bitcoind RPC password")] pub bitcoind_password: String, + /// Max retries for Bitcoin RPC calls. + #[argh(option, description = "max retries for bitcoin RPC (default: 3)")] + pub bitcoin_retry_count: Option, + + /// Timeout duration for btc request retries in ms. Defaults to `1000`. + #[argh( + option, + description = "max interval between bitcoin RPC retries in ms (default: 1000)" + )] + pub bitcoin_retry_interval: Option, + /// Path to the custom rollup configuration file. #[argh(option, short = 'p', description = "custom rollup config path")] pub rollup_params: PathBuf, diff --git a/bin/prover-client/src/main.rs b/bin/prover-client/src/main.rs index b38b72d53..bf217b4a8 100644 --- a/bin/prover-client/src/main.rs +++ b/bin/prover-client/src/main.rs @@ -63,6 +63,8 @@ async fn main_inner(args: Args) -> anyhow::Result<()> { args.get_btc_rpc_url(), args.bitcoind_user.clone(), args.bitcoind_password.clone(), + args.bitcoin_retry_count, + args.bitcoin_retry_interval, ) .context("Failed to connect to the Bitcoin client")?; diff --git a/bin/strata-client/src/args.rs b/bin/strata-client/src/args.rs index 22b7b7794..fd43ec317 100644 --- a/bin/strata-client/src/args.rs +++ b/bin/strata-client/src/args.rs @@ -36,6 +36,17 @@ pub struct Args { #[argh(option, description = "bitcoind RPC password")] pub bitcoind_password: Option, + /// Max retries for Bitcoin RPC calls. + #[argh(option, description = "max retries for bitcoin RPC (default: 3)")] + pub bitcoind_retry_count: Option, + + /// Timeout duration for btc request retries in ms. Defaults to `1000`. + #[argh( + option, + description = "max interval between bitcoin RPC retries in ms (default: 1000)" + )] + pub bitcoind_retry_interval: Option, + #[argh(option, short = 'n', description = "L1 network to run on")] pub network: Option, @@ -71,6 +82,8 @@ impl Args { "args: no bitcoin --rpc-password provided", )?, network: require(args.network, "args: no bitcoin --network provided")?, + retry_count: args.bitcoind_retry_count, + retry_interval: args.bitcoind_retry_interval, }, client: ClientConfig { rpc_host: require(args.rpc_host, "args: no client --rpc-host provided")?, @@ -123,6 +136,12 @@ impl Args { if let Some(rpc_password) = args.bitcoind_password { config.bitcoind_rpc.rpc_password = rpc_password; } + if let Some(retry_count) = args.bitcoind_retry_count { + config.bitcoind_rpc.retry_count = Some(retry_count); + } + if let Some(retry_interval) = args.bitcoind_retry_interval { + config.bitcoind_rpc.retry_interval = Some(retry_interval); + } if let Some(rpc_host) = args.rpc_host { config.client.rpc_host = rpc_host; } diff --git a/bin/strata-client/src/helpers.rs b/bin/strata-client/src/helpers.rs index 6b6e272d1..55b6d8efe 100644 --- a/bin/strata-client/src/helpers.rs +++ b/bin/strata-client/src/helpers.rs @@ -104,6 +104,8 @@ pub fn create_bitcoin_rpc_client(config: &Config) -> anyhow::Result = Result; /// The maximum number of retries for a request. -const MAX_RETRIES: u8 = 3; +const DEFAULT_MAX_RETRIES: u8 = 3; + +/// The maximum number of retries for a request. +const DEFAULT_RETRY_INTERVAL_MS: u64 = 1_000; /// Custom implementation to convert a value to a `Value` type. pub fn to_value(value: T) -> ClientResult @@ -59,6 +62,10 @@ pub struct BitcoinClient { client: Client, /// The ID of the current request. id: AtomicUsize, + /// The maximum number of retries for a request. + max_retries: u8, + /// Interval between retries for a request in ms. + retry_interval: u64, } /// Response returned by the `bitcoind` RPC server. @@ -71,7 +78,13 @@ struct Response { impl BitcoinClient { /// Creates a new [`BitcoinClient`] with the given URL, username, and password. - pub fn new(url: String, username: String, password: String) -> ClientResult { + pub fn new( + url: String, + username: String, + password: String, + max_retries: Option, + retry_interval: Option, + ) -> ClientResult { if username.is_empty() || password.is_empty() { return Err(ClientError::MissingUserPassword); } @@ -96,9 +109,18 @@ impl BitcoinClient { let id = AtomicUsize::new(0); + let max_retries = max_retries.unwrap_or(DEFAULT_MAX_RETRIES); + let retry_interval = retry_interval.unwrap_or(DEFAULT_RETRY_INTERVAL_MS); + trace!(url = %url, "Created bitcoin client"); - Ok(Self { url, client, id }) + Ok(Self { + url, + client, + id, + max_retries, + retry_interval, + }) } fn next_id(&self) -> usize { @@ -186,10 +208,10 @@ impl BitcoinClient { } } retries += 1; - if retries >= MAX_RETRIES { - return Err(ClientError::MaxRetriesExceeded(MAX_RETRIES)); + if retries >= self.max_retries { + return Err(ClientError::MaxRetriesExceeded(self.max_retries)); } - sleep(Duration::from_millis(1_000)).await; + sleep(Duration::from_millis(self.retry_interval)).await; } } } diff --git a/crates/btcio/src/test_utils.rs b/crates/btcio/src/test_utils.rs index 9ac635e1b..78d4dff3d 100644 --- a/crates/btcio/src/test_utils.rs +++ b/crates/btcio/src/test_utils.rs @@ -348,7 +348,7 @@ pub mod corepc_node_helpers { let bitcoind = BitcoinD::from_downloaded().unwrap(); let url = bitcoind.rpc_url(); let (user, password) = get_auth(&bitcoind); - let client = BitcoinClient::new(url, user, password).unwrap(); + let client = BitcoinClient::new(url, user, password, None, None).unwrap(); (bitcoind, client) } } diff --git a/crates/config/src/config.rs b/crates/config/src/config.rs index 5be5a08ed..ad2504088 100644 --- a/crates/config/src/config.rs +++ b/crates/config/src/config.rs @@ -45,6 +45,10 @@ pub struct BitcoindConfig { pub rpc_user: String, pub rpc_password: String, pub network: Network, + #[serde(skip_serializing_if = "Option::is_none")] + pub retry_count: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub retry_interval: Option, } #[derive(Debug, Clone, Deserialize)] diff --git a/crates/util/python-utils/src/drt.rs b/crates/util/python-utils/src/drt.rs index 6346687f4..a70410277 100644 --- a/crates/util/python-utils/src/drt.rs +++ b/crates/util/python-utils/src/drt.rs @@ -518,7 +518,8 @@ mod tests { let bitcoind = BitcoinD::from_downloaded().unwrap(); let url = bitcoind.rpc_url(); let (user, password) = get_auth(&bitcoind); - let client = BitcoinClient::new(url.clone(), user.clone(), password.clone()).unwrap(); + let client = + BitcoinClient::new(url.clone(), user.clone(), password.clone(), None, None).unwrap(); let mut wallet = taproot_wallet().unwrap(); let address = wallet.reveal_next_address(KeychainKind::External).address; @@ -546,7 +547,8 @@ mod tests { let bitcoind = BitcoinD::from_downloaded().unwrap(); let url = bitcoind.rpc_url(); let (user, password) = get_auth(&bitcoind); - let client = BitcoinClient::new(url.clone(), user.clone(), password.clone()).unwrap(); + let client = + BitcoinClient::new(url.clone(), user.clone(), password.clone(), None, None).unwrap(); let wallet_client = new_bitcoind_client(&url, None, Some(&user), Some(&password)) .expect("valid wallet client"); @@ -633,7 +635,8 @@ mod tests { let bitcoind = BitcoinD::from_downloaded().unwrap(); let url = bitcoind.rpc_url(); let (user, password) = get_auth(&bitcoind); - let client = BitcoinClient::new(url.clone(), user.clone(), password.clone()).unwrap(); + let client = + BitcoinClient::new(url.clone(), user.clone(), password.clone(), None, None).unwrap(); let wallet_client = new_bitcoind_client(&url, None, Some(&user), Some(&password)) .expect("valid wallet client"); @@ -706,7 +709,8 @@ mod tests { let bitcoind = BitcoinD::from_downloaded().unwrap(); let url = bitcoind.rpc_url(); let (user, password) = get_auth(&bitcoind); - let client = BitcoinClient::new(url.clone(), user.clone(), password.clone()).unwrap(); + let client = + BitcoinClient::new(url.clone(), user.clone(), password.clone(), None, None).unwrap(); let wallet_client = new_bitcoind_client(&url, None, Some(&user), Some(&password)) .expect("valid wallet client"); From 08ca7e12eb3d1a5870752f51522c04580b746480 Mon Sep 17 00:00:00 2001 From: Sapin Bajracharya Date: Fri, 17 Jan 2025 15:41:20 +0545 Subject: [PATCH 2/4] refactor: rename to indicate default values --- bin/bridge-client/src/constants.rs | 4 ++-- bin/bridge-client/src/modes/operator/bootstrap.rs | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/bin/bridge-client/src/constants.rs b/bin/bridge-client/src/constants.rs index aa24623ec..3f103279e 100644 --- a/bin/bridge-client/src/constants.rs +++ b/bin/bridge-client/src/constants.rs @@ -6,7 +6,7 @@ pub(super) const DEFAULT_RPC_HOST: &str = "127.0.0.1"; pub(super) const DEFAULT_DUTY_TIMEOUT_SEC: u64 = 600; /// The default bridge rocksdb database retry count, if not overridden by the user. -pub(super) const ROCKSDB_RETRY_COUNT: u16 = 3; +pub(super) const DEFAULT_ROCKSDB_RETRY_COUNT: u16 = 3; /// The default RPC retry count, if not overridden by the user. -pub(super) const MAX_RPC_RETRY_COUNT: u16 = 5; +pub(super) const DEFAULT_MAX_RPC_RETRY_COUNT: u16 = 5; diff --git a/bin/bridge-client/src/modes/operator/bootstrap.rs b/bin/bridge-client/src/modes/operator/bootstrap.rs index 4fe34cb35..28ca712c7 100644 --- a/bin/bridge-client/src/modes/operator/bootstrap.rs +++ b/bin/bridge-client/src/modes/operator/bootstrap.rs @@ -31,8 +31,8 @@ use super::{constants::DB_THREAD_COUNT, task_manager::TaskManager}; use crate::{ args::Cli, constants::{ - DEFAULT_DUTY_TIMEOUT_SEC, DEFAULT_RPC_HOST, DEFAULT_RPC_PORT, MAX_RPC_RETRY_COUNT, - ROCKSDB_RETRY_COUNT, + DEFAULT_DUTY_TIMEOUT_SEC, DEFAULT_MAX_RPC_RETRY_COUNT, DEFAULT_ROCKSDB_RETRY_COUNT, + DEFAULT_RPC_HOST, DEFAULT_RPC_PORT, }, db::open_rocksdb_database, rpc_server::{self, BridgeRpc}, @@ -48,7 +48,7 @@ pub(crate) async fn bootstrap(args: Cli) -> anyhow::Result<()> { // Initialize a rocksdb instance with the required column families. let rbdb = open_rocksdb_database(data_dir)?; - let retry_count = args.retry_count.unwrap_or(ROCKSDB_RETRY_COUNT); + let retry_count = args.retry_count.unwrap_or(DEFAULT_ROCKSDB_RETRY_COUNT); let ops_config = DbOpsConfig::new(retry_count); // Setup Threadpool for the database I/O ops. @@ -175,7 +175,9 @@ pub(crate) async fn bootstrap(args: Cli) -> anyhow::Result<()> { .unwrap_or(DEFAULT_DUTY_TIMEOUT_SEC), ); - let max_retry_count = args.max_rpc_retry_count.unwrap_or(MAX_RPC_RETRY_COUNT); + let max_retry_count = args + .max_rpc_retry_count + .unwrap_or(DEFAULT_MAX_RPC_RETRY_COUNT); // TODO: wrap these in `strata-tasks` let duty_task = tokio::spawn(async move { From b0f834de28b81da147fe4374eb2e6d5bf5ea73f0 Mon Sep 17 00:00:00 2001 From: Sapin Bajracharya Date: Tue, 21 Jan 2025 15:49:34 +0545 Subject: [PATCH 3/4] make broadcast poll duration configurable --- bin/strata-client/src/main.rs | 11 +++++++++-- crates/btcio/src/broadcaster/handle.rs | 13 ++++++++++--- crates/btcio/src/broadcaster/task.rs | 5 ++--- crates/config/src/btcio.rs | 16 ++++++++++++++++ crates/config/src/config.rs | 6 ++++++ 5 files changed, 43 insertions(+), 8 deletions(-) diff --git a/bin/strata-client/src/main.rs b/bin/strata-client/src/main.rs index 585f8a9f2..affa7af81 100644 --- a/bin/strata-client/src/main.rs +++ b/bin/strata-client/src/main.rs @@ -140,6 +140,7 @@ fn main_inner(args: Args) -> anyhow::Result<()> { &executor, ctx.bitcoin_client.clone(), params.clone(), + config.btcio.broadcaster.poll_interval_ms, ); let writer_db = init_writer_database(rbdb.clone(), ops_config); @@ -477,6 +478,7 @@ fn start_broadcaster_tasks( executor: &TaskExecutor, bitcoin_client: Arc, params: Arc, + broadcast_poll_interval: u64, ) -> Arc { // Set up L1 broadcaster. let broadcast_ctx = strata_storage::ops::l1tx_broadcast::Context::new( @@ -484,8 +486,13 @@ fn start_broadcaster_tasks( ); let broadcast_ops = Arc::new(broadcast_ctx.into_ops(pool)); // start broadcast task - let broadcast_handle = - spawn_broadcaster_task(executor, bitcoin_client.clone(), broadcast_ops, params); + let broadcast_handle = spawn_broadcaster_task( + executor, + bitcoin_client.clone(), + broadcast_ops, + params, + broadcast_poll_interval, + ); Arc::new(broadcast_handle) } diff --git a/crates/btcio/src/broadcaster/handle.rs b/crates/btcio/src/broadcaster/handle.rs index c1f4cc190..20f1197d2 100644 --- a/crates/btcio/src/broadcaster/handle.rs +++ b/crates/btcio/src/broadcaster/handle.rs @@ -70,6 +70,7 @@ pub fn spawn_broadcaster_task( l1_rpc_client: Arc, broadcast_ops: Arc, params: Arc, + broadcast_poll_interval: u64, ) -> L1BroadcastHandle where T: ReaderRpc + BroadcasterRpc + WalletRpc + SignerRpc + Send + Sync + 'static, @@ -77,9 +78,15 @@ where let (broadcast_entry_tx, broadcast_entry_rx) = mpsc::channel::<(u64, L1TxEntry)>(64); let ops = broadcast_ops.clone(); executor.spawn_critical_async("l1_broadcaster_task", async move { - broadcaster_task(l1_rpc_client, ops, broadcast_entry_rx, params) - .await - .map_err(Into::into) + broadcaster_task( + l1_rpc_client, + ops, + broadcast_entry_rx, + params, + broadcast_poll_interval, + ) + .await + .map_err(Into::into) }); L1BroadcastHandle::new(broadcast_entry_tx, broadcast_ops) } diff --git a/crates/btcio/src/broadcaster/task.rs b/crates/btcio/src/broadcaster/task.rs index 3db50f154..e890275e4 100644 --- a/crates/btcio/src/broadcaster/task.rs +++ b/crates/btcio/src/broadcaster/task.rs @@ -15,17 +15,16 @@ use crate::{ rpc::traits::{BroadcasterRpc, WalletRpc}, }; -const BROADCAST_POLL_INTERVAL: u64 = 1_000; // millis - /// Broadcasts the next blob to be sent pub async fn broadcaster_task( rpc_client: Arc, ops: Arc, mut entry_receiver: Receiver<(u64, L1TxEntry)>, params: Arc, + broadcast_poll_interval: u64, ) -> BroadcasterResult<()> { info!("Starting Broadcaster task"); - let interval = tokio::time::interval(Duration::from_millis(BROADCAST_POLL_INTERVAL)); + let interval = tokio::time::interval(Duration::from_millis(broadcast_poll_interval)); tokio::pin!(interval); let mut state = BroadcasterState::initialize(&ops).await?; diff --git a/crates/config/src/btcio.rs b/crates/config/src/btcio.rs index b7ca3a51d..c25897c20 100644 --- a/crates/config/src/btcio.rs +++ b/crates/config/src/btcio.rs @@ -5,6 +5,7 @@ use serde::Deserialize; pub struct BtcioConfig { pub reader: ReaderConfig, pub writer: WriterConfig, + pub broadcaster: BroadcasterConfig, } /// Configuration for btcio reader. @@ -38,6 +39,13 @@ pub enum FeePolicy { Fixed(u64), } +/// Configuration for btcio broadcaster. +#[derive(Debug, Clone, Deserialize)] +pub struct BroadcasterConfig { + /// How often to invoke the broadcaster, in ms. + pub poll_interval_ms: u64, +} + impl Default for WriterConfig { fn default() -> Self { Self { @@ -56,3 +64,11 @@ impl Default for ReaderConfig { } } } + +impl Default for BroadcasterConfig { + fn default() -> Self { + Self { + poll_interval_ms: 1_000, + } + } +} diff --git a/crates/config/src/config.rs b/crates/config/src/config.rs index ad2504088..d15a0f6eb 100644 --- a/crates/config/src/config.rs +++ b/crates/config/src/config.rs @@ -113,6 +113,9 @@ mod test { reveal_amount = 100 bundle_interval_ms = 1000 + [btcio.broadcaster] + poll_interval_ms = 1000 + [relayer] refresh_interval = 10 stale_duration = 120 @@ -161,6 +164,9 @@ mod test { reveal_amount = 100 bundle_interval_ms = 1000 + [btcio.broadcaster] + poll_interval_ms = 1000 + [exec.reth] rpc_url = "http://localhost:8551" secret = "1234567890abcdef" From 938c7c465ef40e73c12d0c87695224131d78965f Mon Sep 17 00:00:00 2001 From: Sapin Bajracharya Date: Mon, 3 Feb 2025 14:33:02 +0545 Subject: [PATCH 4/4] dep: update openssl to fix cargo audit --- Cargo.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 788080d60..76cc8b992 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3422,7 +3422,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1145d32e826a7748b69ee8fc62d3e6355ff7f1051df53141e7048162fc90481b" dependencies = [ "data-encoding", - "syn 2.0.97", + "syn 1.0.109", ] [[package]] @@ -6923,9 +6923,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.69" +version = "0.10.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5e534d133a060a3c19daec1eb3e98ec6f4685978834f2dbadfe2ec215bab64e" +checksum = "61cfb4e166a8bb8c9b55c500bc2308550148ece889be90f609377e58140f42c6" dependencies = [ "bitflags 2.8.0", "cfg-if", @@ -6955,9 +6955,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.104" +version = "0.9.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc" dependencies = [ "cc", "libc",