+ pub(crate) fn add_holder_sig(&self, funding_redeemscript: &Script, holder_sig: Signature) -> Transaction {
+ // First push the multisig dummy, note that due to BIP147 (NULLDUMMY) it must be a zero-length element.
+ let mut tx = self.inner.built.transaction.clone();
+ tx.input[0].witness.push(Vec::new());
+
+ if self.holder_sig_first {
+ tx.input[0].witness.push_bitcoin_signature(&holder_sig.serialize_der(), EcdsaSighashType::All);
+ tx.input[0].witness.push_bitcoin_signature(&self.counterparty_sig.serialize_der(), EcdsaSighashType::All);
+ } else {
+ tx.input[0].witness.push_bitcoin_signature(&self.counterparty_sig.serialize_der(), EcdsaSighashType::All);
+ tx.input[0].witness.push_bitcoin_signature(&holder_sig.serialize_der(), EcdsaSighashType::All);
+ }
+
+ tx.input[0].witness.push(funding_redeemscript.as_bytes().to_vec());
+ tx
+ }
+}
+
+/// A pre-built Bitcoin commitment transaction and its txid.
+#[derive(Clone)]
+pub struct BuiltCommitmentTransaction {
+ /// The commitment transaction
+ pub transaction: Transaction,
+ /// The txid for the commitment transaction.
+ ///
+ /// This is provided as a performance optimization, instead of calling transaction.txid()
+ /// multiple times.
+ pub txid: Txid,
+}
+
+impl_writeable_tlv_based!(BuiltCommitmentTransaction, {
+ (0, transaction, required),
+ (2, txid, required),
+});
+
+impl BuiltCommitmentTransaction {
+ /// Get the SIGHASH_ALL sighash value of the transaction.
+ ///
+ /// This can be used to verify a signature.
+ pub fn get_sighash_all(&self, funding_redeemscript: &Script, channel_value_satoshis: u64) -> Message {
+ let sighash = &sighash::SighashCache::new(&self.transaction).segwit_signature_hash(0, funding_redeemscript, channel_value_satoshis, EcdsaSighashType::All).unwrap()[..];
+ hash_to_message!(sighash)
+ }
+
+ /// Sign a transaction, either because we are counter-signing the counterparty's transaction or
+ /// because we are about to broadcast a holder transaction.
+ pub fn sign<T: secp256k1::Signing>(&self, funding_key: &SecretKey, funding_redeemscript: &Script, channel_value_satoshis: u64, secp_ctx: &Secp256k1<T>) -> Signature {
+ let sighash = self.get_sighash_all(funding_redeemscript, channel_value_satoshis);
+ sign(secp_ctx, &sighash, funding_key)
+ }
+}
+
+/// This class tracks the per-transaction information needed to build a closing transaction and will
+/// actually build it and sign.
+///
+/// This class can be used inside a signer implementation to generate a signature given the relevant
+/// secret key.
+#[derive(Clone, Hash, PartialEq, Eq)]
+pub struct ClosingTransaction {
+ to_holder_value_sat: u64,
+ to_counterparty_value_sat: u64,
+ to_holder_script: Script,
+ to_counterparty_script: Script,
+ built: Transaction,
+}
+
+impl ClosingTransaction {
+ /// Construct an object of the class
+ pub fn new(
+ to_holder_value_sat: u64,
+ to_counterparty_value_sat: u64,
+ to_holder_script: Script,
+ to_counterparty_script: Script,
+ funding_outpoint: OutPoint,
+ ) -> Self {
+ let built = build_closing_transaction(
+ to_holder_value_sat, to_counterparty_value_sat,
+ to_holder_script.clone(), to_counterparty_script.clone(),
+ funding_outpoint
+ );
+ ClosingTransaction {
+ to_holder_value_sat,
+ to_counterparty_value_sat,
+ to_holder_script,
+ to_counterparty_script,
+ built
+ }
+ }
+
+ /// Trust our pre-built transaction.
+ ///
+ /// Applies a wrapper which allows access to the transaction.
+ ///
+ /// 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) -> TrustedClosingTransaction {
+ TrustedClosingTransaction { inner: self }
+ }
+
+ /// Verify our pre-built transaction.
+ ///
+ /// Applies a wrapper which allows access to the transaction.
+ ///
+ /// An external validating signer must call this method before signing
+ /// or using the built transaction.
+ pub fn verify(&self, funding_outpoint: OutPoint) -> Result<TrustedClosingTransaction, ()> {
+ let built = build_closing_transaction(
+ self.to_holder_value_sat, self.to_counterparty_value_sat,
+ self.to_holder_script.clone(), self.to_counterparty_script.clone(),
+ funding_outpoint
+ );
+ if self.built != built {
+ return Err(())
+ }
+ Ok(TrustedClosingTransaction { inner: self })
+ }
+
+ /// The value to be sent to the holder, or zero if the output will be omitted
+ pub fn to_holder_value_sat(&self) -> u64 {
+ self.to_holder_value_sat
+ }
+
+ /// The value to be sent to the counterparty, or zero if the output will be omitted
+ pub fn to_counterparty_value_sat(&self) -> u64 {
+ self.to_counterparty_value_sat
+ }
+
+ /// The destination of the holder's output
+ pub fn to_holder_script(&self) -> &Script {
+ &self.to_holder_script
+ }
+
+ /// The destination of the counterparty's output
+ pub fn to_counterparty_script(&self) -> &Script {
+ &self.to_counterparty_script
+ }
+}
+
+/// A wrapper on ClosingTransaction indicating that the built bitcoin
+/// transaction is trusted.
+///
+/// See trust() and verify() functions on CommitmentTransaction.
+///
+/// This structure implements Deref.
+pub struct TrustedClosingTransaction<'a> {
+ inner: &'a ClosingTransaction,
+}
+
+impl<'a> Deref for TrustedClosingTransaction<'a> {
+ type Target = ClosingTransaction;
+
+ fn deref(&self) -> &Self::Target { self.inner }
+}
+
+impl<'a> TrustedClosingTransaction<'a> {
+ /// The pre-built Bitcoin commitment transaction
+ pub fn built_transaction(&self) -> &Transaction {
+ &self.inner.built
+ }
+
+ /// Get the SIGHASH_ALL sighash value of the transaction.
+ ///
+ /// This can be used to verify a signature.
+ pub fn get_sighash_all(&self, funding_redeemscript: &Script, channel_value_satoshis: u64) -> Message {
+ let sighash = &sighash::SighashCache::new(&self.inner.built).segwit_signature_hash(0, funding_redeemscript, channel_value_satoshis, EcdsaSighashType::All).unwrap()[..];
+ hash_to_message!(sighash)
+ }
+
+ /// Sign a transaction, either because we are counter-signing the counterparty's transaction or
+ /// because we are about to broadcast a holder transaction.
+ pub fn sign<T: secp256k1::Signing>(&self, funding_key: &SecretKey, funding_redeemscript: &Script, channel_value_satoshis: u64, secp_ctx: &Secp256k1<T>) -> Signature {
+ let sighash = self.get_sighash_all(funding_redeemscript, channel_value_satoshis);
+ sign(secp_ctx, &sighash, funding_key)
+ }
+}
+
+/// This class tracks the per-transaction information needed to build a commitment transaction and will
+/// actually build it and sign. It is used for holder transactions that we sign only when needed
+/// and for transactions we sign for the counterparty.
+///
+/// This class can be used inside a signer implementation to generate a signature given the relevant
+/// secret key.
+#[derive(Clone)]
+pub struct CommitmentTransaction {
+ commitment_number: u64,
+ to_broadcaster_value_sat: u64,
+ to_countersignatory_value_sat: u64,
+ feerate_per_kw: u32,
+ htlcs: Vec<HTLCOutputInCommitment>,
+ // A boolean that is serialization backwards-compatible
+ opt_anchors: Option<()>,
+ // Whether non-zero-fee anchors should be used
+ opt_non_zero_fee_anchors: Option<()>,
+ // A cache of the parties' pubkeys required to construct the transaction, see doc for trust()
+ keys: TxCreationKeys,
+ // For access to the pre-built transaction, see doc for trust()
+ built: BuiltCommitmentTransaction,
+}
+
+impl Eq for CommitmentTransaction {}
+impl PartialEq for CommitmentTransaction {
+ fn eq(&self, o: &Self) -> bool {
+ let eq = self.commitment_number == o.commitment_number &&
+ self.to_broadcaster_value_sat == o.to_broadcaster_value_sat &&
+ self.to_countersignatory_value_sat == o.to_countersignatory_value_sat &&
+ self.feerate_per_kw == o.feerate_per_kw &&
+ self.htlcs == o.htlcs &&
+ self.opt_anchors == o.opt_anchors &&
+ self.keys == o.keys;
+ if eq {
+ debug_assert_eq!(self.built.transaction, o.built.transaction);
+ debug_assert_eq!(self.built.txid, o.built.txid);
+ }
+ eq
+ }
+}
+
+impl_writeable_tlv_based!(CommitmentTransaction, {
+ (0, commitment_number, required),
+ (2, to_broadcaster_value_sat, required),
+ (4, to_countersignatory_value_sat, required),
+ (6, feerate_per_kw, required),
+ (8, keys, required),
+ (10, built, required),
+ (12, htlcs, vec_type),
+ (14, opt_anchors, option),
+ (16, opt_non_zero_fee_anchors, option),
+});
+
+impl CommitmentTransaction {
+ /// Construct an object of the class while assigning transaction output indices to HTLCs.
+ ///
+ /// Populates HTLCOutputInCommitment.transaction_output_index in htlcs_with_aux.
+ ///
+ /// The generic T allows the caller to match the HTLC output index with auxiliary data.
+ /// This auxiliary data is not stored in this object.
+ ///
+ /// Only include HTLCs that are above the dust limit for the channel.
+ ///
+ /// (C-not exported) due to the generic though we likely should expose a version without
+ pub fn new_with_auxiliary_htlc_data<T>(commitment_number: u64, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, opt_anchors: bool, broadcaster_funding_key: PublicKey, countersignatory_funding_key: PublicKey, keys: TxCreationKeys, feerate_per_kw: u32, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters) -> CommitmentTransaction {
+ // Sort outputs and populate output indices while keeping track of the auxiliary data
+ let (outputs, htlcs) = Self::internal_build_outputs(&keys, to_broadcaster_value_sat, to_countersignatory_value_sat, htlcs_with_aux, channel_parameters, opt_anchors, &broadcaster_funding_key, &countersignatory_funding_key).unwrap();
+
+ let (obscured_commitment_transaction_number, txins) = Self::internal_build_inputs(commitment_number, channel_parameters);
+ let transaction = Self::make_transaction(obscured_commitment_transaction_number, txins, outputs);
+ let txid = transaction.txid();
+ CommitmentTransaction {
+ commitment_number,
+ to_broadcaster_value_sat,
+ to_countersignatory_value_sat,
+ feerate_per_kw,
+ htlcs,
+ opt_anchors: if opt_anchors { Some(()) } else { None },
+ keys,
+ built: BuiltCommitmentTransaction {
+ transaction,
+ txid
+ },
+ opt_non_zero_fee_anchors: None,
+ }
+ }
+
+ /// Use non-zero fee anchors
+ ///
+ /// (C-not exported) due to move, and also not likely to be useful for binding users
+ pub fn with_non_zero_fee_anchors(mut self) -> Self {
+ self.opt_non_zero_fee_anchors = Some(());
+ self
+ }
+
+ fn internal_rebuild_transaction(&self, keys: &TxCreationKeys, channel_parameters: &DirectedChannelTransactionParameters, broadcaster_funding_key: &PublicKey, countersignatory_funding_key: &PublicKey) -> Result<BuiltCommitmentTransaction, ()> {
+ let (obscured_commitment_transaction_number, txins) = Self::internal_build_inputs(self.commitment_number, channel_parameters);
+
+ let mut htlcs_with_aux = self.htlcs.iter().map(|h| (h.clone(), ())).collect();
+ let (outputs, _) = Self::internal_build_outputs(keys, self.to_broadcaster_value_sat, self.to_countersignatory_value_sat, &mut htlcs_with_aux, channel_parameters, self.opt_anchors.is_some(), broadcaster_funding_key, countersignatory_funding_key)?;
+
+ let transaction = Self::make_transaction(obscured_commitment_transaction_number, txins, outputs);
+ let txid = transaction.txid();
+ let built_transaction = BuiltCommitmentTransaction {
+ transaction,
+ txid
+ };
+ Ok(built_transaction)
+ }
+
+ fn make_transaction(obscured_commitment_transaction_number: u64, txins: Vec<TxIn>, outputs: Vec<TxOut>) -> Transaction {
+ Transaction {
+ version: 2,
+ lock_time: PackedLockTime(((0x20 as u32) << 8 * 3) | ((obscured_commitment_transaction_number & 0xffffffu64) as u32)),
+ input: txins,
+ output: outputs,
+ }
+ }
+
+ // 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 {
+ Payload::p2wpkh(&BitcoinPublicKey::new(countersignatory_pubkeys.payment_point)).unwrap().script_pubkey()
+ };
+ 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: 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);
+ 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);
+
+ 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(), self.opt_non_zero_fee_anchors.is_some(), &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(), self.opt_non_zero_fee_anchors.is_some(), &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);
+
+ htlc_tx.input[0].witness = chan_utils::build_htlc_input_witness(
+ signature, counterparty_signature, preimage, &htlc_redeemscript, self.opt_anchors(),
+ );
+ 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)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::CounterpartyCommitmentSecrets;
+ use crate::{hex, chain};
+ use crate::prelude::*;
+ use crate::ln::chan_utils::{get_htlc_redeemscript, get_to_countersignatory_with_anchors_redeemscript, CommitmentTransaction, TxCreationKeys, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, HTLCOutputInCommitment};
+ use bitcoin::secp256k1::{PublicKey, SecretKey, Secp256k1};
+ use crate::util::test_utils;
+ use crate::chain::keysinterface::{BaseSign, SignerProvider};
+ use bitcoin::{Network, Txid};
+ use bitcoin::hashes::Hash;
+ use crate::ln::PaymentHash;
+ use bitcoin::hashes::hex::ToHex;
+ use bitcoin::util::address::Payload;
+ use bitcoin::PublicKey as BitcoinPublicKey;
+
+ #[test]
+ fn test_anchors() {
+ let secp_ctx = Secp256k1::new();
+
+ let seed = [42; 32];
+ let network = Network::Testnet;
+ let keys_provider = test_utils::TestKeysInterface::new(&seed, network);
+ let signer = keys_provider.derive_channel_signer(3000, keys_provider.generate_channel_keys_id(false, 1_000_000, 0));
+ let counterparty_signer = keys_provider.derive_channel_signer(3000, keys_provider.generate_channel_keys_id(true, 1_000_000, 1));
+ let delayed_payment_base = &signer.pubkeys().delayed_payment_basepoint;
+ let per_commitment_secret = SecretKey::from_slice(&hex::decode("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100").unwrap()[..]).unwrap();
+ let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &per_commitment_secret);
+ let htlc_basepoint = &signer.pubkeys().htlc_basepoint;
+ let holder_pubkeys = signer.pubkeys();
+ let counterparty_pubkeys = counterparty_signer.pubkeys();
+ let keys = TxCreationKeys::derive_new(&secp_ctx, &per_commitment_point, delayed_payment_base, htlc_basepoint, &counterparty_pubkeys.revocation_basepoint, &counterparty_pubkeys.htlc_basepoint);
+ let mut channel_parameters = ChannelTransactionParameters {
+ holder_pubkeys: holder_pubkeys.clone(),
+ holder_selected_contest_delay: 0,
+ is_outbound_from_holder: false,
+ counterparty_parameters: Some(CounterpartyChannelTransactionParameters { pubkeys: counterparty_pubkeys.clone(), selected_contest_delay: 0 }),
+ funding_outpoint: Some(chain::transaction::OutPoint { txid: Txid::all_zeros(), index: 0 }),
+ opt_anchors: None,
+ opt_non_zero_fee_anchors: None,
+ };
+
+ let mut htlcs_with_aux: Vec<(_, ())> = Vec::new();
+
+ // Generate broadcaster and counterparty outputs
+ let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(
+ 0, 1000, 2000,
+ false,
+ holder_pubkeys.funding_pubkey,
+ counterparty_pubkeys.funding_pubkey,
+ keys.clone(), 1,
+ &mut htlcs_with_aux, &channel_parameters.as_holder_broadcastable()
+ );
+ assert_eq!(tx.built.transaction.output.len(), 2);
+ assert_eq!(tx.built.transaction.output[1].script_pubkey, Payload::p2wpkh(&BitcoinPublicKey::new(counterparty_pubkeys.payment_point)).unwrap().script_pubkey());
+
+ // Generate broadcaster and counterparty outputs as well as two anchors
+ let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(
+ 0, 1000, 2000,
+ true,
+ holder_pubkeys.funding_pubkey,
+ counterparty_pubkeys.funding_pubkey,
+ keys.clone(), 1,
+ &mut htlcs_with_aux, &channel_parameters.as_holder_broadcastable()
+ );
+ assert_eq!(tx.built.transaction.output.len(), 4);
+ assert_eq!(tx.built.transaction.output[3].script_pubkey, get_to_countersignatory_with_anchors_redeemscript(&counterparty_pubkeys.payment_point).to_v0_p2wsh());
+
+ // Generate broadcaster output and anchor
+ let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(
+ 0, 3000, 0,
+ true,
+ holder_pubkeys.funding_pubkey,
+ counterparty_pubkeys.funding_pubkey,
+ keys.clone(), 1,
+ &mut htlcs_with_aux, &channel_parameters.as_holder_broadcastable()
+ );
+ assert_eq!(tx.built.transaction.output.len(), 2);
+
+ // Generate counterparty output and anchor
+ let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(
+ 0, 0, 3000,
+ true,
+ holder_pubkeys.funding_pubkey,
+ counterparty_pubkeys.funding_pubkey,
+ keys.clone(), 1,
+ &mut htlcs_with_aux, &channel_parameters.as_holder_broadcastable()
+ );
+ assert_eq!(tx.built.transaction.output.len(), 2);
+
+ let received_htlc = HTLCOutputInCommitment {
+ offered: false,
+ amount_msat: 400000,
+ cltv_expiry: 100,
+ payment_hash: PaymentHash([42; 32]),
+ transaction_output_index: None,
+ };
+
+ let offered_htlc = HTLCOutputInCommitment {
+ offered: true,
+ amount_msat: 600000,
+ cltv_expiry: 100,
+ payment_hash: PaymentHash([43; 32]),
+ transaction_output_index: None,
+ };
+
+ // Generate broadcaster output and received and offered HTLC outputs, w/o anchors
+ let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(
+ 0, 3000, 0,
+ false,
+ holder_pubkeys.funding_pubkey,
+ counterparty_pubkeys.funding_pubkey,
+ keys.clone(), 1,
+ &mut vec![(received_htlc.clone(), ()), (offered_htlc.clone(), ())],
+ &channel_parameters.as_holder_broadcastable()
+ );
+ assert_eq!(tx.built.transaction.output.len(), 3);
+ assert_eq!(tx.built.transaction.output[0].script_pubkey, get_htlc_redeemscript(&received_htlc, false, &keys).to_v0_p2wsh());
+ assert_eq!(tx.built.transaction.output[1].script_pubkey, get_htlc_redeemscript(&offered_htlc, false, &keys).to_v0_p2wsh());
+ assert_eq!(get_htlc_redeemscript(&received_htlc, false, &keys).to_v0_p2wsh().to_hex(),
+ "0020e43a7c068553003fe68fcae424fb7b28ec5ce48cd8b6744b3945631389bad2fb");
+ assert_eq!(get_htlc_redeemscript(&offered_htlc, false, &keys).to_v0_p2wsh().to_hex(),
+ "0020215d61bba56b19e9eadb6107f5a85d7f99c40f65992443f69229c290165bc00d");
+
+ // Generate broadcaster output and received and offered HTLC outputs, with anchors
+ channel_parameters.opt_anchors = Some(());
+ let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(
+ 0, 3000, 0,
+ true,
+ holder_pubkeys.funding_pubkey,
+ counterparty_pubkeys.funding_pubkey,
+ keys.clone(), 1,
+ &mut vec![(received_htlc.clone(), ()), (offered_htlc.clone(), ())],
+ &channel_parameters.as_holder_broadcastable()
+ );
+ assert_eq!(tx.built.transaction.output.len(), 5);
+ assert_eq!(tx.built.transaction.output[2].script_pubkey, get_htlc_redeemscript(&received_htlc, true, &keys).to_v0_p2wsh());
+ assert_eq!(tx.built.transaction.output[3].script_pubkey, get_htlc_redeemscript(&offered_htlc, true, &keys).to_v0_p2wsh());
+ assert_eq!(get_htlc_redeemscript(&received_htlc, true, &keys).to_v0_p2wsh().to_hex(),
+ "0020b70d0649c72b38756885c7a30908d912a7898dd5d79457a7280b8e9a20f3f2bc");
+ assert_eq!(get_htlc_redeemscript(&offered_htlc, true, &keys).to_v0_p2wsh().to_hex(),
+ "002087a3faeb1950a469c0e2db4a79b093a41b9526e5a6fc6ef5cb949bde3be379c7");
+ }
+
+ #[test]
+ fn test_per_commitment_storage() {
+ // Test vectors from BOLT 3:
+ let mut secrets: Vec<[u8; 32]> = Vec::new();
+ let mut monitor;
+
+ macro_rules! test_secrets {
+ () => {
+ let mut idx = 281474976710655;
+ for secret in secrets.iter() {
+ assert_eq!(monitor.get_secret(idx).unwrap(), *secret);
+ idx -= 1;
+ }
+ assert_eq!(monitor.get_min_seen_secret(), idx + 1);
+ assert!(monitor.get_secret(idx).is_none());
+ };
+ }
+
+ {
+ // insert_secret correct sequence
+ monitor = CounterpartyCommitmentSecrets::new();
+ secrets.clear();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
+ monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
+ monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
+ monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
+ monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c65716add7aa98ba7acb236352d665cab17345fe45b55fb879ff80e6bd0c41dd").unwrap());
+ monitor.provide_secret(281474976710651, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap());
+ monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("a5a64476122ca0925fb344bdc1854c1c0a59fc614298e50a33e331980a220f32").unwrap());
+ monitor.provide_secret(281474976710649, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17").unwrap());
+ monitor.provide_secret(281474976710648, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+ }
+
+ {
+ // insert_secret #1 incorrect
+ monitor = CounterpartyCommitmentSecrets::new();
+ secrets.clear();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148").unwrap());
+ monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
+ assert!(monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).is_err());
+ }
+
+ {
+ // insert_secret #2 incorrect (#1 derived from incorrect)
+ monitor = CounterpartyCommitmentSecrets::new();
+ secrets.clear();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148").unwrap());
+ monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("dddc3a8d14fddf2b68fa8c7fbad2748274937479dd0f8930d5ebb4ab6bd866a3").unwrap());
+ monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
+ monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
+ assert!(monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).is_err());
+ }
+
+ {
+ // insert_secret #3 incorrect
+ monitor = CounterpartyCommitmentSecrets::new();
+ secrets.clear();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
+ monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
+ monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c51a18b13e8527e579ec56365482c62f180b7d5760b46e9477dae59e87ed423a").unwrap());
+ monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
+ assert!(monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).is_err());
+ }
+
+ {
+ // insert_secret #4 incorrect (1,2,3 derived from incorrect)
+ monitor = CounterpartyCommitmentSecrets::new();
+ secrets.clear();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148").unwrap());
+ monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("dddc3a8d14fddf2b68fa8c7fbad2748274937479dd0f8930d5ebb4ab6bd866a3").unwrap());
+ monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c51a18b13e8527e579ec56365482c62f180b7d5760b46e9477dae59e87ed423a").unwrap());
+ monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("ba65d7b0ef55a3ba300d4e87af29868f394f8f138d78a7011669c79b37b936f4").unwrap());
+ monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c65716add7aa98ba7acb236352d665cab17345fe45b55fb879ff80e6bd0c41dd").unwrap());
+ monitor.provide_secret(281474976710651, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap());
+ monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("a5a64476122ca0925fb344bdc1854c1c0a59fc614298e50a33e331980a220f32").unwrap());
+ monitor.provide_secret(281474976710649, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17").unwrap());
+ assert!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone()).is_err());
+ }
+
+ {
+ // insert_secret #5 incorrect
+ monitor = CounterpartyCommitmentSecrets::new();
+ secrets.clear();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
+ monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
+ monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
+ monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
+ monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("631373ad5f9ef654bb3dade742d09504c567edd24320d2fcd68e3cc47e2ff6a6").unwrap());
+ monitor.provide_secret(281474976710651, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap());
+ assert!(monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).is_err());
+ }
+
+ {
+ // insert_secret #6 incorrect (5 derived from incorrect)
+ monitor = CounterpartyCommitmentSecrets::new();
+ secrets.clear();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
+ monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
+ monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
+ monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
+ monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("631373ad5f9ef654bb3dade742d09504c567edd24320d2fcd68e3cc47e2ff6a6").unwrap());
+ monitor.provide_secret(281474976710651, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("b7e76a83668bde38b373970155c868a653304308f9896692f904a23731224bb1").unwrap());
+ monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("a5a64476122ca0925fb344bdc1854c1c0a59fc614298e50a33e331980a220f32").unwrap());
+ monitor.provide_secret(281474976710649, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17").unwrap());
+ assert!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone()).is_err());
+ }
+
+ {
+ // insert_secret #7 incorrect
+ monitor = CounterpartyCommitmentSecrets::new();
+ secrets.clear();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
+ monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
+ monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
+ monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
+ monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c65716add7aa98ba7acb236352d665cab17345fe45b55fb879ff80e6bd0c41dd").unwrap());
+ monitor.provide_secret(281474976710651, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap());
+ monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("e7971de736e01da8ed58b94c2fc216cb1dca9e326f3a96e7194fe8ea8af6c0a3").unwrap());
+ monitor.provide_secret(281474976710649, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17").unwrap());
+ assert!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone()).is_err());
+ }
+
+ {
+ // insert_secret #8 incorrect
+ monitor = CounterpartyCommitmentSecrets::new();
+ secrets.clear();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
+ monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
+ monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
+ monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
+ monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c65716add7aa98ba7acb236352d665cab17345fe45b55fb879ff80e6bd0c41dd").unwrap());
+ monitor.provide_secret(281474976710651, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap());
+ monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("a5a64476122ca0925fb344bdc1854c1c0a59fc614298e50a33e331980a220f32").unwrap());
+ monitor.provide_secret(281474976710649, secrets.last().unwrap().clone()).unwrap();
+ test_secrets!();
+
+ secrets.push([0; 32]);
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("a7efbc61aac46d34f77778bac22c8a20c6a46ca460addc49009bda875ec88fa4").unwrap());
+ assert!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone()).is_err());
+ }