Skip to content

Commit bd09cd4

Browse files
committed
Change WalletSource::sign_tx to sign_psbt
1 parent fcf47a4 commit bd09cd4

File tree

2 files changed

+45
-12
lines changed

2 files changed

+45
-12
lines changed

lightning/src/events/bump_transaction.rs

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ use bitcoin::{OutPoint, PubkeyHash, Sequence, ScriptBuf, Transaction, TxIn, TxOu
3535
use bitcoin::blockdata::constants::WITNESS_SCALE_FACTOR;
3636
use bitcoin::blockdata::locktime::absolute::LockTime;
3737
use bitcoin::consensus::Encodable;
38+
use bitcoin::psbt::PartiallySignedTransaction;
3839
use bitcoin::secp256k1;
3940
use bitcoin::secp256k1::Secp256k1;
4041
use bitcoin::secp256k1::ecdsa::Signature;
@@ -343,7 +344,7 @@ pub trait CoinSelectionSource {
343344
) -> Result<CoinSelection, ()>;
344345
/// Signs and provides the full witness for all inputs within the transaction known to the
345346
/// trait (i.e., any provided via [`CoinSelectionSource::select_confirmed_utxos`]).
346-
fn sign_tx(&self, tx: Transaction) -> Result<Transaction, ()>;
347+
fn sign_psbt(&self, tx: PartiallySignedTransaction) -> Result<Transaction, ()>;
347348
}
348349

349350
/// An alternative to [`CoinSelectionSource`] that can be implemented and used along [`Wallet`] to
@@ -357,7 +358,7 @@ pub trait WalletSource {
357358
/// Signs and provides the full [`TxIn::script_sig`] and [`TxIn::witness`] for all inputs within
358359
/// the transaction known to the wallet (i.e., any provided via
359360
/// [`WalletSource::list_confirmed_utxos`]).
360-
fn sign_tx(&self, tx: Transaction) -> Result<Transaction, ()>;
361+
fn sign_psbt(&self, psbt: PartiallySignedTransaction) -> Result<Transaction, ()>;
361362
}
362363

363364
/// A wrapper over [`WalletSource`] that implements [`CoinSelection`] by preferring UTXOs that would
@@ -504,8 +505,8 @@ where
504505
.or_else(|_| do_coin_selection(true, true))
505506
}
506507

507-
fn sign_tx(&self, tx: Transaction) -> Result<Transaction, ()> {
508-
self.source.sign_tx(tx)
508+
fn sign_psbt(&self, psbt: PartiallySignedTransaction) -> Result<Transaction, ()> {
509+
self.source.sign_psbt(psbt)
509510
}
510511
}
511512

@@ -549,16 +550,16 @@ where
549550
}
550551

551552
/// Updates a transaction with the result of a successful coin selection attempt.
552-
fn process_coin_selection(&self, tx: &mut Transaction, mut coin_selection: CoinSelection) {
553-
for utxo in coin_selection.confirmed_utxos.drain(..) {
553+
fn process_coin_selection(&self, tx: &mut Transaction, coin_selection: &CoinSelection) {
554+
for utxo in coin_selection.confirmed_utxos.iter() {
554555
tx.input.push(TxIn {
555556
previous_output: utxo.outpoint,
556557
script_sig: ScriptBuf::new(),
557558
sequence: Sequence::ZERO,
558559
witness: Witness::new(),
559560
});
560561
}
561-
if let Some(change_output) = coin_selection.change_output.take() {
562+
if let Some(change_output) = coin_selection.change_output.clone() {
562563
tx.output.push(change_output);
563564
} else if tx.output.is_empty() {
564565
// We weren't provided a change output, likely because the input set was a perfect
@@ -613,15 +614,28 @@ where
613614
let total_input_amount = must_spend_amount +
614615
coin_selection.confirmed_utxos.iter().map(|utxo| utxo.output.value).sum::<u64>();
615616

616-
self.process_coin_selection(&mut anchor_tx, coin_selection);
617+
self.process_coin_selection(&mut anchor_tx, &coin_selection);
617618
let anchor_txid = anchor_tx.txid();
618619

620+
// construct psbt
621+
let mut anchor_psbt = PartiallySignedTransaction::from_unsigned_tx(anchor_tx.clone()).unwrap();
622+
// add witness_utxo to anchor input
623+
anchor_psbt.inputs[0].witness_utxo = Some(anchor_descriptor.previous_utxo());
624+
// add witness_utxo to remaining inputs
625+
for (idx, utxo) in coin_selection.confirmed_utxos.into_iter().enumerate() {
626+
// add 1 to skip the anchor input
627+
let index = idx + 1;
628+
debug_assert_eq!(anchor_psbt.unsigned_tx.input[index].previous_output, utxo.outpoint);
629+
anchor_psbt.inputs[index].witness_utxo = Some(utxo.output);
630+
}
631+
619632
debug_assert_eq!(anchor_tx.output.len(), 1);
620633
#[cfg(debug_assertions)]
621634
let unsigned_tx_weight = anchor_tx.weight().to_wu() - (anchor_tx.input.len() as u64 * EMPTY_SCRIPT_SIG_WEIGHT);
622635

623636
log_debug!(self.logger, "Signing anchor transaction {}", anchor_txid);
624-
anchor_tx = self.utxo_source.sign_tx(anchor_tx)?;
637+
debug_assert!(anchor_psbt.inputs.iter().all(|i| i.witness_utxo.is_some()));
638+
anchor_tx = self.utxo_source.sign_psbt(anchor_psbt)?;
625639

626640
let signer = anchor_descriptor.derive_channel_signer(&self.signer_provider);
627641
let anchor_sig = signer.sign_holder_anchor_input(&anchor_tx, 0, &self.secp)?;
@@ -701,13 +715,29 @@ where
701715
let total_input_amount = must_spend_amount +
702716
coin_selection.confirmed_utxos.iter().map(|utxo| utxo.output.value).sum::<u64>();
703717

704-
self.process_coin_selection(&mut htlc_tx, coin_selection);
718+
self.process_coin_selection(&mut htlc_tx, &coin_selection);
719+
720+
// construct psbt
721+
let mut htlc_psbt = PartiallySignedTransaction::from_unsigned_tx(htlc_tx.clone()).unwrap();
722+
// add witness_utxo to htlc inputs
723+
for (i, htlc_descriptor) in htlc_descriptors.iter().enumerate() {
724+
debug_assert_eq!(htlc_psbt.unsigned_tx.input[i].previous_output, htlc_descriptor.outpoint());
725+
htlc_psbt.inputs[i].witness_utxo = Some(htlc_descriptor.previous_utxo(&self.secp));
726+
}
727+
// add witness_utxo to remaining inputs
728+
for (idx, utxo) in coin_selection.confirmed_utxos.into_iter().enumerate() {
729+
// offset to skip the htlc inputs
730+
let index = idx + htlc_descriptors.len();
731+
debug_assert_eq!(htlc_psbt.unsigned_tx.input[index].previous_output, utxo.outpoint);
732+
htlc_psbt.inputs[index].witness_utxo = Some(utxo.output);
733+
}
705734

706735
#[cfg(debug_assertions)]
707736
let unsigned_tx_weight = htlc_tx.weight().to_wu() - (htlc_tx.input.len() as u64 * EMPTY_SCRIPT_SIG_WEIGHT);
708737

709738
log_debug!(self.logger, "Signing HTLC transaction {}", htlc_tx.txid());
710-
htlc_tx = self.utxo_source.sign_tx(htlc_tx)?;
739+
debug_assert!(htlc_psbt.inputs.iter().all(|i| i.witness_utxo.is_some()));
740+
htlc_tx = self.utxo_source.sign_psbt(htlc_psbt)?;
711741

712742
let mut signers = BTreeMap::new();
713743
for (idx, htlc_descriptor) in htlc_descriptors.iter().enumerate() {

lightning/src/util/test_utils.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ use crate::sign::{InMemorySigner, Recipient, EntropySource, NodeSigner, SignerPr
7171

7272
#[cfg(feature = "std")]
7373
use std::time::{SystemTime, UNIX_EPOCH};
74+
use bitcoin::psbt::PartiallySignedTransaction;
7475
use bitcoin::Sequence;
7576

7677
pub fn pubkey(byte: u8) -> PublicKey {
@@ -1410,7 +1411,8 @@ impl WalletSource for TestWalletSource {
14101411
Ok(ScriptBuf::new_p2pkh(&public_key.pubkey_hash()))
14111412
}
14121413

1413-
fn sign_tx(&self, mut tx: Transaction) -> Result<Transaction, ()> {
1414+
fn sign_psbt(&self, mut psbt: PartiallySignedTransaction) -> Result<Transaction, ()> {
1415+
let mut tx = psbt.extract_tx();
14141416
let utxos = self.utxos.borrow();
14151417
for i in 0..tx.input.len() {
14161418
if let Some(utxo) = utxos.iter().find(|utxo| utxo.outpoint == tx.input[i].previous_output) {
@@ -1425,6 +1427,7 @@ impl WalletSource for TestWalletSource {
14251427
.into_script();
14261428
}
14271429
}
1430+
14281431
Ok(tx)
14291432
}
14301433
}

0 commit comments

Comments
 (0)