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 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 let original_tx_fee = self.get_tx_fee(&original_tx).await.map_err(|e| eyre!(e))?;
47
48 let original_tx_weight = original_tx.weight();
51
52 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_sat_per_kwu >= new_feerate {
61 return Ok(None);
62 }
63
64 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 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 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 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 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 let create_psbt_opts = bitcoincore_rpc::json::WalletCreateFundedPsbtOptions {
159 add_inputs: Some(true), change_address: None,
161 change_position: Some(tx.output.len() as u16), change_type: None,
163 include_watching: None,
164 lock_unspent: None,
165 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), 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 pub async fn attempt_sign_psbt(
246 &self,
247 psbt: String,
248 rbf_signing_info: RbfSigningInfo,
249 ) -> Result<String> {
250 let mut decoded_psbt = Psbt::from_str(&psbt).map_err(|e| eyre!(e))?;
252
253 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 let tx = decoded_psbt.unsigned_tx.clone();
262 let mut sighash_cache = SighashCache::new(&tx);
263
264 let sighash_type = decoded_psbt.inputs[input_index]
266 .sighash_type
267 .unwrap_or((TapSighashType::Default).into());
268
269 if let Ok(tap_sighash_type) = sighash_type.taproot_hash_ty() {
271 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 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 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 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 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 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 #[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, 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), 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 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 dbtx.commit().await.wrap_err(
497 "Failed to commit database transaction after failed bump check",
498 )?;
499 return Ok(());
500 } else {
501 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 let process_result = self
545 .rpc
546 .wallet_process_psbt(&bumped_psbt, Some(true), None, None) .await;
548
549 let processed_psbt = match process_result {
550 Ok(res) if res.complete => res.psbt,
551 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 let finalize_result = self
575 .rpc
576 .finalize_psbt(&processed_psbt, None) .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 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 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 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 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 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 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 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 } else {
933 amount - MIN_TAPROOT_AMOUNT * 3
934 },
935 script_pubkey: address.script_pubkey(), }))
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(), }))
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 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 let tx = create_challenge_tx(&rpc, &signer, network).await?;
1006
1007 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, &tx,
1015 FeePayingType::RBF,
1016 None, &[], &[], &[], &[], )
1022 .await?;
1023 dbtx.commit().await?;
1024
1025 let current_fee_rate = tx_sender.get_fee_rate().await?;
1027
1028 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 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 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 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 let tx = create_rbf_tx(&rpc, &signer, network, false).await?;
1064
1065 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, &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 &[], &[], &[], &[], )
1087 .await?;
1088 dbtx.commit().await?;
1089
1090 let current_fee_rate = tx_sender.get_fee_rate().await?;
1092
1093 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 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 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 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 let tx = create_rbf_tx(&rpc, &signer, network, true).await?;
1142
1143 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, &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 &[], &[], &[], &[], )
1165 .await?;
1166 dbtx.commit().await?;
1167
1168 let current_fee_rate = tx_sender.get_fee_rate().await?;
1170
1171 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 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 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 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 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 let tx = create_rbf_tx(&rpc, &signer, network, false).await?;
1226
1227 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, &tx,
1235 FeePayingType::RBF,
1236 None,
1237 &[], &[], &[], &[], )
1242 .await?;
1243 dbtx.commit().await?;
1244
1245 let current_fee_rate = tx_sender.get_fee_rate().await?;
1247
1248 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 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 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 async fn test_bump_rbf_after_sent() -> Result<(), BridgeError> {
1274 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 let tx = create_rbf_tx(&rpc, &signer, network, true).await?;
1285
1286 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, &tx,
1294 FeePayingType::RBF,
1295 None,
1296 &[], &[], &[], &[], )
1301 .await?;
1302 dbtx.commit().await?;
1303
1304 let current_fee_rate = tx_sender.get_fee_rate().await?;
1305
1306 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 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 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 let higher_fee_rate = current_fee_rate.checked_mul(2).unwrap();
1342
1343 tokio::time::sleep(Duration::from_secs(1)).await;
1344
1345 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 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 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 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}