Skip to content
Open
Show file tree
Hide file tree
Changes from 7 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 bin/citrea/tests/bitcoin/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ pub async fn spawn_bitcoin_da_service(
utxo_selection_mode,
rpc_timeout_secs: None,
rpc_connect_timeout_secs: None,
max_fee_rate_sat_vb: None,
};

let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
Expand Down
10 changes: 8 additions & 2 deletions crates/bitcoin-da/src/fee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ const BASE_FEE_RATE_MULTIPLIER: f64 = 1.0;
const FEE_RATE_MULTIPLIER_FACTOR: f64 = 1.1;
const MAX_FEE_RATE_MULTIPLIER: f64 = 2.0;

pub(crate) const DEFAULT_MAX_FEE_RATE_SAT_VB: u64 = 15;

/// Type alias for a Partially Signed Bitcoin Transaction (PSBT).
pub type Psbt = String;

Expand Down Expand Up @@ -99,6 +101,7 @@ impl FeeService {
) -> Self {
let mempool_space_url =
mempool_space_url.unwrap_or_else(|| DEFAULT_MEMPOOL_SPACE_URL.to_string());

Self {
client,
network,
Expand Down Expand Up @@ -139,10 +142,13 @@ impl FeeService {
.fee_rate
}
};

let sat_vkb = smart_fee.map_or(1000, |rate| rate.to_sat());
let sat_vb = sat_vkb / 1000;

tracing::debug!("Fee rate: {sat_vb} sat/vb");

tracing::debug!("Fee rate: {} sat/vb", sat_vkb / 1000);
Ok(sat_vkb / 1000)
Ok(sat_vb)
}

/// Bump TX fee via cpfp.
Expand Down
23 changes: 22 additions & 1 deletion crates/bitcoin-da/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ use tokio::sync::Mutex;
use tracing::{debug, error, info, instrument, trace, warn};

use crate::error::{BitcoinServiceError, MempoolRejection};
use crate::fee::{validate_txs_fee_rate, BumpFeeMethod, FeeService};
use crate::fee::{validate_txs_fee_rate, BumpFeeMethod, FeeService, DEFAULT_MAX_FEE_RATE_SAT_VB};
use crate::helpers::backup::backup_txs_to_file;
use crate::helpers::builders::body_builders::{create_inscription_transactions, DaTxs, RawTxData};
use crate::helpers::builders::TxWithId;
Expand Down Expand Up @@ -124,6 +124,9 @@ pub struct BitcoinServiceConfig {

/// Connection timeout for RPC in seconds
pub rpc_connect_timeout_secs: Option<u64>,

/// Max fee rate in sat/vb
pub max_fee_rate_sat_vb: Option<u64>,
}

impl citrea_common::FromEnv for BitcoinServiceConfig {
Expand All @@ -149,6 +152,9 @@ impl citrea_common::FromEnv for BitcoinServiceConfig {
rpc_connect_timeout_secs: read_env("BITCOIN_RPC_CONNECT_TIMEOUT_SECS")
.ok()
.and_then(|v| v.parse::<u64>().ok()),
max_fee_rate_sat_vb: read_env("BITCOIN_MAX_FEE_RATE_SAT_VB")
.ok()
.and_then(|v| v.parse::<u64>().ok()),
})
}
}
Expand All @@ -170,6 +176,7 @@ pub struct BitcoinService {
tx_queue: Arc<Mutex<VecDeque<SignedTxPair>>>,
pub(crate) tx_signer: TxSigner,
utxo_selection_mode: UtxoSelectionMode,
max_fee_rate_sat_vb: u64,
}

impl BitcoinService {
Expand All @@ -185,6 +192,7 @@ impl BitcoinService {
reveal_tx_prefix: Vec<u8>,
tx_backup_dir: PathBuf,
utxo_selection_mode: UtxoSelectionMode,
max_fee_rate_sat_vb: u64,
) -> Self {
Self {
tx_signer: TxSigner::new(client.clone()),
Expand All @@ -202,6 +210,7 @@ impl BitcoinService {
))),
tx_queue: Arc::new(Mutex::new(VecDeque::new())),
utxo_selection_mode,
max_fee_rate_sat_vb,
}
}

Expand Down Expand Up @@ -242,6 +251,9 @@ impl BitcoinService {
.map_err(|_| BitcoinServiceError::InvalidPrivateKey)?;

let utxo_selection_mode = config.utxo_selection_mode.clone().unwrap_or_default();
let max_fee_rate_sat_vb = config
.max_fee_rate_sat_vb
.unwrap_or(DEFAULT_MAX_FEE_RATE_SAT_VB);
Ok(Self::new(
client,
network,
Expand All @@ -253,6 +265,7 @@ impl BitcoinService {
chain_params.reveal_tx_prefix,
tx_backup_dir.to_path_buf(),
utxo_selection_mode,
max_fee_rate_sat_vb,
))
}

Expand Down Expand Up @@ -296,6 +309,14 @@ impl BitcoinService {
continue;
}
};

if fee_sat_per_vbyte > self.max_fee_rate_sat_vb {
warn!("Fee rate {} above cap of {}. Waiting before sending transaction", fee_sat_per_vbyte, self.max_fee_rate_sat_vb);
tokio::time::sleep(Duration::from_secs(10)).await;
continue;
}


match self
.send_transaction_with_fee_rate(
request.tx_request.clone(),
Expand Down
Loading