1use crate::{log_error_for_tx, TxSender};
2use bitcoin::absolute::{LockTime, LOCK_TIME_THRESHOLD};
3use bitcoin::hashes::Hash;
4use bitcoin::script::Instruction;
5use bitcoin::sighash::{Prevouts, SighashCache};
6use bitcoin::taproot::{self, LeafVersion};
7use bitcoin::{Address, Amount, ScriptBuf, TapLeafHash, Transaction};
8use bitcoin::{Psbt, TxOut, Txid, Witness};
9use bitcoincore_rpc::json::{
10 BumpFeeOptions, BumpFeeResult, CreateRawTransactionInput, WalletCreateFundedPsbtOutput,
11 WalletCreateFundedPsbtOutputs, WalletCreateFundedPsbtResult,
12};
13use bitcoincore_rpc::RpcApi;
14use clementine_config::NON_EPHEMERAL_ANCHOR_AMOUNT;
15use clementine_errors::SendTxError;
16use clementine_primitives::FeeRateKvb;
17use clementine_utils::sign::TapTweakData;
18use clementine_utils::{RbfSigningInfo, RbfSigningSpendPath, TxMetadata};
19use eyre::Context;
20use eyre::{eyre, OptionExt};
21use std::str::FromStr;
22
23use super::Result;
24
25#[cfg(feature = "testing")]
27pub const REVEAL_TX_PREFIX: &[u8] = &[2];
28#[cfg(not(feature = "testing"))]
29pub const REVEAL_TX_PREFIX: &[u8] = &[2, 2];
30
31impl TxSender {
32 pub async fn calculate_bump_feerate_if_needed(
52 &self,
53 txid: &Txid,
54 new_feerate: FeeRateKvb,
55 ) -> Result<Option<FeeRateKvb>> {
56 let original_tx = self.rpc.get_tx_of_txid(txid).await.map_err(|e| eyre!(e))?;
57
58 let original_tx_fee = self.get_tx_fee(&original_tx).await.map_err(|e| eyre!(e))?;
60
61 let original_tx_weight = original_tx.weight();
62
63 let original_feerate_sat_per_kvb = FeeRateKvb::from_sat_per_kvb(
66 original_tx_fee
67 .to_sat()
68 .saturating_mul(1000)
69 .div_ceil(original_tx_weight.to_vbytes_ceil() as u64),
70 );
71
72 if original_feerate_sat_per_kvb >= new_feerate {
74 return Ok(None);
75 }
76
77 let incremental_fee_rate = self
79 .rpc
80 .get_network_info()
81 .await
82 .map_err(|e| eyre!(e))?
83 .incremental_fee;
84 let incremental_fee_rate_sat_per_kvb = incremental_fee_rate.to_sat();
85 let incremental_fee_rate = FeeRateKvb::from_sat_per_kvb(incremental_fee_rate_sat_per_kvb);
86
87 let min_bump_feerate =
89 original_feerate_sat_per_kvb.to_sat_per_kvb() + incremental_fee_rate.to_sat_per_kvb();
90
91 let effective_feerate_sat_per_kvb =
92 std::cmp::max(new_feerate.to_sat_per_kvb(), min_bump_feerate);
93
94 Ok(Some(FeeRateKvb::from_sat_per_kvb(
95 effective_feerate_sat_per_kvb,
96 )))
97 }
98
99 pub async fn fill_in_utxo_info(&self, psbt: &mut String) -> Result<()> {
100 let mut decoded_psbt = Psbt::from_str(psbt).map_err(|e| eyre!(e))?;
101 let tx = decoded_psbt.unsigned_tx.clone();
102
103 for (idx, input) in tx.input.iter().enumerate() {
104 let utxo = self
105 .rpc
106 .get_tx_out(
107 &input.previous_output.txid,
108 input.previous_output.vout,
109 Some(false),
110 )
111 .await
112 .wrap_err("Failed to get UTXO info")?;
113
114 if let Some(utxo) = utxo {
115 decoded_psbt.inputs[idx].witness_utxo = Some(TxOut {
116 value: utxo.value,
117 script_pubkey: utxo
118 .script_pub_key
119 .script()
120 .wrap_err("Failed to get script pubkey")?,
121 });
122 }
123 }
124
125 *psbt = decoded_psbt.to_string();
126
127 Ok(())
128 }
129
130 pub async fn copy_witnesses(&self, psbt: String, initial_tx: &Transaction) -> Result<String> {
138 let mut decoded_psbt = Psbt::from_str(&psbt).map_err(|e| eyre!(e))?;
139
140 for (idx, input) in initial_tx.input.iter().enumerate() {
141 if let Some(sig) = input.witness.nth(0) {
142 if sig.len() == 65 && sig[64] == 0x83 {
143 decoded_psbt.inputs[idx].final_script_witness = Some(input.witness.clone());
145 }
146 }
147 }
148
149 Ok(decoded_psbt.to_string())
150 }
151
152 pub async fn create_funded_psbt(
153 &self,
154 tx: &Transaction,
155 fee_rate: FeeRateKvb,
156 ) -> Result<WalletCreateFundedPsbtResult> {
157 let create_psbt_opts = bitcoincore_rpc::json::WalletCreateFundedPsbtOptions {
159 add_inputs: Some(true), include_unsafe: Some(self.include_unsafe),
161 change_address: None,
162 change_position: Some(tx.output.len() as u16), change_type: None,
164 include_watching: None,
165 lock_unspent: None,
166 fee_rate: Some(
168 fee_rate
169 .fee_vb(1000)
170 .ok_or_eyre("Failed to convert fee rate to BTC/kvbyte")?,
171 ),
172 subtract_fee_from_outputs: vec![],
173 replaceable: Some(true), conf_target: None,
175 estimate_mode: None,
176 };
177
178 let mut omitted = 0usize;
179 let filtered_outputs: Vec<WalletCreateFundedPsbtOutput> = tx
180 .output
181 .iter()
182 .filter_map(|out| {
183 if out.script_pubkey.is_op_return() {
184 if let Some(Ok(Instruction::PushBytes(data))) =
185 out.script_pubkey.instructions().last()
186 {
187 return Some(WalletCreateFundedPsbtOutput::OpReturn(
188 data.as_bytes().to_vec(),
189 ));
190 }
191 }
192 let address = Address::from_script(
193 &out.script_pubkey,
194 self.network,
195 )
196 .map_err(|e| eyre!(e));
197 match address {
198 Ok(address) => Some(WalletCreateFundedPsbtOutput::Spendable(
199 address.to_string(),
200 out.value,
201 )),
202 Err(err) => {
203 tracing::error!(
204 "Failed to get address from script for output of tx with txid {} for script: {}",
205 tx.compute_txid(),
206 err
207 );
208 omitted += 1;
209 None
210 }
211 }
212 })
213 .collect::<Vec<_>>();
214
215 if omitted > 0 {
216 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());
217 }
218
219 let outputs = WalletCreateFundedPsbtOutputs(filtered_outputs);
220
221 self.rpc
222 .wallet_create_funded_psbt(
223 &tx.input
224 .iter()
225 .map(|inp| CreateRawTransactionInput {
226 txid: inp.previous_output.txid,
227 vout: inp.previous_output.vout,
228 sequence: Some(inp.sequence.to_consensus_u32()),
229 weight: if inp.witness.is_empty() {
231 None
232 } else {
233 Some(inp.segwit_weight().to_wu())
234 },
235 })
236 .collect::<Vec<_>>(),
237 outputs,
238 None,
239 Some(create_psbt_opts),
240 None,
241 )
242 .await
243 .map_err(|e| eyre!(e).into())
244 }
245 pub async fn attempt_sign_psbt(
256 &self,
257 psbt: String,
258 rbf_signing_info: &RbfSigningInfo,
259 cached_leaf_hash: Option<TapLeafHash>,
260 ) -> Result<String> {
261 let mut decoded_psbt = Psbt::from_str(&psbt).map_err(|e| eyre!(e))?;
263
264 if decoded_psbt.inputs.is_empty() {
266 return Err(eyre!("PSBT has no inputs to sign").into());
267 }
268
269 let input_index = rbf_signing_info.vout as usize;
270
271 let tx = decoded_psbt.unsigned_tx.clone();
273 let mut sighash_cache = SighashCache::new(&tx);
274
275 let tap_sighash_type = rbf_signing_info.tap_sighash_type;
276
277 let prevouts: Vec<bitcoin::TxOut> = decoded_psbt
280 .inputs
281 .iter()
282 .zip(tx.input.iter())
283 .map(|(psbt_input, tx_input)| {
284 if let Some(witness_utxo) = psbt_input.witness_utxo.clone() {
286 Ok(witness_utxo)
287 } else if let Some(ref non_witness_tx) = psbt_input.non_witness_utxo {
288 let vout = tx_input.previous_output.vout as usize;
290 non_witness_tx
291 .output
292 .get(vout)
293 .cloned()
294 .ok_or_eyre(format!(
295 "Output index {vout} out of bounds in previous transaction",
296 ))
297 .map_err(SendTxError::Other)
298 } else {
299 Err(eyre!(
300 "Neither witness_utxo nor non_witness_utxo found for input"
301 ))
302 .map_err(SendTxError::Other)
303 }
304 })
305 .collect::<Result<Vec<_>>>()?;
306
307 let sighash = match &rbf_signing_info.spend_path {
308 RbfSigningSpendPath::KeyPath { .. } => sighash_cache
309 .taproot_key_spend_signature_hash(
310 input_index,
311 &Prevouts::All(&prevouts),
312 tap_sighash_type,
313 )
314 .map_err(|e| eyre!("Failed to calculate sighash: {}", e))?,
315 RbfSigningSpendPath::ScriptPath { .. } => sighash_cache
316 .taproot_script_spend_signature_hash(
317 input_index,
318 &Prevouts::All(&prevouts),
319 match cached_leaf_hash {
320 Some(leaf_hash) => leaf_hash,
321 None => {
322 return Err(eyre!(
323 "Cached leaf hash expected but not found for RBF script spend"
324 )
325 .into())
326 }
327 },
328 tap_sighash_type,
329 )
330 .map_err(|e| eyre!("Failed to calculate sighash: {}", e))?,
331 };
332
333 #[cfg(feature = "testing")]
334 let mut sighash = sighash;
335
336 #[cfg(feature = "testing")]
337 {
338 use bitcoin::sighash::Annex;
339 if let Some(ref annex_bytes) = rbf_signing_info.annex {
341 if let RbfSigningSpendPath::ScriptPath { .. } = &rbf_signing_info.spend_path {
342 return Err(eyre!("Script path RBF signing with annex not supported").into());
343 }
344 let annex = Annex::new(annex_bytes).unwrap();
345 sighash = sighash_cache
346 .taproot_signature_hash(
347 input_index,
348 &Prevouts::All(&prevouts),
349 Some(annex),
350 None,
351 tap_sighash_type,
352 )
353 .map_err(|e| eyre!("Failed to calculate sighash with annex: {}", e))?;
354 }
355 }
356
357 let tweak_data = match &rbf_signing_info.spend_path {
359 RbfSigningSpendPath::KeyPath { tweak_merkle_root } => {
360 TapTweakData::KeyPath(*tweak_merkle_root)
361 }
362 RbfSigningSpendPath::ScriptPath { .. } => TapTweakData::ScriptPath,
363 };
364
365 let signature = self
366 .signer
367 .sign_with_tweak_data(sighash, tweak_data)
368 .map_err(|e| eyre!("Failed to sign input: {}", e))?;
369
370 let mut witness = Witness::new();
371 let taproot_signature = taproot::Signature {
372 signature,
373 sighash_type: tap_sighash_type,
374 };
375
376 match &rbf_signing_info.spend_path {
377 RbfSigningSpendPath::KeyPath { .. } => {
378 witness.push(taproot_signature.serialize());
379 decoded_psbt.inputs[input_index].tap_key_sig = Some(taproot_signature);
381 }
382 RbfSigningSpendPath::ScriptPath {
383 control_block,
384 script,
385 } => {
386 witness.push(taproot_signature.serialize());
387 witness.push(script.clone());
388 witness.push(control_block.clone());
389 }
390 }
391
392 #[cfg(feature = "testing")]
393 {
394 if let Some(ref annex_bytes) = rbf_signing_info.annex {
395 witness.push(annex_bytes);
396 tracing::info!("Decoded PSBT: {:?}", decoded_psbt);
397 }
398 }
399 decoded_psbt.inputs[input_index].final_script_witness = Some(witness);
400 Ok(decoded_psbt.to_string())
402 }
403
404 #[track_caller]
405 pub fn handle_err(
406 &self,
407 err_msg: impl AsRef<str>,
408 err_state: impl Into<String>,
409 try_to_send_id: u32,
410 ) {
411 log_error_for_tx!(self.db, try_to_send_id, err_msg.as_ref());
412
413 let err_state = err_state.into();
414 let db = self.db.clone();
415
416 tokio::spawn(async move {
417 let _ = db
418 .update_tx_debug_sending_state(try_to_send_id, &err_state, true)
419 .await;
420 });
421 }
422
423 pub fn verify_new_inputs(&self, psbt: &str, original_tx: &Transaction) -> bool {
428 let Ok(psbt) = Psbt::from_str(psbt) else {
429 tracing::error!("Failed to parse PSBT");
430 return false;
431 };
432
433 psbt.inputs.len() > original_tx.input.len()
434 }
435
436 pub fn reorder_psbt_outputs(&self, psbt: &mut Psbt, original_tx: &Transaction) -> Result<()> {
442 if psbt.unsigned_tx.output.len() != psbt.outputs.len() {
443 return Err(SendTxError::Other(eyre!(
444 "PSBT outputs length mismatch: unsigned_tx outputs={} psbt outputs={}",
445 psbt.unsigned_tx.output.len(),
446 psbt.outputs.len()
447 )));
448 }
449
450 let mut used = vec![false; psbt.unsigned_tx.output.len()];
451 let mut new_outputs = Vec::with_capacity(psbt.unsigned_tx.output.len());
452 let mut new_psbt_outputs = Vec::with_capacity(psbt.outputs.len());
453
454 for original_out in &original_tx.output {
455 let mut found_idx = None;
456 for (idx, out) in psbt.unsigned_tx.output.iter().enumerate() {
457 if !used[idx]
458 && out.value == original_out.value
459 && out.script_pubkey == original_out.script_pubkey
460 {
461 found_idx = Some(idx);
462 break;
463 }
464 }
465
466 let Some(idx) = found_idx else {
467 return Err(SendTxError::Other(eyre!(
468 "Failed to find original output in PSBT"
469 )));
470 };
471
472 used[idx] = true;
473 new_outputs.push(psbt.unsigned_tx.output[idx].clone());
474 new_psbt_outputs.push(psbt.outputs[idx].clone());
475 }
476
477 for (idx, out) in psbt.unsigned_tx.output.iter().enumerate() {
478 if !used[idx] {
479 new_outputs.push(out.clone());
480 new_psbt_outputs.push(psbt.outputs[idx].clone());
481 }
482 }
483
484 psbt.unsigned_tx.output = new_outputs;
485 psbt.outputs = new_psbt_outputs;
486
487 Ok(())
488 }
489
490 fn extract_final_tx_from_psbt(psbt: &str) -> Result<Transaction> {
491 let psbt = Psbt::from_str(psbt).map_err(|e| eyre!(e))?;
492 if psbt.inputs.len() != psbt.unsigned_tx.input.len() {
493 return Err(eyre!("PSBT input count mismatch").into());
494 }
495
496 let mut tx = psbt.unsigned_tx.clone();
497 for (idx, input) in tx.input.iter_mut().enumerate() {
498 let psbt_input = &psbt.inputs[idx];
499 if psbt_input.final_script_witness.is_none() && psbt_input.final_script_sig.is_none() {
500 return Err(eyre!("PSBT input {idx} is not finalized").into());
501 }
502 if let Some(witness) = psbt_input.final_script_witness.clone() {
503 input.witness = witness;
504 }
505 if let Some(sig) = psbt_input.final_script_sig.clone() {
506 input.script_sig = sig;
507 }
508 }
509 Ok(tx)
510 }
511
512 pub async fn get_tx_fee(&self, tx: &Transaction) -> Result<Amount> {
513 let inputs = {
514 let mut inputs = Amount::ZERO;
515 for inp in &tx.input {
516 inputs += self
517 .rpc
518 .get_txout_from_outpoint(&inp.previous_output)
519 .await
520 .map_err(|e| eyre!(e))?
521 .value;
522 }
523 inputs
524 };
525 let outputs = tx.output.iter().map(|o| o.value).sum::<Amount>();
526
527 let tx_fee = inputs - outputs;
528
529 Ok(tx_fee)
530 }
531
532 #[tracing::instrument(skip_all, fields(try_to_send_id, tx_meta=?tx_metadata))]
556 #[allow(clippy::too_many_arguments)]
557 pub async fn send_rbf_tx(
558 &self,
559 try_to_send_id: u32,
560 mut tx: Transaction,
561 tx_metadata: Option<TxMetadata>,
562 fee_rate: FeeRateKvb,
563 rbf_signing_info: Option<RbfSigningInfo>,
564 current_tip_height: u32,
565 needs_wtxid_grind: bool,
566 ) -> Result<()> {
567 tracing::debug!(?tx_metadata, "Sending RBF tx",);
568
569 tracing::debug!(?try_to_send_id, "Attempting to send.");
570
571 let _ = self
572 .db
573 .update_tx_debug_sending_state(try_to_send_id, "preparing_rbf", true)
574 .await;
575
576 let rbf_txids = self
577 .db
578 .list_rbf_txids_for_id(None, try_to_send_id)
579 .await
580 .wrap_err("Failed to list RBF txids")?;
581
582 let mut bump_from_txid = None;
585 for txid in rbf_txids {
586 match self.rpc.get_mempool_entry(&txid).await {
587 Ok(_) => {
588 bump_from_txid = Some(txid);
589 break;
590 }
591 Err(e) => {
592 if !e.to_string().contains("Transaction not in mempool") {
594 return Err(eyre!("Failed to get mempool entry for {txid}: {e}").into());
595 }
596
597 if let Ok(tx_info) = self.rpc.get_transaction(&txid, None).await {
598 if tx_info.info.blockhash.is_some() && tx_info.info.confirmations > 0 {
599 tracing::debug!(
600 ?try_to_send_id,
601 "RBF tx {txid} already confirmed, skipping bump"
602 );
603 return Ok(());
604 }
605 }
606 }
607 }
608 }
609
610 let cached_leaf_hash = match &rbf_signing_info {
612 Some(rbf_signing_info) => match &rbf_signing_info.spend_path {
613 RbfSigningSpendPath::ScriptPath { script, .. } => Some(TapLeafHash::from_script(
614 ScriptBuf::from_bytes(script.clone()).as_script(),
615 LeafVersion::TapScript,
616 )),
617 _ => None,
618 },
619 None => None,
620 };
621
622 let effective_feerate = if let Some(bump_from_txid) = bump_from_txid {
623 tracing::debug!(
624 ?try_to_send_id,
625 "Attempting to bump fee for txid {bump_from_txid} using psbt_bump_fee"
626 );
627
628 let effective_feerate = self
629 .calculate_bump_feerate_if_needed(&bump_from_txid, fee_rate)
630 .await?;
631
632 let Some(effective_feerate) = effective_feerate else {
633 tracing::debug!(
634 ?try_to_send_id,
635 "Original tx feerate already higher than target ({} sat/vB), skipping bump",
636 fee_rate.to_sat_per_vb_ceil()
637 );
638 return Ok(());
639 };
640
641 let psbt_bump_opts = BumpFeeOptions {
642 conf_target: None, fee_rate: Some(bitcoincore_rpc::json::FeeRate::per_kvbyte(
644 Amount::from_sat(effective_feerate.to_sat_per_kvb()),
645 )),
646 replaceable: Some(true), estimate_mode: None,
648 };
649
650 let bump_result = self
651 .rpc
652 .psbt_bump_fee(&bump_from_txid, Some(&psbt_bump_opts))
653 .await;
654
655 let mut bumped_psbt = match bump_result {
656 Err(e) => {
657 let rpc_error_str = e.to_string();
659 if rpc_error_str.contains("Transaction already in block chain") {
660 tracing::debug!(
661 ?try_to_send_id,
662 "RBF bump failed for {bump_from_txid}, likely confirmed or spent: {e}"
663 );
664 return Ok(());
666 } else {
667 let error_message = format!("psbt_bump_fee failed: {e}");
669 log_error_for_tx!(self.db, try_to_send_id, error_message);
670 let _ = self
671 .db
672 .update_tx_debug_sending_state(
673 try_to_send_id,
674 "rbf_psbt_bump_failed",
675 true,
676 )
677 .await;
678 tracing::warn!(?try_to_send_id, "psbt_bump_fee failed: {e:?}");
679 return Err(SendTxError::Other(eyre!(e)));
680 }
681 }
682 Ok(BumpFeeResult {
683 psbt: Some(psbt), ..
684 }) => psbt,
685 Ok(BumpFeeResult { errors, .. }) if !errors.is_empty() => {
686 self.handle_err(
687 format!("psbt_bump_fee failed: {errors:?}"),
688 "rbf_psbt_bump_failed",
689 try_to_send_id,
690 );
691 return Err(SendTxError::Other(eyre!(errors.join(", "))));
692 }
693 Ok(BumpFeeResult { psbt: None, .. }) => {
694 self.handle_err(
695 "psbt_bump_fee returned no psbt",
696 "rbf_psbt_bump_failed",
697 try_to_send_id,
698 );
699 return Err(SendTxError::Other(eyre!("psbt_bump_fee returned no psbt")));
700 }
701 };
702
703 self.fill_in_utxo_info(&mut bumped_psbt)
704 .await
705 .map_err(|err| {
706 let err = eyre!(err).wrap_err("Failed to fill in utxo info");
707 self.handle_err(
708 format!("{err:?}"),
709 "rbf_fill_in_utxo_info_failed",
710 try_to_send_id,
711 );
712
713 err
714 })?;
715
716 let bumped_psbt = self
717 .copy_witnesses(bumped_psbt, &tx)
718 .await
719 .wrap_err("Failed to fill SAP signatures")?;
720
721 let mut unsigned_psbt = Psbt::from_str(&bumped_psbt).map_err(|e| eyre!(e))?;
722
723 if let Err(err) = self.reorder_psbt_outputs(&mut unsigned_psbt, &tx) {
724 let err_msg = format!("Failed to reorder bumped PSBT outputs: {err}");
725 self.handle_err(
726 err_msg.clone(),
727 "rbf_psbt_output_reorder_failed",
728 try_to_send_id,
729 );
730 return Err(err);
731 }
732 let mut current_locktime = unsigned_psbt.unsigned_tx.lock_time;
733
734 let final_tx = loop {
735 unsigned_psbt.unsigned_tx.lock_time = current_locktime;
736 let bumped_psbt = unsigned_psbt.to_string();
737
738 let process_result = self
741 .rpc
742 .wallet_process_psbt(&bumped_psbt, Some(true), None, None) .await;
744
745 let processed_psbt = match process_result {
746 Ok(res) if res.complete => res.psbt,
747 Ok(res) => {
749 let Some(rbf_signing_info) = &rbf_signing_info else {
750 return Err(eyre!(
751 "RBF signing info is required for non SighashSingle RBF txs"
752 )
753 .into());
754 };
755 self.attempt_sign_psbt(res.psbt, rbf_signing_info, cached_leaf_hash)
756 .await?
757 }
758 Err(e) => {
759 let err_msg = format!("wallet_process_psbt error: {e}");
760 tracing::warn!(?try_to_send_id, "{}", err_msg);
761 log_error_for_tx!(self.db, try_to_send_id, err_msg);
762 let _ = self
763 .db
764 .update_tx_debug_sending_state(
765 try_to_send_id,
766 "rbf_psbt_sign_failed",
767 true,
768 )
769 .await;
770 return Err(SendTxError::Other(eyre!(e)));
771 }
772 };
773
774 let final_tx = Self::extract_final_tx_from_psbt(&processed_psbt)?;
775 if !needs_wtxid_grind
776 || final_tx
777 .compute_wtxid()
778 .as_raw_hash()
779 .to_byte_array()
780 .starts_with(REVEAL_TX_PREFIX)
781 {
782 break final_tx;
783 } else {
784 current_locktime = LockTime::from_consensus(std::cmp::max(
785 current_locktime.to_consensus_u32() + 1,
786 LOCK_TIME_THRESHOLD,
787 ));
788 }
789 };
790
791 let bumped_txid = final_tx.compute_txid();
792
793 let sent_txid = match self.rpc.send_raw_transaction(&final_tx).await {
795 Ok(sent_txid) if sent_txid == bumped_txid => sent_txid,
796 Ok(other_txid) => {
797 log_error_for_tx!(
798 self.db,
799 try_to_send_id,
800 format!(
801 "send_raw_transaction returned unexpected txid {} (expected {})",
802 other_txid, bumped_txid
803 )
804 );
805 let _ = self
806 .db
807 .update_tx_debug_sending_state(
808 try_to_send_id,
809 "rbf_send_txid_mismatch",
810 true,
811 )
812 .await;
813 return Err(SendTxError::Other(eyre!(
814 "send_raw_transaction returned unexpected txid"
815 )));
816 }
817 Err(e) => {
818 log_error_for_tx!(
819 self.db,
820 try_to_send_id,
821 format!("send_raw_transaction error for bumped RBF tx: {}", e)
822 );
823 let _ = self
824 .db
825 .update_tx_debug_sending_state(try_to_send_id, "rbf_bump_send_failed", true)
826 .await;
827 return Err(SendTxError::Other(eyre!(e)));
828 }
829 };
830
831 tracing::debug!(
832 ?try_to_send_id,
833 "RBF tx {bump_from_txid} successfully bumped and sent as {sent_txid}"
834 );
835
836 let _ = self
837 .db
838 .update_tx_debug_sending_state(try_to_send_id, "rbf_bumped_sent", true)
839 .await;
840
841 self.db
842 .save_rbf_txid(None, try_to_send_id, sent_txid)
843 .await
844 .wrap_err("Failed to save new RBF txid after bump")?;
845
846 effective_feerate
847 } else {
848 tracing::debug!(
849 ?try_to_send_id,
850 "Funding initial RBF tx using PSBT workflow"
851 );
852
853 let _ = self
854 .db
855 .update_tx_debug_sending_state(try_to_send_id, "creating_initial_rbf_psbt", true)
856 .await;
857
858 if let Some(rbf_signing_info) = &rbf_signing_info {
860 let vout = rbf_signing_info.vout as usize;
861 let input_count = tx.input.len();
862 let input = tx.input.get_mut(vout).ok_or_else(|| {
863 SendTxError::from(eyre!(
864 "Input at vout {} given in RBF signing info does not exist in transaction (has {} inputs)",
865 vout,
866 input_count
867 ))
868 })?;
869 if input.witness.is_empty() {
870 match &rbf_signing_info.spend_path {
871 RbfSigningSpendPath::KeyPath { .. } => {
872 input.witness = Witness::from_slice(&[&[0u8; 65]]);
873 }
874 RbfSigningSpendPath::ScriptPath {
875 script,
876 control_block,
877 } => {
878 let mut witness = Witness::new();
879 witness.push([0u8; 65]);
880 witness.push(script.clone());
881 witness.push(control_block.clone());
882 input.witness = witness;
883 }
884 }
885 }
886 }
887
888 let mut added_dummy_output = false;
889 if tx.output.is_empty() {
892 tx.output.push(TxOut {
893 value: NON_EPHEMERAL_ANCHOR_AMOUNT,
894 script_pubkey: ScriptBuf::from_hex("51024e73").expect("valid anchor script"),
895 });
896 added_dummy_output = true;
897 }
898
899 let create_result = self
900 .create_funded_psbt(&tx, fee_rate)
901 .await
902 .map_err(|err| {
903 let err = eyre!(err).wrap_err("Failed to create funded PSBT");
904 self.handle_err(format!("{err:?}"), "rbf_psbt_create_failed", try_to_send_id);
905
906 err
907 })?;
908
909 if !self.verify_new_inputs(&create_result.psbt, &tx) {
910 tracing::warn!(
911 ?try_to_send_id,
912 "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."
913 );
914 }
915 let mut funded_psbt_str = create_result.psbt;
916
917 self.fill_in_utxo_info(&mut funded_psbt_str)
918 .await
919 .map_err(|err| {
920 let err = eyre!(err).wrap_err("Failed to fill in utxo info");
921 self.handle_err(
922 format!("{err:?}"),
923 "rbf_fill_in_utxo_info_failed",
924 try_to_send_id,
925 );
926
927 err
928 })?;
929
930 funded_psbt_str = self
931 .copy_witnesses(funded_psbt_str, &tx)
932 .await
933 .map_err(|err| {
934 let err = eyre!(err).wrap_err("Failed to copy witnesses");
935 self.handle_err(
936 format!("{err:?}"),
937 "rbf_copy_witnesses_failed",
938 try_to_send_id,
939 );
940
941 err
942 })?;
943
944 let mut funded_psbt = Psbt::from_str(&funded_psbt_str).map_err(|e| eyre!(e))?;
945 if added_dummy_output {
946 let dummy_output_weight = funded_psbt.unsigned_tx.output[0].weight();
949 let dummy_output_value = funded_psbt.unsigned_tx.output[0].value;
950 let needed_fee_for_dummy_output = fee_rate.fee_wu(dummy_output_weight).ok_or_eyre(format!("Fee overflow occurred for dummy output: current fee rate: {fee_rate}, dummy_output_weight: {dummy_output_weight}"))?;
951 funded_psbt.unsigned_tx.output.remove(0);
952 funded_psbt.outputs.remove(0);
953 let Some(change_output) = funded_psbt.unsigned_tx.output.last_mut() else {
954 let err_msg = "Failed to remove dummy output: funded no-output RBF transaction has no change output";
955 return Err(SendTxError::Other(eyre!(err_msg)));
956 };
957 change_output.value += needed_fee_for_dummy_output + dummy_output_value;
958 } else if let Err(err) = self.reorder_psbt_outputs(&mut funded_psbt, &tx) {
959 let err_msg = format!("Failed to reorder initial PSBT outputs: {err}");
961 self.handle_err(
962 err_msg.clone(),
963 "rbf_psbt_output_reorder_failed",
964 try_to_send_id,
965 );
966 return Err(err);
967 }
968 let mut current_locktime = tx.lock_time;
969
970 let final_tx = loop {
971 funded_psbt.unsigned_tx.lock_time = current_locktime;
973 funded_psbt.unsigned_tx.version = tx.version;
974
975 tracing::debug!(
976 try_to_send_id,
977 "Successfully created initial RBF PSBT with fee {}",
978 create_result.fee
979 );
980
981 let mut psbt = funded_psbt.to_string();
982
983 let process_result = self
985 .rpc
986 .wallet_process_psbt(&psbt, Some(true), None, None)
987 .await
988 .map_err(|err| {
989 let err = eyre!(err).wrap_err("Failed to process initial RBF PSBT");
990 self.handle_err(
991 format!("{err:?}"),
992 "rbf_psbt_process_failed",
993 try_to_send_id,
994 );
995
996 err
997 })?;
998
999 if let Some(rbf_signing_info) = &rbf_signing_info {
1000 psbt = self
1001 .attempt_sign_psbt(process_result.psbt, rbf_signing_info, cached_leaf_hash)
1002 .await
1003 .map_err(|err| {
1004 let err = eyre!(err).wrap_err("Failed to sign initial RBF PSBT");
1005 self.handle_err(
1006 format!("{err:?}"),
1007 "rbf_psbt_sign_failed",
1008 try_to_send_id,
1009 );
1010
1011 err
1012 })?;
1013 } else {
1014 psbt = process_result.psbt;
1015 }
1016
1017 tracing::debug!(try_to_send_id, "Successfully processed initial RBF PSBT");
1018
1019 let final_tx = Self::extract_final_tx_from_psbt(&psbt)?;
1020 if !needs_wtxid_grind
1022 || final_tx
1023 .compute_wtxid()
1024 .as_raw_hash()
1025 .to_byte_array()
1026 .starts_with(REVEAL_TX_PREFIX)
1027 {
1028 break final_tx;
1029 } else {
1030 current_locktime = LockTime::from_consensus(std::cmp::max(
1032 current_locktime.to_consensus_u32() + 1,
1033 LOCK_TIME_THRESHOLD,
1034 ));
1035 }
1036 };
1037
1038 let initial_txid = final_tx.compute_txid();
1039
1040 let sent_txid = match self.rpc.send_raw_transaction(&final_tx).await {
1042 Ok(sent_txid) => {
1043 if sent_txid != initial_txid {
1044 let err_msg = format!(
1045 "send_raw_transaction returned unexpected txid {sent_txid} (expected {initial_txid}) for initial RBF",
1046 );
1047 log_error_for_tx!(self.db, try_to_send_id, err_msg);
1048 let _ = self
1049 .db
1050 .update_tx_debug_sending_state(
1051 try_to_send_id,
1052 "rbf_initial_send_txid_mismatch",
1053 true,
1054 )
1055 .await;
1056 return Err(SendTxError::Other(eyre!(err_msg)));
1057 }
1058 tracing::debug!(
1059 try_to_send_id,
1060 "Successfully sent initial RBF tx with txid {sent_txid}"
1061 );
1062 sent_txid
1063 }
1064 Err(e) => {
1065 tracing::error!("RBF failed for: {:?}", final_tx);
1066 let err_msg = format!("send_raw_transaction error for initial RBF tx: {e}");
1067 log_error_for_tx!(self.db, try_to_send_id, err_msg);
1068 let _ = self
1069 .db
1070 .update_tx_debug_sending_state(
1071 try_to_send_id,
1072 "rbf_initial_send_failed",
1073 true,
1074 )
1075 .await;
1076 return Err(SendTxError::Other(eyre!(e)));
1077 }
1078 };
1079
1080 let _ = self
1082 .db
1083 .update_tx_debug_sending_state(try_to_send_id, "rbf_initial_sent", true)
1084 .await;
1085
1086 self.db
1087 .save_rbf_txid(None, try_to_send_id, sent_txid)
1088 .await
1089 .wrap_err("Failed to save initial RBF txid")?;
1090
1091 fee_rate
1092 };
1093
1094 self.db
1095 .update_effective_fee_rate(None, try_to_send_id, effective_feerate, current_tip_height)
1096 .await
1097 .wrap_err("Failed to update effective fee rate")?;
1098
1099 Ok(())
1100 }
1101}