Skip to content

Commit c17ce2e

Browse files
committed
Expose HTLC transaction construction helpers
1 parent 0aaba2c commit c17ce2e

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
@@ -679,16 +679,38 @@ pub fn make_funding_redeemscript(broadcaster: &PublicKey, countersignatory: &Pub
679679
/// commitment transaction).
680680
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 {
681681
let mut txins: Vec<TxIn> = Vec::new();
682-
txins.push(TxIn {
682+
txins.push(build_htlc_input(commitment_txid, htlc, opt_anchors));
683+
684+
let mut txouts: Vec<TxOut> = Vec::new();
685+
txouts.push(build_htlc_output(
686+
feerate_per_kw, contest_delay, htlc, opt_anchors, use_non_zero_fee_anchors,
687+
broadcaster_delayed_payment_key, revocation_key
688+
));
689+
690+
Transaction {
691+
version: 2,
692+
lock_time: PackedLockTime(if htlc.offered { htlc.cltv_expiry } else { 0 }),
693+
input: txins,
694+
output: txouts,
695+
}
696+
}
697+
698+
pub(crate) fn build_htlc_input(commitment_txid: &Txid, htlc: &HTLCOutputInCommitment, opt_anchors: bool) -> TxIn {
699+
TxIn {
683700
previous_output: OutPoint {
684701
txid: commitment_txid.clone(),
685702
vout: htlc.transaction_output_index.expect("Can't build an HTLC transaction for a dust output"),
686703
},
687704
script_sig: Script::new(),
688705
sequence: Sequence(if opt_anchors { 1 } else { 0 }),
689706
witness: Witness::new(),
690-
});
707+
}
708+
}
691709

710+
pub(crate) fn build_htlc_output(
711+
feerate_per_kw: u32, contest_delay: u16, htlc: &HTLCOutputInCommitment, opt_anchors: bool,
712+
use_non_zero_fee_anchors: bool, broadcaster_delayed_payment_key: &PublicKey, revocation_key: &PublicKey
713+
) -> TxOut {
692714
let weight = if htlc.offered {
693715
htlc_timeout_tx_weight(opt_anchors)
694716
} else {
@@ -701,18 +723,41 @@ pub fn build_htlc_transaction(commitment_txid: &Txid, feerate_per_kw: u32, conte
701723
htlc.amount_msat / 1000 - total_fee
702724
};
703725

704-
let mut txouts: Vec<TxOut> = Vec::new();
705-
txouts.push(TxOut {
726+
TxOut {
706727
script_pubkey: get_revokeable_redeemscript(revocation_key, contest_delay, broadcaster_delayed_payment_key).to_v0_p2wsh(),
707728
value: output_value,
708-
});
729+
}
730+
}
709731

710-
Transaction {
711-
version: 2,
712-
lock_time: PackedLockTime(if htlc.offered { htlc.cltv_expiry } else { 0 }),
713-
input: txins,
714-
output: txouts,
732+
/// Returns the witness required to satisfy and spend a HTLC input.
733+
pub fn build_htlc_input_witness(
734+
local_sig: &Signature, remote_sig: &Signature, preimage: &Option<PaymentPreimage>,
735+
redeem_script: &Script, opt_anchors: bool,
736+
) -> Witness {
737+
let remote_sighash_type = if opt_anchors {
738+
EcdsaSighashType::SinglePlusAnyoneCanPay
739+
} else {
740+
EcdsaSighashType::All
741+
};
742+
let mut remote_sig = remote_sig.serialize_der().to_vec();
743+
remote_sig.push(remote_sighash_type as u8);
744+
745+
let mut local_sig = local_sig.serialize_der().to_vec();
746+
local_sig.push(EcdsaSighashType::All as u8);
747+
748+
let mut witness = Witness::new();
749+
// First push the multisig dummy, note that due to BIP147 (NULLDUMMY) it must be a zero-length element.
750+
witness.push(vec![]);
751+
witness.push(remote_sig);
752+
witness.push(local_sig);
753+
if let Some(preimage) = preimage {
754+
witness.push(preimage.0.to_vec());
755+
} else {
756+
// Due to BIP146 (MINIMALIF) this must be a zero-length element to relay.
757+
witness.push(vec![]);
715758
}
759+
witness.push(redeem_script.to_bytes());
760+
witness
716761
}
717762

718763
/// Gets the witnessScript for the to_remote output when anchors are enabled.
@@ -1553,26 +1598,9 @@ impl<'a> TrustedCommitmentTransaction<'a> {
15531598

15541599
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);
15551600

1556-
let sighashtype = if self.opt_anchors() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All };
1557-
1558-
// First push the multisig dummy, note that due to BIP147 (NULLDUMMY) it must be a zero-length element.
1559-
htlc_tx.input[0].witness.push(Vec::new());
1560-
1561-
let mut cp_sig_ser = counterparty_signature.serialize_der().to_vec();
1562-
cp_sig_ser.push(sighashtype as u8);
1563-
htlc_tx.input[0].witness.push(cp_sig_ser);
1564-
let mut holder_sig_ser = signature.serialize_der().to_vec();
1565-
holder_sig_ser.push(EcdsaSighashType::All as u8);
1566-
htlc_tx.input[0].witness.push(holder_sig_ser);
1567-
1568-
if this_htlc.offered {
1569-
// Due to BIP146 (MINIMALIF) this must be a zero-length element to relay.
1570-
htlc_tx.input[0].witness.push(Vec::new());
1571-
} else {
1572-
htlc_tx.input[0].witness.push(preimage.unwrap().0.to_vec());
1573-
}
1574-
1575-
htlc_tx.input[0].witness.push(htlc_redeemscript.as_bytes().to_vec());
1601+
htlc_tx.input[0].witness = chan_utils::build_htlc_input_witness(
1602+
signature, counterparty_signature, preimage, &htlc_redeemscript, self.opt_anchors(),
1603+
);
15761604
htlc_tx
15771605
}
15781606
}

0 commit comments

Comments
 (0)