1use crate::{log_error_for_tx, TxSender, TxSenderDatabase, TxSenderSigner, TxSenderTxBuilder};
2use bitcoin::script::Instruction;
3use bitcoin::sighash::{Prevouts, SighashCache};
4use bitcoin::taproot::{self};
5use bitcoin::{consensus, Address, Amount, FeeRate, Transaction};
6use bitcoin::{Psbt, TapSighashType, TxOut, Txid, Witness};
7use bitcoincore_rpc::json::{
8 BumpFeeOptions, BumpFeeResult, CreateRawTransactionInput, FinalizePsbtResult,
9 WalletCreateFundedPsbtOutput, WalletCreateFundedPsbtOutputs, WalletCreateFundedPsbtResult,
10};
11use bitcoincore_rpc::RpcApi;
12use clementine_errors::SendTxError;
13use clementine_utils::sign::TapTweakData;
14use clementine_utils::{RbfSigningInfo, TxMetadata};
15use eyre::Context;
16use eyre::{eyre, OptionExt};
17use std::str::FromStr;
18
19use super::Result;
20
21impl<S, D, B> TxSender<S, D, B>
22where
23 S: TxSenderSigner,
24 D: TxSenderDatabase,
25 B: TxSenderTxBuilder,
26{
27 pub async fn calculate_bump_feerate_if_needed(
47 &self,
48 txid: &Txid,
49 new_feerate: FeeRate,
50 ) -> Result<Option<FeeRate>> {
51 let original_tx = self.rpc.get_tx_of_txid(txid).await.map_err(|e| eyre!(e))?;
52
53 let original_tx_fee = self.get_tx_fee(&original_tx).await.map_err(|e| eyre!(e))?;
55
56 let original_tx_weight = original_tx.weight();
59
60 let original_feerate_sat_per_kwu = FeeRate::from_sat_per_kwu(
64 (original_tx_fee.to_sat() * 1000) / (original_tx_weight.to_vbytes_ceil() * 4),
65 );
66
67 if original_feerate_sat_per_kwu >= new_feerate {
69 return Ok(None);
70 }
71
72 let incremental_fee_rate = self
74 .rpc
75 .get_network_info()
76 .await
77 .map_err(|e| eyre!(e))?
78 .incremental_fee;
79 let incremental_fee_rate_sat_per_kvb = incremental_fee_rate.to_sat();
80 let incremental_fee_rate = FeeRate::from_sat_per_kwu(incremental_fee_rate_sat_per_kvb / 4);
81
82 let min_bump_feerate =
84 original_feerate_sat_per_kwu.to_sat_per_kwu() + incremental_fee_rate.to_sat_per_kwu();
85
86 let effective_feerate_sat_per_kwu =
87 std::cmp::max(new_feerate.to_sat_per_kwu(), min_bump_feerate);
88
89 Ok(Some(FeeRate::from_sat_per_kwu(
90 effective_feerate_sat_per_kwu,
91 )))
92 }
93
94 pub async fn fill_in_utxo_info(&self, psbt: &mut String) -> Result<()> {
95 let mut decoded_psbt = Psbt::from_str(psbt).map_err(|e| eyre!(e))?;
96 let tx = decoded_psbt.unsigned_tx.clone();
97
98 for (idx, input) in tx.input.iter().enumerate() {
99 let utxo = self
100 .rpc
101 .get_tx_out(
102 &input.previous_output.txid,
103 input.previous_output.vout,
104 Some(false),
105 )
106 .await
107 .wrap_err("Failed to get UTXO info")?;
108
109 if let Some(utxo) = utxo {
110 decoded_psbt.inputs[idx].witness_utxo = Some(TxOut {
111 value: utxo.value,
112 script_pubkey: utxo
113 .script_pub_key
114 .script()
115 .wrap_err("Failed to get script pubkey")?,
116 });
117 }
118 }
119
120 *psbt = decoded_psbt.to_string();
121
122 Ok(())
123 }
124
125 pub async fn copy_witnesses(&self, psbt: String, initial_tx: &Transaction) -> Result<String> {
133 let mut decoded_psbt = Psbt::from_str(&psbt).map_err(|e| eyre!(e))?;
134
135 for (idx, input) in initial_tx.input.iter().enumerate() {
136 if let Some(sig) = input.witness.nth(0) {
137 if sig.len() == 65 && sig[64] == 0x83 {
138 decoded_psbt.inputs[idx].final_script_witness = Some(input.witness.clone());
140 }
141 }
142 }
143
144 Ok(decoded_psbt.to_string())
145 }
146
147 pub async fn create_funded_psbt(
148 &self,
149 tx: &Transaction,
150 fee_rate: FeeRate,
151 ) -> Result<WalletCreateFundedPsbtResult> {
152 let witness_scaleup = tx.weight().to_wu() as f64 / (tx.base_size() * 4) as f64;
160
161 let adjusted_fee_rate = FeeRate::from_sat_per_kwu(
162 (fee_rate.to_sat_per_kwu() as f64 * witness_scaleup).ceil() as u64,
163 );
164
165 let create_psbt_opts = bitcoincore_rpc::json::WalletCreateFundedPsbtOptions {
167 add_inputs: Some(true), change_address: None,
169 change_position: Some(tx.output.len() as u16), change_type: None,
171 include_watching: None,
172 lock_unspent: None,
173 fee_rate: Some(
175 adjusted_fee_rate
176 .fee_vb(1000)
177 .ok_or_eyre("Failed to convert fee rate to BTC/kvbyte")?,
178 ),
179 subtract_fee_from_outputs: vec![],
180 replaceable: Some(true), conf_target: None,
182 estimate_mode: None,
183 };
184
185 let mut omitted = 0usize;
186 let filtered_outputs: Vec<WalletCreateFundedPsbtOutput> = tx
187 .output
188 .iter()
189 .filter_map(|out| {
190 if out.script_pubkey.is_op_return() {
191 if let Some(Ok(Instruction::PushBytes(data))) =
192 out.script_pubkey.instructions().last()
193 {
194 return Some(WalletCreateFundedPsbtOutput::OpReturn(
195 data.as_bytes().to_vec(),
196 ));
197 }
198 }
199 let address = Address::from_script(
200 &out.script_pubkey,
201 self.protocol_paramset.network,
202 )
203 .map_err(|e| eyre!(e));
204 match address {
205 Ok(address) => Some(WalletCreateFundedPsbtOutput::Spendable(
206 address.to_string(),
207 out.value,
208 )),
209 Err(err) => {
210 tracing::error!(
211 "Failed to get address from script for output of tx with txid {} for script: {}",
212 tx.compute_txid(),
213 err
214 );
215 omitted += 1;
216 None
217 }
218 }
219 })
220 .collect::<Vec<_>>();
221
222 if omitted > 0 {
223 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());
224 }
225
226 let outputs = WalletCreateFundedPsbtOutputs(filtered_outputs);
227
228 self.rpc
229 .wallet_create_funded_psbt(
230 &tx.input
231 .iter()
232 .map(|inp| CreateRawTransactionInput {
233 txid: inp.previous_output.txid,
234 vout: inp.previous_output.vout,
235 sequence: Some(inp.sequence.to_consensus_u32()),
236 })
237 .collect::<Vec<_>>(),
238 outputs,
239 None,
240 Some(create_psbt_opts),
241 None,
242 )
243 .await
244 .map_err(|e| eyre!(e).into())
245 }
246 pub async fn attempt_sign_psbt(
254 &self,
255 psbt: String,
256 rbf_signing_info: RbfSigningInfo,
257 ) -> Result<String> {
258 let mut decoded_psbt = Psbt::from_str(&psbt).map_err(|e| eyre!(e))?;
260
261 if decoded_psbt.inputs.is_empty() {
263 return Err(eyre!("PSBT has no inputs to sign").into());
264 }
265
266 let input_index = rbf_signing_info.vout as usize;
267
268 let tx = decoded_psbt.unsigned_tx.clone();
270 let mut sighash_cache = SighashCache::new(&tx);
271
272 let sighash_type = decoded_psbt.inputs[input_index]
274 .sighash_type
275 .unwrap_or((TapSighashType::Default).into());
276
277 if let Ok(tap_sighash_type) = sighash_type.taproot_hash_ty() {
279 let prevouts: Vec<bitcoin::TxOut> = decoded_psbt
282 .inputs
283 .iter()
284 .map(|input| {
285 input
286 .witness_utxo
287 .clone()
288 .ok_or_eyre("expected inputs to be segwit")
289 .map_err(SendTxError::Other)
290 })
291 .collect::<Result<Vec<_>>>()?;
292
293 let sighash = sighash_cache
294 .taproot_key_spend_signature_hash(
295 input_index,
296 &Prevouts::All(&prevouts),
297 tap_sighash_type,
298 )
299 .map_err(|e| eyre!("Failed to calculate sighash: {}", e))?;
300
301 #[cfg(test)]
302 let mut sighash = sighash;
303
304 #[cfg(test)]
305 {
306 use bitcoin::sighash::Annex;
307 if let Some(ref annex_bytes) = rbf_signing_info.annex {
309 let annex = Annex::new(annex_bytes).unwrap();
310 sighash = sighash_cache
311 .taproot_signature_hash(
312 input_index,
313 &Prevouts::All(&prevouts),
314 Some(annex),
315 None,
316 tap_sighash_type,
317 )
318 .map_err(|e| eyre!("Failed to calculate sighash with annex: {}", e))?;
319 }
320 }
321
322 let signature = self
324 .signer
325 .sign_with_tweak_data(
326 sighash,
327 TapTweakData::KeyPath(rbf_signing_info.tweak_merkle_root),
328 )
329 .map_err(|e| eyre!("Failed to sign input: {}", e))?;
330
331 decoded_psbt.inputs[input_index].tap_key_sig = Some(taproot::Signature {
333 signature,
334 sighash_type: tap_sighash_type,
335 });
336
337 decoded_psbt.inputs[input_index].final_script_witness =
338 Some(Witness::from_slice(&[signature.serialize()]));
339
340 #[cfg(test)]
341 {
342 if let Some(ref annex_bytes) = rbf_signing_info.annex {
343 let mut witness = Witness::from_slice(&[signature.serialize()]);
344 witness.push(annex_bytes);
345 decoded_psbt.inputs[input_index].final_script_witness = Some(witness);
346 tracing::info!("Decoded PSBT: {:?}", decoded_psbt);
347 }
348 }
349 Ok(decoded_psbt.to_string())
351 } else {
352 Err(eyre!("Only Taproot key path signing is currently supported").into())
353 }
354 }
355
356 #[track_caller]
357 pub fn handle_err(
358 &self,
359 err_msg: impl AsRef<str>,
360 err_state: impl Into<String>,
361 try_to_send_id: u32,
362 ) {
363 log_error_for_tx!(self.db, try_to_send_id, err_msg.as_ref());
364
365 let err_state = err_state.into();
366 let db = self.db.clone();
367
368 tokio::spawn(async move {
369 let _ = db
370 .update_tx_debug_sending_state(try_to_send_id, &err_state, true)
371 .await;
372 });
373 }
374
375 pub fn verify_new_inputs(&self, psbt: &str, original_tx: &Transaction) -> bool {
380 let Ok(psbt) = Psbt::from_str(psbt) else {
381 tracing::error!("Failed to parse PSBT");
382 return false;
383 };
384
385 psbt.inputs.len() > original_tx.input.len()
386 }
387
388 pub async fn get_tx_fee(&self, tx: &Transaction) -> Result<Amount> {
389 let inputs = {
390 let mut inputs = Amount::ZERO;
391 for inp in &tx.input {
392 inputs += self
393 .rpc
394 .get_txout_from_outpoint(&inp.previous_output)
395 .await
396 .map_err(|e| eyre!(e))?
397 .value;
398 }
399 inputs
400 };
401 let outputs = tx.output.iter().map(|o| o.value).sum::<Amount>();
402
403 let tx_fee = inputs - outputs;
404
405 Ok(tx_fee)
406 }
407
408 #[tracing::instrument(skip_all, fields(sender = self.btc_syncer_consumer_id, try_to_send_id, tx_meta=?tx_metadata))]
431 pub async fn send_rbf_tx(
432 &self,
433 try_to_send_id: u32,
434 tx: Transaction,
435 tx_metadata: Option<TxMetadata>,
436 fee_rate: FeeRate,
437 rbf_signing_info: Option<RbfSigningInfo>,
438 ) -> Result<()> {
439 tracing::debug!(?tx_metadata, "Sending RBF tx",);
440
441 tracing::debug!(?try_to_send_id, "Attempting to send.");
442
443 let _ = self
444 .db
445 .update_tx_debug_sending_state(try_to_send_id, "preparing_rbf", true)
446 .await;
447
448 let mut dbtx = self
449 .db
450 .begin_transaction()
451 .await
452 .wrap_err("Failed to begin database transaction")?;
453
454 let last_rbf_txid = self
455 .db
456 .get_last_rbf_txid(Some(&mut dbtx), try_to_send_id)
457 .await
458 .wrap_err("Failed to get last RBF txid")?;
459
460 if let Some(last_rbf_txid) = last_rbf_txid {
461 tracing::debug!(
462 ?try_to_send_id,
463 "Attempting to bump fee for txid {last_rbf_txid} using psbt_bump_fee"
464 );
465
466 let effective_feerate = self
467 .calculate_bump_feerate_if_needed(&last_rbf_txid, fee_rate)
468 .await?;
469
470 let Some(effective_feerate) = effective_feerate else {
471 tracing::debug!(
472 ?try_to_send_id,
473 "Original tx feerate already higher than target ({} sat/vB), skipping bump",
474 fee_rate.to_sat_per_vb_ceil()
475 );
476 return Ok(());
477 };
478
479 let psbt_bump_opts = BumpFeeOptions {
480 conf_target: None, fee_rate: Some(bitcoincore_rpc::json::FeeRate::per_vbyte(Amount::from_sat(
482 effective_feerate.to_sat_per_vb_ceil(),
483 ))),
484 replaceable: Some(true), estimate_mode: None,
486 };
487
488 let bump_result = self
489 .rpc
490 .psbt_bump_fee(&last_rbf_txid, Some(&psbt_bump_opts))
491 .await;
492
493 let bumped_psbt = match bump_result {
494 Err(e) => {
495 let rpc_error_str = e.to_string();
497 if rpc_error_str.contains("Transaction already in block chain") {
498 tracing::debug!(
499 ?try_to_send_id,
500 "RBF bump failed for {last_rbf_txid}, likely confirmed or spent: {e}"
501 );
502 self.db.commit_transaction(dbtx).await.wrap_err(
504 "Failed to commit database transaction after failed bump check",
505 )?;
506 return Ok(());
507 } else {
508 let error_message = format!("psbt_bump_fee failed: {e}");
510 log_error_for_tx!(self.db, try_to_send_id, error_message);
511 let _ = self
512 .db
513 .update_tx_debug_sending_state(
514 try_to_send_id,
515 "rbf_psbt_bump_failed",
516 true,
517 )
518 .await;
519 tracing::warn!(?try_to_send_id, "psbt_bump_fee failed: {e:?}");
520 return Err(SendTxError::Other(eyre!(e)));
521 }
522 }
523 Ok(BumpFeeResult {
524 psbt: Some(psbt), ..
525 }) => psbt,
526 Ok(BumpFeeResult { errors, .. }) if !errors.is_empty() => {
527 self.handle_err(
528 format!("psbt_bump_fee failed: {errors:?}"),
529 "rbf_psbt_bump_failed",
530 try_to_send_id,
531 );
532 return Err(SendTxError::Other(eyre!(errors.join(", "))));
533 }
534 Ok(BumpFeeResult { psbt: None, .. }) => {
535 self.handle_err(
536 "psbt_bump_fee returned no psbt",
537 "rbf_psbt_bump_failed",
538 try_to_send_id,
539 );
540 return Err(SendTxError::Other(eyre!("psbt_bump_fee returned no psbt")));
541 }
542 };
543
544 let bumped_psbt = self
545 .copy_witnesses(bumped_psbt, &tx)
546 .await
547 .wrap_err("Failed to fill SAP signatures")?;
548
549 let process_result = self
552 .rpc
553 .wallet_process_psbt(&bumped_psbt, Some(true), None, None) .await;
555
556 let processed_psbt = match process_result {
557 Ok(res) if res.complete => res.psbt,
558 Ok(res) => {
560 let Some(rbf_signing_info) = rbf_signing_info else {
561 return Err(eyre!(
562 "RBF signing info is required for non SighashSingle RBF txs"
563 )
564 .into());
565 };
566 self.attempt_sign_psbt(res.psbt, rbf_signing_info).await?
567 }
568 Err(e) => {
569 let err_msg = format!("wallet_process_psbt error: {e}");
570 tracing::warn!(?try_to_send_id, "{}", err_msg);
571 log_error_for_tx!(self.db, try_to_send_id, err_msg);
572 let _ = self
573 .db
574 .update_tx_debug_sending_state(try_to_send_id, "rbf_psbt_sign_failed", true)
575 .await;
576 return Err(SendTxError::Other(eyre!(e)));
577 }
578 };
579
580 let finalize_result = self
582 .rpc
583 .finalize_psbt(&processed_psbt, None) .await;
585
586 let final_tx_hex = match finalize_result {
587 Ok(FinalizePsbtResult {
588 hex: Some(hex),
589 complete: true,
590 ..
591 }) => hex,
592 Ok(res) => {
593 let err_msg = format!("Could not finalize PSBT: {res:?}");
594 log_error_for_tx!(self.db, try_to_send_id, err_msg);
595
596 let _ = self
597 .db
598 .update_tx_debug_sending_state(
599 try_to_send_id,
600 "rbf_psbt_finalize_incomplete",
601 true,
602 )
603 .await;
604 return Err(SendTxError::PsbtError(err_msg));
605 }
606 Err(e) => {
607 log_error_for_tx!(
608 self.db,
609 try_to_send_id,
610 format!("finalize_psbt error: {}", e)
611 );
612 let _ = self
613 .db
614 .update_tx_debug_sending_state(
615 try_to_send_id,
616 "rbf_psbt_finalize_failed",
617 true,
618 )
619 .await;
620 return Err(SendTxError::Other(eyre!(e)));
621 }
622 };
623
624 let final_tx: Transaction = match consensus::deserialize(&final_tx_hex) {
626 Ok(tx) => tx,
627 Err(e) => {
628 log_error_for_tx!(
629 self.db,
630 try_to_send_id,
631 format!("Failed to deserialize final RBF tx hex: {}", e)
632 );
633 return Err(SendTxError::Other(eyre!(e)));
634 }
635 };
636 let bumped_txid = final_tx.compute_txid();
637
638 let sent_txid = match self.rpc.send_raw_transaction(&final_tx).await {
640 Ok(sent_txid) if sent_txid == bumped_txid => sent_txid,
641 Ok(other_txid) => {
642 log_error_for_tx!(
643 self.db,
644 try_to_send_id,
645 format!(
646 "send_raw_transaction returned unexpected txid {} (expected {})",
647 other_txid, bumped_txid
648 )
649 );
650 let _ = self
651 .db
652 .update_tx_debug_sending_state(
653 try_to_send_id,
654 "rbf_send_txid_mismatch",
655 true,
656 )
657 .await;
658 return Err(SendTxError::Other(eyre!(
659 "send_raw_transaction returned unexpected txid"
660 )));
661 }
662 Err(e) => {
663 log_error_for_tx!(
664 self.db,
665 try_to_send_id,
666 format!("send_raw_transaction error for bumped RBF tx: {}", e)
667 );
668 let _ = self
669 .db
670 .update_tx_debug_sending_state(try_to_send_id, "rbf_bump_send_failed", true)
671 .await;
672 return Err(SendTxError::Other(eyre!(e)));
673 }
674 };
675
676 tracing::debug!(
677 ?try_to_send_id,
678 "RBF tx {last_rbf_txid} successfully bumped and sent as {sent_txid}"
679 );
680
681 let _ = self
682 .db
683 .update_tx_debug_sending_state(try_to_send_id, "rbf_bumped_sent", true)
684 .await;
685
686 self.db
687 .save_rbf_txid(Some(&mut dbtx), try_to_send_id, sent_txid)
688 .await
689 .wrap_err("Failed to save new RBF txid after bump")?;
690 } else {
691 tracing::debug!(
692 ?try_to_send_id,
693 "Funding initial RBF tx using PSBT workflow"
694 );
695
696 let _ = self
697 .db
698 .update_tx_debug_sending_state(try_to_send_id, "creating_initial_rbf_psbt", true)
699 .await;
700
701 let create_result = self
702 .create_funded_psbt(&tx, fee_rate)
703 .await
704 .map_err(|err| {
705 let err = eyre!(err).wrap_err("Failed to create funded PSBT");
706 self.handle_err(format!("{err:?}"), "rbf_psbt_create_failed", try_to_send_id);
707
708 err
709 })?;
710
711 if !self.verify_new_inputs(&create_result.psbt, &tx) {
712 tracing::warn!(
713 ?try_to_send_id,
714 "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."
715 );
716 }
717
718 let mut psbt = Psbt::from_str(&create_result.psbt).map_err(|e| eyre!(e))?;
720 psbt.unsigned_tx.lock_time = tx.lock_time;
721 psbt.unsigned_tx.version = tx.version;
722
723 tracing::debug!(
724 try_to_send_id,
725 "Successfully created initial RBF PSBT with fee {}",
726 create_result.fee
727 );
728
729 let mut psbt = psbt.to_string();
730
731 self.fill_in_utxo_info(&mut psbt).await.map_err(|err| {
732 let err = eyre!(err).wrap_err("Failed to fill in utxo info");
733 self.handle_err(
734 format!("{err:?}"),
735 "rbf_fill_in_utxo_info_failed",
736 try_to_send_id,
737 );
738
739 err
740 })?;
741
742 psbt = self.copy_witnesses(psbt, &tx).await.map_err(|err| {
743 let err = eyre!(err).wrap_err("Failed to copy witnesses");
744 self.handle_err(
745 format!("{err:?}"),
746 "rbf_copy_witnesses_failed",
747 try_to_send_id,
748 );
749
750 err
751 })?;
752
753 let process_result = self
755 .rpc
756 .wallet_process_psbt(&psbt, Some(true), None, None)
757 .await
758 .map_err(|err| {
759 let err = eyre!(err).wrap_err("Failed to process initial RBF PSBT");
760 self.handle_err(
761 format!("{err:?}"),
762 "rbf_psbt_process_failed",
763 try_to_send_id,
764 );
765
766 err
767 })?;
768
769 if let Some(rbf_signing_info) = rbf_signing_info {
770 psbt = self
771 .attempt_sign_psbt(process_result.psbt, rbf_signing_info)
772 .await
773 .map_err(|err| {
774 let err = eyre!(err).wrap_err("Failed to sign initial RBF PSBT");
775 self.handle_err(format!("{err:?}"), "rbf_psbt_sign_failed", try_to_send_id);
776
777 err
778 })?;
779 } else {
780 psbt = process_result.psbt;
781 }
782
783 tracing::debug!(try_to_send_id, "Successfully processed initial RBF PSBT");
784
785 let final_tx = {
786 let psbt = Psbt::from_str(&psbt).map_err(|e| eyre!(e)).map_err(|err| {
788 let err = eyre!(err).wrap_err("Failed to deserialize initial RBF PSBT");
789 self.handle_err(
790 format!("{err:?}"),
791 "rbf_psbt_deserialize_failed",
792 try_to_send_id,
793 );
794 err
795 })?;
796
797 let mut tx = psbt.unsigned_tx.clone();
798
799 for (idx, input) in tx.input.iter_mut().enumerate() {
800 if let Some(witness) = psbt.inputs[idx].final_script_witness.clone() {
801 input.witness = witness;
802 }
803 if let Some(sig) = psbt.inputs[idx].final_script_sig.clone() {
804 input.script_sig = sig;
805 }
806 }
807
808 tx
809 };
810
811 let initial_txid = final_tx.compute_txid();
812
813 let sent_txid = match self.rpc.send_raw_transaction(&final_tx).await {
815 Ok(sent_txid) => {
816 if sent_txid != initial_txid {
817 let err_msg = format!(
818 "send_raw_transaction returned unexpected txid {sent_txid} (expected {initial_txid}) for initial RBF",
819 );
820 log_error_for_tx!(self.db, try_to_send_id, err_msg);
821 let _ = self
822 .db
823 .update_tx_debug_sending_state(
824 try_to_send_id,
825 "rbf_initial_send_txid_mismatch",
826 true,
827 )
828 .await;
829 return Err(SendTxError::Other(eyre!(err_msg)));
830 }
831 tracing::debug!(
832 try_to_send_id,
833 "Successfully sent initial RBF tx with txid {sent_txid}"
834 );
835 sent_txid
836 }
837 Err(e) => {
838 tracing::error!("RBF failed for: {:?}", final_tx);
839 let err_msg = format!("send_raw_transaction error for initial RBF tx: {e}");
840 log_error_for_tx!(self.db, try_to_send_id, err_msg);
841 let _ = self
842 .db
843 .update_tx_debug_sending_state(
844 try_to_send_id,
845 "rbf_initial_send_failed",
846 true,
847 )
848 .await;
849 return Err(SendTxError::Other(eyre!(e)));
850 }
851 };
852
853 let _ = self
855 .db
856 .update_tx_debug_sending_state(try_to_send_id, "rbf_initial_sent", true)
857 .await;
858
859 self.db
860 .save_rbf_txid(Some(&mut dbtx), try_to_send_id, sent_txid)
861 .await
862 .wrap_err("Failed to save initial RBF txid")?;
863 }
864
865 self.db
866 .commit_transaction(dbtx)
867 .await
868 .wrap_err("Failed to commit database transaction")?;
869
870 Ok(())
871 }
872}