+
+ // This is used in two cases:
+ // - initial sorting of outputs / HTLCs in the constructor, in which case T is auxiliary data the
+ // caller needs to have sorted together with the HTLCs so it can keep track of the output index
+ // - building of a bitcoin transaction during a verify() call, in which case T is just ()
+ fn internal_build_outputs<T>(keys: &TxCreationKeys, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters, opt_anchors: bool, broadcaster_funding_key: &PublicKey, countersignatory_funding_key: &PublicKey) -> Result<(Vec<TxOut>, Vec<HTLCOutputInCommitment>), ()> {
+ let countersignatory_pubkeys = channel_parameters.countersignatory_pubkeys();
+ let contest_delay = channel_parameters.contest_delay();
+
+ let mut txouts: Vec<(TxOut, Option<&mut HTLCOutputInCommitment>)> = Vec::new();
+
+ if to_countersignatory_value_sat > 0 {
+ let script = if opt_anchors {
+ get_to_countersignatory_with_anchors_redeemscript(&countersignatory_pubkeys.payment_point).to_v0_p2wsh()
+ } else {
+ get_p2wpkh_redeemscript(&countersignatory_pubkeys.payment_point)
+ };
+ txouts.push((
+ TxOut {
+ script_pubkey: script.clone(),
+ value: to_countersignatory_value_sat,
+ },
+ None,
+ ))
+ }
+
+ if to_broadcaster_value_sat > 0 {
+ let redeem_script = get_revokeable_redeemscript(
+ &keys.revocation_key,
+ contest_delay,
+ &keys.broadcaster_delayed_payment_key,
+ );
+ txouts.push((
+ TxOut {
+ script_pubkey: redeem_script.to_v0_p2wsh(),
+ value: to_broadcaster_value_sat,
+ },
+ None,
+ ));
+ }
+
+ if opt_anchors {
+ if to_broadcaster_value_sat > 0 || !htlcs_with_aux.is_empty() {
+ let anchor_script = get_anchor_redeemscript(broadcaster_funding_key);
+ txouts.push((
+ TxOut {
+ script_pubkey: anchor_script.to_v0_p2wsh(),
+ value: ANCHOR_OUTPUT_VALUE_SATOSHI,
+ },
+ None,
+ ));
+ }
+
+ if to_countersignatory_value_sat > 0 || !htlcs_with_aux.is_empty() {
+ let anchor_script = get_anchor_redeemscript(countersignatory_funding_key);
+ txouts.push((
+ TxOut {
+ script_pubkey: anchor_script.to_v0_p2wsh(),
+ value: ANCHOR_OUTPUT_VALUE_SATOSHI,
+ },
+ None,
+ ));
+ }
+ }
+
+ let mut htlcs = Vec::with_capacity(htlcs_with_aux.len());
+ for (htlc, _) in htlcs_with_aux {
+ let script = chan_utils::get_htlc_redeemscript(&htlc, opt_anchors, &keys);
+ let txout = TxOut {
+ script_pubkey: script.to_v0_p2wsh(),
+ value: htlc.amount_msat / 1000,
+ };
+ txouts.push((txout, Some(htlc)));
+ }
+
+ // Sort output in BIP-69 order (amount, scriptPubkey). Tie-breaks based on HTLC
+ // CLTV expiration height.
+ sort_outputs(&mut txouts, |a, b| {
+ if let &Some(ref a_htlcout) = a {
+ if let &Some(ref b_htlcout) = b {
+ a_htlcout.cltv_expiry.cmp(&b_htlcout.cltv_expiry)
+ // Note that due to hash collisions, we have to have a fallback comparison
+ // here for fuzzing mode (otherwise at least chanmon_fail_consistency
+ // may fail)!
+ .then(a_htlcout.payment_hash.0.cmp(&b_htlcout.payment_hash.0))
+ // For non-HTLC outputs, if they're copying our SPK we don't really care if we
+ // close the channel due to mismatches - they're doing something dumb:
+ } else { cmp::Ordering::Equal }
+ } else { cmp::Ordering::Equal }
+ });
+
+ let mut outputs = Vec::with_capacity(txouts.len());
+ for (idx, out) in txouts.drain(..).enumerate() {
+ if let Some(htlc) = out.1 {
+ htlc.transaction_output_index = Some(idx as u32);
+ htlcs.push(htlc.clone());
+ }
+ outputs.push(out.0);
+ }
+ Ok((outputs, htlcs))
+ }
+
+ fn internal_build_inputs(commitment_number: u64, channel_parameters: &DirectedChannelTransactionParameters) -> (u64, Vec<TxIn>) {
+ let broadcaster_pubkeys = channel_parameters.broadcaster_pubkeys();
+ let countersignatory_pubkeys = channel_parameters.countersignatory_pubkeys();
+ let commitment_transaction_number_obscure_factor = get_commitment_transaction_number_obscure_factor(
+ &broadcaster_pubkeys.payment_point,
+ &countersignatory_pubkeys.payment_point,
+ channel_parameters.is_outbound(),
+ );
+
+ let obscured_commitment_transaction_number =
+ commitment_transaction_number_obscure_factor ^ (INITIAL_COMMITMENT_NUMBER - commitment_number);
+
+ let txins = {
+ let mut ins: Vec<TxIn> = Vec::new();
+ ins.push(TxIn {
+ previous_output: channel_parameters.funding_outpoint(),
+ script_sig: Script::new(),
+ sequence: ((0x80 as u32) << 8 * 3)
+ | ((obscured_commitment_transaction_number >> 3 * 8) as u32),
+ witness: Witness::new(),
+ });
+ ins
+ };
+ (obscured_commitment_transaction_number, txins)
+ }
+
+ /// The backwards-counting commitment number
+ pub fn commitment_number(&self) -> u64 {
+ self.commitment_number
+ }
+
+ /// The value to be sent to the broadcaster
+ pub fn to_broadcaster_value_sat(&self) -> u64 {
+ self.to_broadcaster_value_sat
+ }
+
+ /// The value to be sent to the counterparty
+ pub fn to_countersignatory_value_sat(&self) -> u64 {
+ self.to_countersignatory_value_sat
+ }
+
+ /// The feerate paid per 1000-weight-unit in this commitment transaction.
+ pub fn feerate_per_kw(&self) -> u32 {
+ self.feerate_per_kw
+ }
+
+ /// The non-dust HTLCs (direction, amt, height expiration, hash, transaction output index)
+ /// which were included in this commitment transaction in output order.
+ /// The transaction index is always populated.
+ ///
+ /// (C-not exported) as we cannot currently convert Vec references to/from C, though we should
+ /// expose a less effecient version which creates a Vec of references in the future.
+ pub fn htlcs(&self) -> &Vec<HTLCOutputInCommitment> {
+ &self.htlcs
+ }
+
+ /// Trust our pre-built transaction and derived transaction creation public keys.
+ ///
+ /// Applies a wrapper which allows access to these fields.
+ ///
+ /// This should only be used if you fully trust the builder of this object. It should not
+ /// be used by an external signer - instead use the verify function.
+ pub fn trust(&self) -> TrustedCommitmentTransaction {
+ TrustedCommitmentTransaction { inner: self }
+ }
+
+ /// Verify our pre-built transaction and derived transaction creation public keys.
+ ///
+ /// Applies a wrapper which allows access to these fields.
+ ///
+ /// An external validating signer must call this method before signing
+ /// or using the built transaction.
+ pub fn verify<T: secp256k1::Signing + secp256k1::Verification>(&self, channel_parameters: &DirectedChannelTransactionParameters, broadcaster_keys: &ChannelPublicKeys, countersignatory_keys: &ChannelPublicKeys, secp_ctx: &Secp256k1<T>) -> Result<TrustedCommitmentTransaction, ()> {
+ // This is the only field of the key cache that we trust
+ let per_commitment_point = self.keys.per_commitment_point;
+ let keys = TxCreationKeys::from_channel_static_keys(&per_commitment_point, broadcaster_keys, countersignatory_keys, secp_ctx).unwrap();
+ if keys != self.keys {
+ return Err(());
+ }
+ let tx = self.internal_rebuild_transaction(&keys, channel_parameters, &broadcaster_keys.funding_pubkey, &countersignatory_keys.funding_pubkey)?;
+ if self.built.transaction != tx.transaction || self.built.txid != tx.txid {
+ return Err(());
+ }
+ Ok(TrustedCommitmentTransaction { inner: self })
+ }
+}
+
+/// A wrapper on CommitmentTransaction indicating that the derived fields (the built bitcoin
+/// transaction and the transaction creation keys) are trusted.
+///
+/// See trust() and verify() functions on CommitmentTransaction.
+///
+/// This structure implements Deref.
+pub struct TrustedCommitmentTransaction<'a> {
+ inner: &'a CommitmentTransaction,
+}
+
+impl<'a> Deref for TrustedCommitmentTransaction<'a> {
+ type Target = CommitmentTransaction;
+
+ fn deref(&self) -> &Self::Target { self.inner }
+}
+
+impl<'a> TrustedCommitmentTransaction<'a> {
+ /// The transaction ID of the built Bitcoin transaction
+ pub fn txid(&self) -> Txid {
+ self.inner.built.txid
+ }
+
+ /// The pre-built Bitcoin commitment transaction
+ pub fn built_transaction(&self) -> &BuiltCommitmentTransaction {
+ &self.inner.built
+ }
+
+ /// The pre-calculated transaction creation public keys.
+ pub fn keys(&self) -> &TxCreationKeys {
+ &self.inner.keys
+ }
+
+ /// Should anchors be used.
+ pub fn opt_anchors(&self) -> bool {
+ self.opt_anchors.is_some()
+ }
+
+ /// Get a signature for each HTLC which was included in the commitment transaction (ie for
+ /// which HTLCOutputInCommitment::transaction_output_index.is_some()).
+ ///
+ /// The returned Vec has one entry for each HTLC, and in the same order.
+ ///
+ /// This function is only valid in the holder commitment context, it always uses EcdsaSighashType::All.
+ pub fn get_htlc_sigs<T: secp256k1::Signing>(&self, htlc_base_key: &SecretKey, channel_parameters: &DirectedChannelTransactionParameters, secp_ctx: &Secp256k1<T>) -> Result<Vec<Signature>, ()> {
+ let inner = self.inner;
+ let keys = &inner.keys;
+ let txid = inner.built.txid;
+ let mut ret = Vec::with_capacity(inner.htlcs.len());
+ let holder_htlc_key = derive_private_key(secp_ctx, &inner.keys.per_commitment_point, htlc_base_key).map_err(|_| ())?;
+
+ for this_htlc in inner.htlcs.iter() {
+ assert!(this_htlc.transaction_output_index.is_some());
+ let htlc_tx = build_htlc_transaction(&txid, inner.feerate_per_kw, channel_parameters.contest_delay(), &this_htlc, self.opt_anchors(), &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
+
+ 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);
+
+ let sighash = hash_to_message!(&sighash::SighashCache::new(&htlc_tx).segwit_signature_hash(0, &htlc_redeemscript, this_htlc.amount_msat / 1000, EcdsaSighashType::All).unwrap()[..]);
+ ret.push(sign(secp_ctx, &sighash, &holder_htlc_key));
+ }
+ Ok(ret)
+ }
+
+ /// Gets a signed HTLC transaction given a preimage (for !htlc.offered) and the holder HTLC transaction signature.
+ pub(crate) fn get_signed_htlc_tx(&self, channel_parameters: &DirectedChannelTransactionParameters, htlc_index: usize, counterparty_signature: &Signature, signature: &Signature, preimage: &Option<PaymentPreimage>) -> Transaction {
+ let inner = self.inner;
+ let keys = &inner.keys;
+ let txid = inner.built.txid;
+ let this_htlc = &inner.htlcs[htlc_index];
+ assert!(this_htlc.transaction_output_index.is_some());
+ // if we don't have preimage for an HTLC-Success, we can't generate an HTLC transaction.
+ if !this_htlc.offered && preimage.is_none() { unreachable!(); }
+ // Further, we should never be provided the preimage for an HTLC-Timeout transaction.
+ if this_htlc.offered && preimage.is_some() { unreachable!(); }
+
+ let mut htlc_tx = build_htlc_transaction(&txid, inner.feerate_per_kw, channel_parameters.contest_delay(), &this_htlc, self.opt_anchors(), &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
+
+ 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);
+
+ let sighashtype = if self.opt_anchors() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All };
+
+ // First push the multisig dummy, note that due to BIP147 (NULLDUMMY) it must be a zero-length element.
+ htlc_tx.input[0].witness.push(Vec::new());
+
+ let mut cp_sig_ser = counterparty_signature.serialize_der().to_vec();
+ cp_sig_ser.push(sighashtype as u8);
+ htlc_tx.input[0].witness.push(cp_sig_ser);
+ let mut holder_sig_ser = signature.serialize_der().to_vec();
+ holder_sig_ser.push(EcdsaSighashType::All as u8);
+ htlc_tx.input[0].witness.push(holder_sig_ser);
+
+ if this_htlc.offered {
+ // Due to BIP146 (MINIMALIF) this must be a zero-length element to relay.
+ htlc_tx.input[0].witness.push(Vec::new());
+ } else {
+ htlc_tx.input[0].witness.push(preimage.unwrap().0.to_vec());
+ }
+
+ htlc_tx.input[0].witness.push(htlc_redeemscript.as_bytes().to_vec());
+ htlc_tx
+ }
+}
+
+/// Commitment transaction numbers which appear in the transactions themselves are XOR'd with a
+/// shared secret first. This prevents on-chain observers from discovering how many commitment
+/// transactions occurred in a channel before it was closed.
+///
+/// This function gets the shared secret from relevant channel public keys and can be used to
+/// "decrypt" the commitment transaction number given a commitment transaction on-chain.
+pub fn get_commitment_transaction_number_obscure_factor(
+ broadcaster_payment_basepoint: &PublicKey,
+ countersignatory_payment_basepoint: &PublicKey,
+ outbound_from_broadcaster: bool,
+) -> u64 {
+ let mut sha = Sha256::engine();
+
+ if outbound_from_broadcaster {
+ sha.input(&broadcaster_payment_basepoint.serialize());
+ sha.input(&countersignatory_payment_basepoint.serialize());
+ } else {
+ sha.input(&countersignatory_payment_basepoint.serialize());
+ sha.input(&broadcaster_payment_basepoint.serialize());
+ }
+ let res = Sha256::from_engine(sha).into_inner();
+
+ ((res[26] as u64) << 5 * 8)
+ | ((res[27] as u64) << 4 * 8)
+ | ((res[28] as u64) << 3 * 8)
+ | ((res[29] as u64) << 2 * 8)
+ | ((res[30] as u64) << 1 * 8)
+ | ((res[31] as u64) << 0 * 8)
+}
+
+fn get_p2wpkh_redeemscript(key: &PublicKey) -> Script {
+ Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0)
+ .push_slice(&WPubkeyHash::hash(&key.serialize())[..])
+ .into_script()