Skip to content

Commit 9a86016

Browse files
committed
Expose HTLC transaction construction helpers
1 parent 1ff227c commit 9a86016

File tree

1 file changed

+58
-30
lines changed

1 file changed

+58
-30
lines changed

lightning/src/ln/chan_utils.rs

Lines changed: 58 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -662,16 +662,38 @@ pub fn make_funding_redeemscript(broadcaster: &PublicKey, countersignatory: &Pub
662662
/// commitment transaction).
663663
pub fn build_htlc_transaction(commitment_txid: &Txid, feerate_per_kw: u32, contest_delay: u16, htlc: &HTLCOutputInCommitment, opt_anchors: bool, use_non_zero_fee_anchors: bool, broadcaster_delayed_payment_key: &PublicKey, revocation_key: &PublicKey) -> Transaction {
664664
let mut txins: Vec<TxIn> = Vec::new();
665-
txins.push(TxIn {
665+
txins.push(build_htlc_input(commitment_txid, htlc, opt_anchors));
666+
667+
let mut txouts: Vec<TxOut> = Vec::new();
668+
txouts.push(build_htlc_output(
669+
feerate_per_kw, contest_delay, htlc, opt_anchors, use_non_zero_fee_anchors,
670+
broadcaster_delayed_payment_key, revocation_key
671+
));
672+
673+
Transaction {
674+
version: 2,
675+
lock_time: PackedLockTime(if htlc.offered { htlc.cltv_expiry } else { 0 }),
676+
input: txins,
677+
output: txouts,
678+
}
679+
}
680+
681+
pub(crate) fn build_htlc_input(commitment_txid: &Txid, htlc: &HTLCOutputInCommitment, opt_anchors: bool) -> TxIn {
682+
TxIn {
666683
previous_output: OutPoint {
667684
txid: commitment_txid.clone(),
668685
vout: htlc.transaction_output_index.expect("Can't build an HTLC transaction for a dust output"),
669686
},
670687
script_sig: Script::new(),
671688
sequence: Sequence(if opt_anchors { 1 } else { 0 }),
672689
witness: Witness::new(),
673-
});
690+
}
691+
}
674692

693+
pub(crate) fn build_htlc_output(
694+
feerate_per_kw: u32, contest_delay: u16, htlc: &HTLCOutputInCommitment, opt_anchors: bool,
695+
use_non_zero_fee_anchors: bool, broadcaster_delayed_payment_key: &PublicKey, revocation_key: &PublicKey
696+
) -> TxOut {
675697
let weight = if htlc.offered {
676698
htlc_timeout_tx_weight(opt_anchors)
677699
} else {
@@ -684,18 +706,41 @@ pub fn build_htlc_transaction(commitment_txid: &Txid, feerate_per_kw: u32, conte
684706
htlc.amount_msat / 1000 - total_fee
685707
};
686708

687-
let mut txouts: Vec<TxOut> = Vec::new();
688-
txouts.push(TxOut {
709+
TxOut {
689710
script_pubkey: get_revokeable_redeemscript(revocation_key, contest_delay, broadcaster_delayed_payment_key).to_v0_p2wsh(),
690711
value: output_value,
691-
});
712+
}
713+
}
692714

693-
Transaction {
694-
version: 2,
695-
lock_time: PackedLockTime(if htlc.offered { htlc.cltv_expiry } else { 0 }),
696-
input: txins,
697-
output: txouts,
715+
/// Returns the witness required to satisfy and spend a HTLC input.
716+
pub fn build_htlc_input_witness(
717+
local_sig: &Signature, remote_sig: &Signature, preimage: &Option<PaymentPreimage>,
718+
redeem_script: &Script, opt_anchors: bool,
719+
) -> Witness {
720+
let remote_sighash_type = if opt_anchors {
721+
EcdsaSighashType::SinglePlusAnyoneCanPay
722+
} else {
723+
EcdsaSighashType::All
724+
};
725+
let mut remote_sig = remote_sig.serialize_der().to_vec();
726+
remote_sig.push(remote_sighash_type as u8);
727+
728+
let mut local_sig = local_sig.serialize_der().to_vec();
729+
local_sig.push(EcdsaSighashType::All as u8);
730+
731+
let mut witness = Witness::new();
732+
// First push the multisig dummy, note that due to BIP147 (NULLDUMMY) it must be a zero-length element.
733+
witness.push(vec![]);
734+
witness.push(remote_sig);
735+
witness.push(local_sig);
736+
if let Some(preimage) = preimage {
737+
witness.push(preimage.0.to_vec());
738+
} else {
739+
// Due to BIP146 (MINIMALIF) this must be a zero-length element to relay.
740+
witness.push(vec![]);
698741
}
742+
witness.push(redeem_script.to_bytes());
743+
witness
699744
}
700745

701746
/// Gets the witnessScript for the to_remote output when anchors are enabled.
@@ -1536,26 +1581,9 @@ impl<'a> TrustedCommitmentTransaction<'a> {
15361581

15371582
let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&this_htlc, self.opt_anchors(), &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key);
15381583

1539-
let sighashtype = if self.opt_anchors() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All };
1540-
1541-
// First push the multisig dummy, note that due to BIP147 (NULLDUMMY) it must be a zero-length element.
1542-
htlc_tx.input[0].witness.push(Vec::new());
1543-
1544-
let mut cp_sig_ser = counterparty_signature.serialize_der().to_vec();
1545-
cp_sig_ser.push(sighashtype as u8);
1546-
htlc_tx.input[0].witness.push(cp_sig_ser);
1547-
let mut holder_sig_ser = signature.serialize_der().to_vec();
1548-
holder_sig_ser.push(EcdsaSighashType::All as u8);
1549-
htlc_tx.input[0].witness.push(holder_sig_ser);
1550-
1551-
if this_htlc.offered {
1552-
// Due to BIP146 (MINIMALIF) this must be a zero-length element to relay.
1553-
htlc_tx.input[0].witness.push(Vec::new());
1554-
} else {
1555-
htlc_tx.input[0].witness.push(preimage.unwrap().0.to_vec());
1556-
}
1557-
1558-
htlc_tx.input[0].witness.push(htlc_redeemscript.as_bytes().to_vec());
1584+
htlc_tx.input[0].witness = chan_utils::build_htlc_input_witness(
1585+
signature, counterparty_signature, preimage, &htlc_redeemscript, self.opt_anchors(),
1586+
);
15591587
htlc_tx
15601588
}
15611589
}

0 commit comments

Comments
 (0)