clementine_core/tx_sender/
rbf.rs

1use super::{log_error_for_tx, Result, SendTxError, TxMetadata, TxSender};
2use crate::builder::{self};
3use crate::utils::RbfSigningInfo;
4use bitcoin::script::Instruction;
5use bitcoin::sighash::{Prevouts, SighashCache};
6use bitcoin::taproot::{self};
7use bitcoin::{consensus, Address, Amount, FeeRate, Transaction};
8use bitcoin::{Psbt, TapSighashType, TxOut, Txid, Witness};
9use bitcoincore_rpc::json::{
10    BumpFeeOptions, BumpFeeResult, CreateRawTransactionInput, FinalizePsbtResult,
11    WalletCreateFundedPsbtOutput, WalletCreateFundedPsbtOutputs, WalletCreateFundedPsbtResult,
12};
13use bitcoincore_rpc::RpcApi;
14use eyre::Context;
15use eyre::{eyre, OptionExt};
16use std::str::FromStr;
17
18impl TxSender {
19    /// Calculates the appropriate fee rate for a Replace-By-Fee (RBF) transaction.
20    ///
21    /// This method determines the effective fee rate needed to successfully replace
22    /// an existing transaction in the mempool. It follows Bitcoin's RBF rules by:
23    ///
24    /// 1. Retrieving the original transaction and calculating its current fee rate
25    /// 2. Ensuring the new fee rate is higher than the original by at least the minimum
26    ///    required incremental relay fee
27    /// 3. Comparing the calculated minimum bump fee rate with the requested target fee rate
28    ///    and selecting the higher of the two
29    ///
30    /// # Arguments
31    /// * `txid` - The transaction ID of the original transaction to be replaced
32    /// * `new_feerate` - The target fee rate requested for the replacement transaction
33    ///
34    /// # Returns
35    /// * `Ok(Some(FeeRate))` - The effective fee rate (in satoshis per kilo-wu) to use for the replacement
36    /// * `Ok(None)` - If the original transaction already has a higher fee rate than requested
37    /// * `Err(...)` - If there was an error retrieving or analyzing the original transaction
38    pub async fn calculate_bump_feerate_if_needed(
39        &self,
40        txid: &Txid,
41        new_feerate: FeeRate,
42    ) -> Result<Option<FeeRate>> {
43        let original_tx = self.rpc.get_tx_of_txid(txid).await.map_err(|e| eyre!(e))?;
44
45        // Calculate original tx fee
46        let original_tx_fee = self.get_tx_fee(&original_tx).await.map_err(|e| eyre!(e))?;
47
48        //tracing::debug!("original_tx_fee: {}", original_tx_fee);
49
50        let original_tx_weight = original_tx.weight();
51
52        // Original fee rate calculation according to Bitcoin Core
53        // In Rust Bitcoin, the calculations are done in sat/kwu
54        // so some precision is lost. https://github.com/bitcoin/bitcoin/blob/a33bd767a37dccf39a094d03c2f62ea81633410f/src/policy/feerate.cpp#L11
55        let original_feerate_sat_per_kwu = FeeRate::from_sat_per_kwu(
56            (original_tx_fee.to_sat() * 1000) / (original_tx_weight.to_vbytes_ceil() * 4),
57        );
58
59        // If original feerate is already higher than target, avoid bumping
60        if original_feerate_sat_per_kwu >= new_feerate {
61            return Ok(None);
62        }
63
64        // Get minimum fee increment rate from node for BIP125 compliance. Returned value is in BTC/kvB
65        let incremental_fee_rate = self
66            .rpc
67            .get_network_info()
68            .await
69            .map_err(|e| eyre!(e))?
70            .incremental_fee;
71        let incremental_fee_rate_sat_per_kvb = incremental_fee_rate.to_sat();
72        let incremental_fee_rate = FeeRate::from_sat_per_kwu(incremental_fee_rate_sat_per_kvb / 4);
73
74        // Use max of target fee rate and original + minimum fee increment rate.
75        let min_bump_feerate =
76            original_feerate_sat_per_kwu.to_sat_per_kwu() + incremental_fee_rate.to_sat_per_kwu();
77
78        let effective_feerate_sat_per_kwu =
79            std::cmp::max(new_feerate.to_sat_per_kwu(), min_bump_feerate);
80
81        Ok(Some(FeeRate::from_sat_per_kwu(
82            effective_feerate_sat_per_kwu,
83        )))
84    }
85
86    pub async fn fill_in_utxo_info(&self, psbt: &mut String) -> Result<()> {
87        let mut decoded_psbt = Psbt::from_str(psbt).map_err(|e| eyre!(e))?;
88        let tx = decoded_psbt.unsigned_tx.clone();
89
90        for (idx, input) in tx.input.iter().enumerate() {
91            let utxo = self
92                .rpc
93                .get_tx_out(
94                    &input.previous_output.txid,
95                    input.previous_output.vout,
96                    Some(false),
97                )
98                .await
99                .wrap_err("Failed to get UTXO info")?;
100
101            if let Some(utxo) = utxo {
102                decoded_psbt.inputs[idx].witness_utxo = Some(TxOut {
103                    value: utxo.value,
104                    script_pubkey: utxo
105                        .script_pub_key
106                        .script()
107                        .wrap_err("Failed to get script pubkey")?,
108                });
109            }
110        }
111
112        *psbt = decoded_psbt.to_string();
113
114        Ok(())
115    }
116
117    /// Given a PSBT with inputs, fill in the existing witnesses from the original tx
118    /// This allows us to create a finalized PSBT if
119    /// the original tx had SinglePlusAnyoneCanPay signatures.  If the original
120    /// tx did not have S+AP, these signatures will be added. The expected behavior is for them to be replaced using RbfSigningInfo.
121    ///
122    /// # Returns
123    /// The PSBT as a base64-encoded string.
124    pub async fn copy_witnesses(&self, psbt: String, initial_tx: &Transaction) -> Result<String> {
125        let mut decoded_psbt = Psbt::from_str(&psbt).map_err(|e| eyre!(e))?;
126
127        for (idx, input) in initial_tx.input.iter().enumerate() {
128            if let Some(sig) = input.witness.nth(0) {
129                if sig.len() == 65 && sig[64] == 0x83 {
130                    // This is a S+AP signature, copy it over
131                    decoded_psbt.inputs[idx].final_script_witness = Some(input.witness.clone());
132                }
133            }
134        }
135
136        Ok(decoded_psbt.to_string())
137    }
138
139    pub async fn create_funded_psbt(
140        &self,
141        tx: &Transaction,
142        fee_rate: FeeRate,
143    ) -> Result<WalletCreateFundedPsbtResult> {
144        // We need to carefully calculate the witness weight and factor that
145        // into the fee rate because wallet_create_funded_psbt does not factor
146        // in witnesses.
147
148        // The scaleup factor is the ratio of the total weight to the base weight
149        // The walletcreatefundedpsbt will use the base weight to calculate the fee
150        // and we'll scale up the fee rate by the scaleup factor to achieve our desired fee
151        let witness_scaleup = tx.weight().to_wu() as f64 / (tx.base_size() * 4) as f64;
152
153        let adjusted_fee_rate = FeeRate::from_sat_per_kwu(
154            (fee_rate.to_sat_per_kwu() as f64 * witness_scaleup).ceil() as u64,
155        );
156
157        // 1. Create a funded PSBT using the wallet
158        let create_psbt_opts = bitcoincore_rpc::json::WalletCreateFundedPsbtOptions {
159            add_inputs: Some(true), // Let the wallet add its inputs
160            change_address: None,
161            change_position: Some(tx.output.len() as u16), // Add change output at last index (so that SinglePlusAnyoneCanPay signatures stay valid)
162            change_type: None,
163            include_watching: None,
164            lock_unspent: None,
165            // Bitcoincore expects BTC/kvbyte for fee_rate
166            fee_rate: Some(
167                adjusted_fee_rate
168                    .fee_vb(1000)
169                    .ok_or_eyre("Failed to convert fee rate to BTC/kvbyte")?,
170            ),
171            subtract_fee_from_outputs: vec![],
172            replaceable: Some(true), // Mark as RBF enabled
173            conf_target: None,
174            estimate_mode: None,
175        };
176
177        let mut omitted = 0usize;
178        let filtered_outputs: Vec<WalletCreateFundedPsbtOutput> = tx
179            .output
180            .iter()
181            .filter_map(|out| {
182                if out.script_pubkey.is_op_return() {
183                    if let Some(Ok(Instruction::PushBytes(data))) =
184                        out.script_pubkey.instructions().last()
185                    {
186                        return Some(WalletCreateFundedPsbtOutput::OpReturn(
187                            data.as_bytes().to_vec(),
188                        ));
189                    }
190                }
191                let address = Address::from_script(
192                    &out.script_pubkey,
193                    self.config.protocol_paramset().network,
194                )
195                .map_err(|e| eyre!(e));
196                match address {
197                    Ok(address) => Some(WalletCreateFundedPsbtOutput::Spendable(
198                        address.to_string(),
199                        out.value,
200                    )),
201                    Err(err) => {
202                        tracing::error!(
203                            "Failed to get address from script for output of tx with txid {} for script: {}",
204                            tx.compute_txid(),
205                            err
206                        );
207                        omitted += 1;
208                        None
209                    }
210                }
211            })
212            .collect::<Vec<_>>();
213
214        if omitted > 0 {
215            return Err(eyre::eyre!("Failed to get address for outputs of tx with txid {} for {} outputs in create_funded_psbt", tx.compute_txid(), omitted).into());
216        }
217
218        let outputs = WalletCreateFundedPsbtOutputs(filtered_outputs);
219
220        self.rpc
221            .wallet_create_funded_psbt(
222                &tx.input
223                    .iter()
224                    .map(|inp| CreateRawTransactionInput {
225                        txid: inp.previous_output.txid,
226                        vout: inp.previous_output.vout,
227                        sequence: Some(inp.sequence.to_consensus_u32()),
228                    })
229                    .collect::<Vec<_>>(),
230                outputs,
231                None,
232                Some(create_psbt_opts),
233                None,
234            )
235            .await
236            .map_err(|e| eyre!(e).into())
237    }
238    /// Given a PSBT with inputs that've been signed by the wallet except for our new input,
239    /// we have to sign the first input with our self.signer actor.
240    ///
241    /// Assumes that the first input is the input with our key.
242    ///
243    /// # Returns
244    /// The signed PSBT as a base64-encoded string.
245    pub async fn attempt_sign_psbt(
246        &self,
247        psbt: String,
248        rbf_signing_info: RbfSigningInfo,
249    ) -> Result<String> {
250        // Parse the PSBT from string
251        let mut decoded_psbt = Psbt::from_str(&psbt).map_err(|e| eyre!(e))?;
252
253        // Ensure we have inputs to sign
254        if decoded_psbt.inputs.is_empty() {
255            return Err(eyre!("PSBT has no inputs to sign").into());
256        }
257
258        let input_index = rbf_signing_info.vout as usize;
259
260        // Get the transaction to calculate the sighash
261        let tx = decoded_psbt.unsigned_tx.clone();
262        let mut sighash_cache = SighashCache::new(&tx);
263
264        // Determine the sighash type (default to ALL if not specified)
265        let sighash_type = decoded_psbt.inputs[input_index]
266            .sighash_type
267            .unwrap_or((TapSighashType::Default).into());
268
269        // For Taproot key path spending
270        if let Ok(tap_sighash_type) = sighash_type.taproot_hash_ty() {
271            // Calculate the sighash for this input
272            // Extract previous outputs from the PSBT
273            let prevouts: Vec<bitcoin::TxOut> = decoded_psbt
274                .inputs
275                .iter()
276                .map(|input| {
277                    input
278                        .witness_utxo
279                        .clone()
280                        .ok_or_eyre("expected inputs to be segwit")
281                        .map_err(SendTxError::Other)
282                })
283                .collect::<Result<Vec<_>>>()?;
284
285            let sighash = sighash_cache
286                .taproot_key_spend_signature_hash(
287                    input_index,
288                    &Prevouts::All(&prevouts),
289                    tap_sighash_type,
290                )
291                .map_err(|e| eyre!("Failed to calculate sighash: {}", e))?;
292
293            #[cfg(test)]
294            let mut sighash = sighash;
295
296            #[cfg(test)]
297            {
298                use bitcoin::sighash::Annex;
299                // This should provide the Sighash for the key spend
300                if let Some(ref annex_bytes) = rbf_signing_info.annex {
301                    let annex = Annex::new(annex_bytes).unwrap();
302                    sighash = sighash_cache
303                        .taproot_signature_hash(
304                            input_index,
305                            &Prevouts::All(&prevouts),
306                            Some(annex),
307                            None,
308                            tap_sighash_type,
309                        )
310                        .map_err(|e| eyre!("Failed to calculate sighash with annex: {}", e))?;
311                }
312            }
313
314            // Sign the sighash with our signer
315            let signature = self
316                .signer
317                .sign_with_tweak_data(
318                    sighash,
319                    builder::sighash::TapTweakData::KeyPath(rbf_signing_info.tweak_merkle_root),
320                    None,
321                )
322                .map_err(|e| eyre!("Failed to sign input: {}", e))?;
323
324            // Add the signature to the PSBT
325            decoded_psbt.inputs[input_index].tap_key_sig = Some(taproot::Signature {
326                signature,
327                sighash_type: tap_sighash_type,
328            });
329
330            decoded_psbt.inputs[input_index].final_script_witness =
331                Some(Witness::from_slice(&[signature.serialize()]));
332
333            #[cfg(test)]
334            {
335                if let Some(ref annex_bytes) = rbf_signing_info.annex {
336                    let mut witness = Witness::from_slice(&[signature.serialize()]);
337                    witness.push(annex_bytes);
338                    decoded_psbt.inputs[input_index].final_script_witness = Some(witness);
339                    tracing::info!("Decoded PSBT: {:?}", decoded_psbt);
340                }
341            }
342            // Serialize the signed PSBT back to base64
343            Ok(decoded_psbt.to_string())
344        } else {
345            Err(eyre!("Only Taproot key path signing is currently supported").into())
346        }
347    }
348
349    #[track_caller]
350    pub fn handle_err(
351        &self,
352        err_msg: impl AsRef<str>,
353        err_state: impl Into<String>,
354        try_to_send_id: u32,
355    ) {
356        log_error_for_tx!(self.db, try_to_send_id, err_msg.as_ref());
357
358        let err_state = err_state.into();
359        let db = self.db.clone();
360
361        tokio::spawn(async move {
362            let _ = db
363                .update_tx_debug_sending_state(try_to_send_id, &err_state, true)
364                .await;
365        });
366    }
367
368    /// This function verifies that the wallet has added a funding input to the
369    /// PSBT.
370    ///
371    /// This is required for a transaction to be added to the wallet.
372    pub fn verify_new_inputs(&self, psbt: &str, original_tx: &Transaction) -> bool {
373        let Ok(psbt) = Psbt::from_str(psbt) else {
374            tracing::error!("Failed to parse PSBT");
375            return false;
376        };
377
378        psbt.inputs.len() > original_tx.input.len()
379    }
380
381    pub async fn get_tx_fee(&self, tx: &Transaction) -> Result<Amount> {
382        let inputs = {
383            let mut inputs = Amount::ZERO;
384            for inp in &tx.input {
385                inputs += self
386                    .rpc
387                    .get_txout_from_outpoint(&inp.previous_output)
388                    .await
389                    .map_err(|e| eyre!(e))?
390                    .value;
391            }
392            inputs
393        };
394        let outputs = tx.output.iter().map(|o| o.value).sum::<Amount>();
395
396        let tx_fee = inputs - outputs;
397
398        Ok(tx_fee)
399    }
400
401    /// Sends or bumps a transaction using the Replace-By-Fee (RBF) strategy.
402    ///
403    /// It interacts with the database to track the latest RBF attempt (`last_rbf_txid`).
404    ///
405    /// # Logic:
406    /// 1.  **Check for Existing RBF Tx:** Retrieves `last_rbf_txid` for the `try_to_send_id`.
407    /// 2.  **Bump Existing Tx:** If `psbt_bump_fee` exists, it calls `rpc.psbt_bump_fee`.
408    ///     - This internally uses the Bitcoin Core `psbtbumpfee` RPC.
409    ///     - We then sign the inputs that we can using our Actor and have the wallet sign the rest.
410    ///
411    /// 3.  **Send Initial RBF Tx:** If no `last_rbf_txid` exists (first attempt):
412    ///     - It uses `fund_raw_transaction` RPC to let the wallet add (potentially) inputs,
413    ///       outputs, set the fee according to `fee_rate`, and mark the transaction as replaceable.
414    ///     - Uses `sign_raw_transaction_with_wallet` RPC to sign the funded transaction.
415    ///     - Uses `send_raw_transaction` RPC to broadcast the initial RBF transaction.
416    ///     - Saves the resulting `txid` to the database as the `last_rbf_txid`.
417    ///
418    /// # Arguments
419    /// * `try_to_send_id` - The database ID tracking this send attempt.
420    /// * `tx` - The original transaction intended for RBF (used only on the first attempt).
421    /// * `tx_metadata` - Optional metadata associated with the transaction.
422    /// * `fee_rate` - The target fee rate for the RBF replacement.
423    #[tracing::instrument(skip_all, fields(sender = self.btc_syncer_consumer_id, try_to_send_id, tx_meta=?tx_metadata))]
424    pub(super) async fn send_rbf_tx(
425        &self,
426        try_to_send_id: u32,
427        tx: Transaction,
428        tx_metadata: Option<TxMetadata>,
429        fee_rate: FeeRate,
430        rbf_signing_info: Option<RbfSigningInfo>,
431    ) -> Result<()> {
432        tracing::debug!(?tx_metadata, "Sending RBF tx",);
433
434        tracing::debug!(?try_to_send_id, "Attempting to send.");
435
436        let _ = self
437            .db
438            .update_tx_debug_sending_state(try_to_send_id, "preparing_rbf", true)
439            .await;
440
441        let mut dbtx = self
442            .db
443            .begin_transaction()
444            .await
445            .wrap_err("Failed to begin database transaction")?;
446
447        let last_rbf_txid = self
448            .db
449            .get_last_rbf_txid(Some(&mut dbtx), try_to_send_id)
450            .await
451            .wrap_err("Failed to get last RBF txid")?;
452
453        if let Some(last_rbf_txid) = last_rbf_txid {
454            tracing::debug!(
455                ?try_to_send_id,
456                "Attempting to bump fee for txid {last_rbf_txid} using psbt_bump_fee"
457            );
458
459            let effective_feerate = self
460                .calculate_bump_feerate_if_needed(&last_rbf_txid, fee_rate)
461                .await?;
462
463            let Some(effective_feerate) = effective_feerate else {
464                tracing::debug!(
465                    ?try_to_send_id,
466                    "Original tx feerate already higher than target ({} sat/vB), skipping bump",
467                    fee_rate.to_sat_per_vb_ceil()
468                );
469                return Ok(());
470            };
471
472            let psbt_bump_opts = BumpFeeOptions {
473                conf_target: None, // Use fee_rate instead
474                fee_rate: Some(bitcoincore_rpc::json::FeeRate::per_vbyte(Amount::from_sat(
475                    effective_feerate.to_sat_per_vb_ceil(),
476                ))),
477                replaceable: Some(true), // Ensure the bumped tx is also replaceable
478                estimate_mode: None,
479            };
480
481            let bump_result = self
482                .rpc
483                .psbt_bump_fee(&last_rbf_txid, Some(&psbt_bump_opts))
484                .await;
485
486            let bumped_psbt = match bump_result {
487                Err(e) => {
488                    // Check for common errors indicating the tx is already confirmed or spent
489                    let rpc_error_str = e.to_string();
490                    if rpc_error_str.contains("Transaction already in block chain") {
491                        tracing::debug!(
492                            ?try_to_send_id,
493                            "RBF bump failed for {last_rbf_txid}, likely confirmed or spent: {e}"
494                        );
495                        // No need to return error, just log and proceed
496                        dbtx.commit().await.wrap_err(
497                            "Failed to commit database transaction after failed bump check",
498                        )?;
499                        return Ok(());
500                    } else {
501                        // Other potentially transient errors
502                        let error_message = format!("psbt_bump_fee failed: {e}");
503                        log_error_for_tx!(self.db, try_to_send_id, error_message);
504                        let _ = self
505                            .db
506                            .update_tx_debug_sending_state(
507                                try_to_send_id,
508                                "rbf_psbt_bump_failed",
509                                true,
510                            )
511                            .await;
512                        tracing::warn!(?try_to_send_id, "psbt_bump_fee failed: {e:?}");
513                        return Err(SendTxError::Other(eyre!(e)));
514                    }
515                }
516                Ok(BumpFeeResult {
517                    psbt: Some(psbt), ..
518                }) => psbt,
519                Ok(BumpFeeResult { errors, .. }) if !errors.is_empty() => {
520                    self.handle_err(
521                        format!("psbt_bump_fee failed: {errors:?}"),
522                        "rbf_psbt_bump_failed",
523                        try_to_send_id,
524                    );
525                    return Err(SendTxError::Other(eyre!(errors.join(", "))));
526                }
527                Ok(BumpFeeResult { psbt: None, .. }) => {
528                    self.handle_err(
529                        "psbt_bump_fee returned no psbt",
530                        "rbf_psbt_bump_failed",
531                        try_to_send_id,
532                    );
533                    return Err(SendTxError::Other(eyre!("psbt_bump_fee returned no psbt")));
534                }
535            };
536
537            let bumped_psbt = self
538                .copy_witnesses(bumped_psbt, &tx)
539                .await
540                .wrap_err("Failed to fill SAP signatures")?;
541
542            // Wallet first pass
543            // We rely on the node's wallet here because psbt_bump_fee might add inputs from it.
544            let process_result = self
545                .rpc
546                .wallet_process_psbt(&bumped_psbt, Some(true), None, None) // sign=true
547                .await;
548
549            let processed_psbt = match process_result {
550                Ok(res) if res.complete => res.psbt,
551                // attempt to sign
552                Ok(res) => {
553                    let Some(rbf_signing_info) = rbf_signing_info else {
554                        return Err(eyre!(
555                            "RBF signing info is required for non SighashSingle RBF txs"
556                        )
557                        .into());
558                    };
559                    self.attempt_sign_psbt(res.psbt, rbf_signing_info).await?
560                }
561                Err(e) => {
562                    let err_msg = format!("wallet_process_psbt error: {e}");
563                    tracing::warn!(?try_to_send_id, "{}", err_msg);
564                    log_error_for_tx!(self.db, try_to_send_id, err_msg);
565                    let _ = self
566                        .db
567                        .update_tx_debug_sending_state(try_to_send_id, "rbf_psbt_sign_failed", true)
568                        .await;
569                    return Err(SendTxError::Other(eyre!(e)));
570                }
571            };
572
573            // Finalize the PSBT
574            let finalize_result = self
575                .rpc
576                .finalize_psbt(&processed_psbt, None) // extract=true by default
577                .await;
578
579            let final_tx_hex = match finalize_result {
580                Ok(FinalizePsbtResult {
581                    hex: Some(hex),
582                    complete: true,
583                    ..
584                }) => hex,
585                Ok(res) => {
586                    let err_msg = format!("Could not finalize PSBT: {res:?}");
587                    log_error_for_tx!(self.db, try_to_send_id, err_msg);
588
589                    let _ = self
590                        .db
591                        .update_tx_debug_sending_state(
592                            try_to_send_id,
593                            "rbf_psbt_finalize_incomplete",
594                            true,
595                        )
596                        .await;
597                    return Err(SendTxError::PsbtError(err_msg));
598                }
599                Err(e) => {
600                    log_error_for_tx!(
601                        self.db,
602                        try_to_send_id,
603                        format!("finalize_psbt error: {}", e)
604                    );
605                    let _ = self
606                        .db
607                        .update_tx_debug_sending_state(
608                            try_to_send_id,
609                            "rbf_psbt_finalize_failed",
610                            true,
611                        )
612                        .await;
613                    return Err(SendTxError::Other(eyre!(e)));
614                }
615            };
616
617            // Deserialize final tx to get txid
618            let final_tx: Transaction = match consensus::deserialize(&final_tx_hex) {
619                Ok(tx) => tx,
620                Err(e) => {
621                    log_error_for_tx!(
622                        self.db,
623                        try_to_send_id,
624                        format!("Failed to deserialize final RBF tx hex: {}", e)
625                    );
626                    return Err(SendTxError::Other(eyre!(e)));
627                }
628            };
629            let bumped_txid = final_tx.compute_txid();
630
631            // Broadcast the finalized transaction
632            let sent_txid = match self.rpc.send_raw_transaction(&final_tx).await {
633                Ok(sent_txid) if sent_txid == bumped_txid => sent_txid,
634                Ok(other_txid) => {
635                    log_error_for_tx!(
636                        self.db,
637                        try_to_send_id,
638                        format!(
639                            "send_raw_transaction returned unexpected txid {} (expected {})",
640                            other_txid, bumped_txid
641                        )
642                    );
643                    let _ = self
644                        .db
645                        .update_tx_debug_sending_state(
646                            try_to_send_id,
647                            "rbf_send_txid_mismatch",
648                            true,
649                        )
650                        .await;
651                    return Err(SendTxError::Other(eyre!(
652                        "send_raw_transaction returned unexpected txid"
653                    )));
654                }
655                Err(e) => {
656                    log_error_for_tx!(
657                        self.db,
658                        try_to_send_id,
659                        format!("send_raw_transaction error for bumped RBF tx: {}", e)
660                    );
661                    let _ = self
662                        .db
663                        .update_tx_debug_sending_state(try_to_send_id, "rbf_bump_send_failed", true)
664                        .await;
665                    return Err(SendTxError::Other(eyre!(e)));
666                }
667            };
668
669            tracing::debug!(
670                ?try_to_send_id,
671                "RBF tx {last_rbf_txid} successfully bumped and sent as {sent_txid}"
672            );
673
674            let _ = self
675                .db
676                .update_tx_debug_sending_state(try_to_send_id, "rbf_bumped_sent", true)
677                .await;
678
679            self.db
680                .save_rbf_txid(Some(&mut dbtx), try_to_send_id, sent_txid)
681                .await
682                .wrap_err("Failed to save new RBF txid after bump")?;
683        } else {
684            tracing::debug!(
685                ?try_to_send_id,
686                "Funding initial RBF tx using PSBT workflow"
687            );
688
689            let _ = self
690                .db
691                .update_tx_debug_sending_state(try_to_send_id, "creating_initial_rbf_psbt", true)
692                .await;
693
694            let create_result = self
695                .create_funded_psbt(&tx, fee_rate)
696                .await
697                .map_err(|err| {
698                    let err = eyre!(err).wrap_err("Failed to create funded PSBT");
699                    self.handle_err(format!("{err:?}"), "rbf_psbt_create_failed", try_to_send_id);
700
701                    err
702                })?;
703
704            if !self.verify_new_inputs(&create_result.psbt, &tx) {
705                tracing::warn!(
706                    ?try_to_send_id,
707                    "Transaction has not been funded and is being sent as is. This transaction will have to be manually bumped as the wallet will not add it to itself."
708                );
709            }
710
711            // replace locktime and version
712            let mut psbt = Psbt::from_str(&create_result.psbt).map_err(|e| eyre!(e))?;
713            psbt.unsigned_tx.lock_time = tx.lock_time;
714            psbt.unsigned_tx.version = tx.version;
715
716            tracing::debug!(
717                try_to_send_id,
718                "Successfully created initial RBF PSBT with fee {}",
719                create_result.fee
720            );
721
722            let mut psbt = psbt.to_string();
723
724            self.fill_in_utxo_info(&mut psbt).await.map_err(|err| {
725                let err = eyre!(err).wrap_err("Failed to fill in utxo info");
726                self.handle_err(
727                    format!("{err:?}"),
728                    "rbf_fill_in_utxo_info_failed",
729                    try_to_send_id,
730                );
731
732                err
733            })?;
734
735            psbt = self.copy_witnesses(psbt, &tx).await.map_err(|err| {
736                let err = eyre!(err).wrap_err("Failed to copy witnesses");
737                self.handle_err(
738                    format!("{err:?}"),
739                    "rbf_copy_witnesses_failed",
740                    try_to_send_id,
741                );
742
743                err
744            })?;
745
746            // 2. Process the PSBT (let the wallet sign its inputs)
747            let process_result = self
748                .rpc
749                .wallet_process_psbt(&psbt, Some(true), None, None)
750                .await
751                .map_err(|err| {
752                    let err = eyre!(err).wrap_err("Failed to process initial RBF PSBT");
753                    self.handle_err(
754                        format!("{err:?}"),
755                        "rbf_psbt_process_failed",
756                        try_to_send_id,
757                    );
758
759                    err
760                })?;
761
762            if let Some(rbf_signing_info) = rbf_signing_info {
763                psbt = self
764                    .attempt_sign_psbt(process_result.psbt, rbf_signing_info)
765                    .await
766                    .map_err(|err| {
767                        let err = eyre!(err).wrap_err("Failed to sign initial RBF PSBT");
768                        self.handle_err(format!("{err:?}"), "rbf_psbt_sign_failed", try_to_send_id);
769
770                        err
771                    })?;
772            } else {
773                psbt = process_result.psbt;
774            }
775
776            tracing::debug!(try_to_send_id, "Successfully processed initial RBF PSBT");
777
778            let final_tx = {
779                // Extract tx
780                let psbt = Psbt::from_str(&psbt).map_err(|e| eyre!(e)).map_err(|err| {
781                    let err = eyre!(err).wrap_err("Failed to deserialize initial RBF PSBT");
782                    self.handle_err(
783                        format!("{err:?}"),
784                        "rbf_psbt_deserialize_failed",
785                        try_to_send_id,
786                    );
787                    err
788                })?;
789
790                let mut tx = psbt.unsigned_tx.clone();
791
792                for (idx, input) in tx.input.iter_mut().enumerate() {
793                    if let Some(witness) = psbt.inputs[idx].final_script_witness.clone() {
794                        input.witness = witness;
795                    }
796                    if let Some(sig) = psbt.inputs[idx].final_script_sig.clone() {
797                        input.script_sig = sig;
798                    }
799                }
800
801                tx
802            };
803
804            let initial_txid = final_tx.compute_txid();
805
806            // 4. Broadcast the finalized transaction
807            let sent_txid = match self.rpc.send_raw_transaction(&final_tx).await {
808                Ok(sent_txid) => {
809                    if sent_txid != initial_txid {
810                        let err_msg = format!(
811                            "send_raw_transaction returned unexpected txid {sent_txid} (expected {initial_txid}) for initial RBF",
812                        );
813                        log_error_for_tx!(self.db, try_to_send_id, err_msg);
814                        let _ = self
815                            .db
816                            .update_tx_debug_sending_state(
817                                try_to_send_id,
818                                "rbf_initial_send_txid_mismatch",
819                                true,
820                            )
821                            .await;
822                        return Err(SendTxError::Other(eyre!(err_msg)));
823                    }
824                    tracing::debug!(
825                        try_to_send_id,
826                        "Successfully sent initial RBF tx with txid {sent_txid}"
827                    );
828                    sent_txid
829                }
830                Err(e) => {
831                    tracing::error!("RBF failed for: {:?}", final_tx);
832                    let err_msg = format!("send_raw_transaction error for initial RBF tx: {e}");
833                    log_error_for_tx!(self.db, try_to_send_id, err_msg);
834                    let _ = self
835                        .db
836                        .update_tx_debug_sending_state(
837                            try_to_send_id,
838                            "rbf_initial_send_failed",
839                            true,
840                        )
841                        .await;
842                    return Err(SendTxError::Other(eyre!(e)));
843                }
844            };
845
846            // Update debug sending state
847            let _ = self
848                .db
849                .update_tx_debug_sending_state(try_to_send_id, "rbf_initial_sent", true)
850                .await;
851
852            self.db
853                .save_rbf_txid(Some(&mut dbtx), try_to_send_id, sent_txid)
854                .await
855                .wrap_err("Failed to save initial RBF txid")?;
856        }
857
858        dbtx.commit()
859            .await
860            .wrap_err("Failed to commit database transaction")?;
861
862        Ok(())
863    }
864}
865
866#[cfg(test)]
867pub mod tests {
868    use super::super::tests::*;
869    use super::*;
870    use crate::actor::Actor;
871    use crate::builder::script::SpendPath;
872    use crate::builder::transaction::input::SpendableTxIn;
873    use crate::builder::transaction::output::UnspentTxOut;
874    use crate::builder::transaction::{
875        op_return_txout, TransactionType, TxHandlerBuilder, DEFAULT_SEQUENCE,
876    };
877    use crate::constants::{MIN_TAPROOT_AMOUNT, NON_STANDARD_V3};
878    use crate::errors::BridgeError;
879    use crate::extended_bitcoin_rpc::ExtendedBitcoinRpc;
880    use crate::rpc::clementine::tagged_signature::SignatureId;
881    use crate::rpc::clementine::{NormalSignatureKind, NumberedSignatureKind};
882    use crate::task::{IntoTask, TaskExt};
883    use crate::test::common::tx_utils::create_bg_tx_sender;
884    use crate::test::common::*;
885    use crate::utils::FeePayingType;
886    use bitcoin::hashes::Hash;
887    use bitcoin::transaction::Version;
888    use bitcoin::TxOut;
889    use bitcoincore_rpc::json::GetRawTransactionResult;
890    use std::result::Result;
891    use std::time::Duration;
892
893    pub async fn create_rbf_tx(
894        rpc: &ExtendedBitcoinRpc,
895        signer: &Actor,
896        network: bitcoin::Network,
897        requires_initial_funding: bool,
898    ) -> Result<Transaction, BridgeError> {
899        let (address, spend_info) =
900            builder::address::create_taproot_address(&[], Some(signer.xonly_public_key), network);
901
902        let amount = Amount::from_sat(100000);
903        let outpoint = rpc.send_to_address(&address, amount).await?;
904
905        rpc.mine_blocks(1).await?;
906
907        let version = Version::TWO;
908
909        let mut txhandler = TxHandlerBuilder::new(TransactionType::Dummy)
910            .with_version(version)
911            .add_input(
912                if !requires_initial_funding {
913                    SignatureId::from(NormalSignatureKind::Challenge)
914                } else {
915                    SignatureId::from((NumberedSignatureKind::WatchtowerChallenge, 0i32))
916                },
917                SpendableTxIn::new(
918                    outpoint,
919                    TxOut {
920                        value: amount,
921                        script_pubkey: address.script_pubkey(),
922                    },
923                    vec![],
924                    Some(spend_info),
925                ),
926                SpendPath::KeySpend,
927                DEFAULT_SEQUENCE,
928            )
929            .add_output(UnspentTxOut::from_partial(TxOut {
930                value: if requires_initial_funding {
931                    amount // do not add any fee if we want to test initial funding
932                } else {
933                    amount - MIN_TAPROOT_AMOUNT * 3
934                },
935                script_pubkey: address.script_pubkey(), // In practice, should be the wallet address, not the signer address
936            }))
937            .finalize();
938
939        signer
940            .tx_sign_and_fill_sigs(&mut txhandler, &[], None)
941            .unwrap();
942
943        let tx = txhandler.get_cached_tx().clone();
944        Ok(tx)
945    }
946
947    async fn create_challenge_tx(
948        rpc: &ExtendedBitcoinRpc,
949        signer: &Actor,
950        network: bitcoin::Network,
951    ) -> Result<Transaction, BridgeError> {
952        let (address, spend_info) =
953            builder::address::create_taproot_address(&[], Some(signer.xonly_public_key), network);
954
955        let amount = MIN_TAPROOT_AMOUNT;
956        let outpoint = rpc.send_to_address(&address, amount).await?;
957
958        rpc.mine_blocks(1).await?;
959
960        let version = NON_STANDARD_V3;
961
962        let mut txhandler = TxHandlerBuilder::new(TransactionType::Challenge)
963            .with_version(version)
964            .add_input(
965                SignatureId::from(NormalSignatureKind::Challenge),
966                SpendableTxIn::new(
967                    outpoint,
968                    TxOut {
969                        value: amount,
970                        script_pubkey: address.script_pubkey(),
971                    },
972                    vec![],
973                    Some(spend_info),
974                ),
975                SpendPath::KeySpend,
976                DEFAULT_SEQUENCE,
977            )
978            .add_output(UnspentTxOut::from_partial(TxOut {
979                value: Amount::from_btc(1.0).unwrap(),
980                script_pubkey: address.script_pubkey(), // In practice, should be the wallet address, not the signer address
981            }))
982            .add_output(UnspentTxOut::from_partial(op_return_txout(b"TEST")))
983            .finalize();
984
985        signer
986            .tx_sign_and_fill_sigs(&mut txhandler, &[], None)
987            .unwrap();
988
989        let tx = txhandler.get_cached_tx().clone();
990        Ok(tx)
991    }
992
993    #[tokio::test]
994    async fn test_send_challenge_tx() -> Result<(), BridgeError> {
995        // Initialize RPC, tx_sender and other components
996        let mut config = create_test_config_with_thread_name().await;
997        let rpc = create_regtest_rpc(&mut config).await;
998
999        let (tx_sender, btc_sender, rpc, db, signer, network) =
1000            create_tx_sender(rpc.rpc().clone()).await;
1001        let pair = btc_sender.into_task().cancelable_loop();
1002        pair.0.into_bg();
1003
1004        // Create a bumpable transaction
1005        let tx = create_challenge_tx(&rpc, &signer, network).await?;
1006
1007        // Insert the transaction into the database
1008        let mut dbtx = db.begin_transaction().await?;
1009        let try_to_send_id = tx_sender
1010            .client()
1011            .insert_try_to_send(
1012                &mut dbtx,
1013                None, // No metadata
1014                &tx,
1015                FeePayingType::RBF,
1016                None, // should not be resigning challenge tx
1017                &[],  // No cancel outpoints
1018                &[],  // No cancel txids
1019                &[],  // No activate txids
1020                &[],  // No activate outpoints
1021            )
1022            .await?;
1023        dbtx.commit().await?;
1024
1025        // Get the current fee rate and increase it for RBF
1026        let current_fee_rate = tx_sender.get_fee_rate().await?;
1027
1028        // Test send_rbf_tx
1029        tx_sender
1030            .send_rbf_tx(try_to_send_id, tx.clone(), None, current_fee_rate, None)
1031            .await
1032            .expect("RBF should succeed");
1033
1034        // Verify that the transaction was fee-bumped
1035        let tx_debug_info = tx_sender
1036            .client()
1037            .debug_tx(try_to_send_id)
1038            .await
1039            .expect("Transaction should be have debug info");
1040
1041        // Get the actual transaction from the mempool
1042        rpc.get_tx_of_txid(&bitcoin::Txid::from_byte_array(
1043            tx_debug_info.txid.unwrap().txid.try_into().unwrap(),
1044        ))
1045        .await
1046        .expect("Transaction should be in mempool");
1047
1048        Ok(())
1049    }
1050
1051    #[tokio::test]
1052    async fn test_send_rbf() -> Result<(), BridgeError> {
1053        // Initialize RPC, tx_sender and other components
1054        let mut config = create_test_config_with_thread_name().await;
1055        let rpc = create_regtest_rpc(&mut config).await;
1056
1057        let (tx_sender, btc_sender, rpc, db, signer, network) =
1058            create_tx_sender(rpc.rpc().clone()).await;
1059        let pair = btc_sender.into_task().cancelable_loop();
1060        pair.0.into_bg();
1061
1062        // Create a bumpable transaction
1063        let tx = create_rbf_tx(&rpc, &signer, network, false).await?;
1064
1065        // Insert the transaction into the database
1066        let mut dbtx = db.begin_transaction().await?;
1067        let try_to_send_id = tx_sender
1068            .client()
1069            .insert_try_to_send(
1070                &mut dbtx,
1071                None, // No metadata
1072                &tx,
1073                FeePayingType::RBF,
1074                Some(RbfSigningInfo {
1075                    vout: 0,
1076                    tweak_merkle_root: None,
1077                    #[cfg(test)]
1078                    annex: None,
1079                    #[cfg(test)]
1080                    additional_taproot_output_count: None,
1081                }),
1082                &[], // No cancel outpoints
1083                &[], // No cancel txids
1084                &[], // No activate txids
1085                &[], // No activate outpoints
1086            )
1087            .await?;
1088        dbtx.commit().await?;
1089
1090        // Get the current fee rate and increase it for RBF
1091        let current_fee_rate = tx_sender.get_fee_rate().await?;
1092
1093        // Test send_rbf_tx
1094        tx_sender
1095            .send_rbf_tx(
1096                try_to_send_id,
1097                tx.clone(),
1098                None,
1099                current_fee_rate,
1100                Some(RbfSigningInfo {
1101                    vout: 0,
1102                    tweak_merkle_root: None,
1103                    #[cfg(test)]
1104                    annex: None,
1105                    #[cfg(test)]
1106                    additional_taproot_output_count: None,
1107                }),
1108            )
1109            .await
1110            .expect("RBF should succeed");
1111
1112        // Verify that the transaction was fee-bumped
1113        let tx_debug_info = tx_sender
1114            .client()
1115            .debug_tx(try_to_send_id)
1116            .await
1117            .expect("Transaction should be have debug info");
1118
1119        // Get the actual transaction from the mempool
1120        rpc.get_tx_of_txid(&bitcoin::Txid::from_byte_array(
1121            tx_debug_info.txid.unwrap().txid.try_into().unwrap(),
1122        ))
1123        .await
1124        .expect("Transaction should be in mempool");
1125
1126        Ok(())
1127    }
1128
1129    #[tokio::test]
1130    async fn test_send_with_initial_funding_rbf() -> Result<(), BridgeError> {
1131        // Initialize RPC, tx_sender and other components
1132        let mut config = create_test_config_with_thread_name().await;
1133        let rpc = create_regtest_rpc(&mut config).await;
1134
1135        let (tx_sender, btc_sender, rpc, db, signer, network) =
1136            create_tx_sender(rpc.rpc().clone()).await;
1137        let pair = btc_sender.into_task().cancelable_loop();
1138        pair.0.into_bg();
1139
1140        // Create a bumpable transaction
1141        let tx = create_rbf_tx(&rpc, &signer, network, true).await?;
1142
1143        // Insert the transaction into the database
1144        let mut dbtx = db.begin_transaction().await?;
1145        let try_to_send_id = tx_sender
1146            .client()
1147            .insert_try_to_send(
1148                &mut dbtx,
1149                None, // No metadata
1150                &tx,
1151                FeePayingType::RBF,
1152                Some(RbfSigningInfo {
1153                    vout: 0,
1154                    tweak_merkle_root: None,
1155                    #[cfg(test)]
1156                    annex: None,
1157                    #[cfg(test)]
1158                    additional_taproot_output_count: None,
1159                }),
1160                &[], // No cancel outpoints
1161                &[], // No cancel txids
1162                &[], // No activate txids
1163                &[], // No activate outpoints
1164            )
1165            .await?;
1166        dbtx.commit().await?;
1167
1168        // Get the current fee rate and increase it for RBF
1169        let current_fee_rate = tx_sender.get_fee_rate().await?;
1170
1171        // Test send_rbf_tx
1172        tx_sender
1173            .send_rbf_tx(
1174                try_to_send_id,
1175                tx.clone(),
1176                None,
1177                current_fee_rate,
1178                Some(RbfSigningInfo {
1179                    vout: 0,
1180                    tweak_merkle_root: None,
1181                    #[cfg(test)]
1182                    annex: None,
1183                    #[cfg(test)]
1184                    additional_taproot_output_count: None,
1185                }),
1186            )
1187            .await
1188            .expect("RBF should succeed");
1189
1190        // Verify that the transaction was fee-bumped
1191        let tx_debug_info = tx_sender
1192            .client()
1193            .debug_tx(try_to_send_id)
1194            .await
1195            .expect("Transaction should have debug info");
1196
1197        // Get the actual transaction from the mempool
1198        let tx = rpc
1199            .get_tx_of_txid(&bitcoin::Txid::from_byte_array(
1200                tx_debug_info.txid.unwrap().txid.try_into().unwrap(),
1201            ))
1202            .await
1203            .expect("Transaction should be in mempool");
1204
1205        // Check that the transaction has new input
1206        assert_eq!(tx.input.len(), 2);
1207
1208        Ok(())
1209    }
1210
1211    #[tokio::test]
1212    async fn test_send_without_info_rbf() -> Result<(), BridgeError> {
1213        // This is the case with no initial funding required, corresponding to the Challenge transaction.
1214
1215        // Initialize RPC, tx_sender and other components
1216        let mut config = create_test_config_with_thread_name().await;
1217        let rpc = create_regtest_rpc(&mut config).await;
1218
1219        let (tx_sender, btc_sender, rpc, db, signer, network) =
1220            create_tx_sender(rpc.rpc().clone()).await;
1221        let pair = btc_sender.into_task().cancelable_loop();
1222        pair.0.into_bg();
1223
1224        // Create a bumpable transaction
1225        let tx = create_rbf_tx(&rpc, &signer, network, false).await?;
1226
1227        // Insert the transaction into the database
1228        let mut dbtx = db.begin_transaction().await?;
1229        let try_to_send_id = tx_sender
1230            .client()
1231            .insert_try_to_send(
1232                &mut dbtx,
1233                None, // No metadata
1234                &tx,
1235                FeePayingType::RBF,
1236                None,
1237                &[], // No cancel outpoints
1238                &[], // No cancel txids
1239                &[], // No activate txids
1240                &[], // No activate outpoints
1241            )
1242            .await?;
1243        dbtx.commit().await?;
1244
1245        // Get the current fee rate and increase it for RBF
1246        let current_fee_rate = tx_sender.get_fee_rate().await?;
1247
1248        // Test send_rbf_tx
1249        tx_sender
1250            .send_rbf_tx(try_to_send_id, tx.clone(), None, current_fee_rate, None)
1251            .await
1252            .expect("RBF should succeed");
1253
1254        // Verify that the transaction was fee-bumped
1255        let tx_debug_info = tx_sender
1256            .client()
1257            .debug_tx(try_to_send_id)
1258            .await
1259            .expect("Transaction should be have debug info");
1260
1261        // Get the actual transaction from the mempool
1262        rpc.get_tx_of_txid(&bitcoin::Txid::from_byte_array(
1263            tx_debug_info.txid.unwrap().txid.try_into().unwrap(),
1264        ))
1265        .await
1266        .expect("Transaction should be in mempool");
1267
1268        Ok(())
1269    }
1270
1271    #[tokio::test]
1272    // #[ignore = "unable to bump right now due to psbtbumpfee not accepting out-of-wallet"]
1273    async fn test_bump_rbf_after_sent() -> Result<(), BridgeError> {
1274        // Initialize RPC, tx_sender and other components
1275        let mut config = create_test_config_with_thread_name().await;
1276        let rpc = create_regtest_rpc(&mut config).await;
1277
1278        let (tx_sender, btc_sender, rpc, db, signer, network) =
1279            create_tx_sender(rpc.rpc().clone()).await;
1280        let pair = btc_sender.into_task().cancelable_loop();
1281        pair.0.into_bg();
1282
1283        // Create a bumpable transaction
1284        let tx = create_rbf_tx(&rpc, &signer, network, true).await?;
1285
1286        // Insert the transaction into the database
1287        let mut dbtx = db.begin_transaction().await?;
1288        let try_to_send_id = tx_sender
1289            .client()
1290            .insert_try_to_send(
1291                &mut dbtx,
1292                None, // No metadata
1293                &tx,
1294                FeePayingType::RBF,
1295                None,
1296                &[], // No cancel outpoints
1297                &[], // No cancel txids
1298                &[], // No activate txids
1299                &[], // No activate outpoints
1300            )
1301            .await?;
1302        dbtx.commit().await?;
1303
1304        let current_fee_rate = tx_sender.get_fee_rate().await?;
1305
1306        // Create initial TX
1307        tx_sender
1308            .send_rbf_tx(
1309                try_to_send_id,
1310                tx.clone(),
1311                None,
1312                current_fee_rate,
1313                Some(RbfSigningInfo {
1314                    vout: 0,
1315                    tweak_merkle_root: None,
1316                    #[cfg(test)]
1317                    annex: None,
1318                    #[cfg(test)]
1319                    additional_taproot_output_count: None,
1320                }),
1321            )
1322            .await
1323            .expect("RBF should succeed");
1324
1325        // Verify that the transaction was saved in db
1326        let tx_debug_info = tx_sender
1327            .client()
1328            .debug_tx(try_to_send_id)
1329            .await
1330            .expect("Transaction should be have debug info");
1331
1332        // Verify that TX is in mempool
1333        let initial_txid = tx_debug_info.txid.unwrap().txid;
1334        rpc.get_tx_of_txid(&bitcoin::Txid::from_byte_array(
1335            initial_txid.clone().try_into().unwrap(),
1336        ))
1337        .await
1338        .expect("Transaction should be in mempool");
1339
1340        // Increase fee rate
1341        let higher_fee_rate = current_fee_rate.checked_mul(2).unwrap();
1342
1343        tokio::time::sleep(Duration::from_secs(1)).await;
1344
1345        // try to send tx with a bumped fee.
1346        tx_sender
1347            .send_rbf_tx(
1348                try_to_send_id,
1349                tx.clone(),
1350                None,
1351                higher_fee_rate,
1352                Some(RbfSigningInfo {
1353                    vout: 0,
1354                    tweak_merkle_root: None,
1355                    #[cfg(test)]
1356                    annex: None,
1357                    #[cfg(test)]
1358                    additional_taproot_output_count: None,
1359                }),
1360            )
1361            .await
1362            .expect("RBF should succeed");
1363
1364        // Verify that the transaction was saved in db
1365        let tx_debug_info = tx_sender
1366            .client()
1367            .debug_tx(try_to_send_id)
1368            .await
1369            .expect("Transaction should be have debug info");
1370
1371        // Verify that TX is in mempool
1372        let changed_txid = tx_debug_info.txid.unwrap().txid;
1373        rpc.get_tx_of_txid(&bitcoin::Txid::from_byte_array(
1374            changed_txid.clone().try_into().unwrap(),
1375        ))
1376        .await
1377        .expect("Transaction should be in mempool");
1378
1379        // Verify that tx has changed.
1380        assert_ne!(
1381            changed_txid, initial_txid,
1382            "Transaction should have been bumped"
1383        );
1384
1385        Ok(())
1386    }
1387
1388    #[tokio::test]
1389    async fn test_bg_send_rbf() -> Result<(), BridgeError> {
1390        let mut config = create_test_config_with_thread_name().await;
1391        let regtest = create_regtest_rpc(&mut config).await;
1392        let rpc = regtest.rpc().clone();
1393
1394        rpc.mine_blocks(1).await.unwrap();
1395
1396        let (client, _tx_sender, _cancel_txs, rpc, db, signer, network) =
1397            create_bg_tx_sender(config).await;
1398
1399        let tx = create_rbf_tx(&rpc, &signer, network, false).await.unwrap();
1400
1401        let mut dbtx = db.begin_transaction().await.unwrap();
1402        client
1403            .insert_try_to_send(
1404                &mut dbtx,
1405                None,
1406                &tx,
1407                FeePayingType::RBF,
1408                Some(RbfSigningInfo {
1409                    vout: 0,
1410                    tweak_merkle_root: None,
1411                    #[cfg(test)]
1412                    annex: None,
1413                    #[cfg(test)]
1414                    additional_taproot_output_count: None,
1415                }),
1416                &[],
1417                &[],
1418                &[],
1419                &[],
1420            )
1421            .await
1422            .unwrap();
1423        dbtx.commit().await.unwrap();
1424
1425        poll_until_condition(
1426            async || {
1427                rpc.mine_blocks(1).await.unwrap();
1428
1429                let tx_result = rpc.get_raw_transaction_info(&tx.compute_txid(), None).await;
1430
1431                Ok(matches!(tx_result, Ok(GetRawTransactionResult {
1432                    confirmations: Some(confirmations),
1433                    ..
1434                }) if confirmations > 0))
1435            },
1436            Some(Duration::from_secs(30)),
1437            Some(Duration::from_millis(100)),
1438        )
1439        .await
1440        .expect("Tx was not confirmed in time");
1441
1442        Ok(())
1443    }
1444}