+
+ pub(super) fn provide_latest_holder_tx(&mut self, tx: HolderCommitmentTransaction) {
+ self.prev_holder_commitment = self.holder_commitment.take();
+ self.holder_commitment = Some(tx);
+ }
+
+ fn sign_latest_holder_htlcs(&mut self) {
+ if let Some(ref holder_commitment) = self.holder_commitment {
+ if let Ok(sigs) = self.key_storage.sign_holder_commitment_htlc_transactions(holder_commitment, &self.secp_ctx) {
+ self.holder_htlc_sigs = Some(Vec::new());
+ let ret = self.holder_htlc_sigs.as_mut().unwrap();
+ for (htlc_idx, (holder_sig, &(ref htlc, _))) in sigs.iter().zip(holder_commitment.per_htlc.iter()).enumerate() {
+ if let Some(tx_idx) = htlc.transaction_output_index {
+ if ret.len() <= tx_idx as usize { ret.resize(tx_idx as usize + 1, None); }
+ ret[tx_idx as usize] = Some((htlc_idx, holder_sig.expect("Did not receive a signature for a non-dust HTLC")));
+ } else {
+ assert!(holder_sig.is_none(), "Received a signature for a dust HTLC");
+ }
+ }
+ }
+ }
+ }
+ fn sign_prev_holder_htlcs(&mut self) {
+ if let Some(ref holder_commitment) = self.prev_holder_commitment {
+ if let Ok(sigs) = self.key_storage.sign_holder_commitment_htlc_transactions(holder_commitment, &self.secp_ctx) {
+ self.prev_holder_htlc_sigs = Some(Vec::new());
+ let ret = self.prev_holder_htlc_sigs.as_mut().unwrap();
+ for (htlc_idx, (holder_sig, &(ref htlc, _))) in sigs.iter().zip(holder_commitment.per_htlc.iter()).enumerate() {
+ if let Some(tx_idx) = htlc.transaction_output_index {
+ if ret.len() <= tx_idx as usize { ret.resize(tx_idx as usize + 1, None); }
+ ret[tx_idx as usize] = Some((htlc_idx, holder_sig.expect("Did not receive a signature for a non-dust HTLC")));
+ } else {
+ assert!(holder_sig.is_none(), "Received a signature for a dust HTLC");
+ }
+ }
+ }
+ }
+ }
+
+ //TODO: getting lastest holder transactions should be infaillible and result in us "force-closing the channel", but we may
+ // have empty holder commitment transaction if a ChannelMonitor is asked to force-close just after Channel::get_outbound_funding_created,
+ // before providing a initial commitment transaction. For outbound channel, init ChannelMonitor at Channel::funding_signed, there is nothing
+ // to monitor before.
+ pub(super) fn get_fully_signed_holder_tx(&mut self, funding_redeemscript: &Script) -> Option<Transaction> {
+ if let Some(ref mut holder_commitment) = self.holder_commitment {
+ match self.key_storage.sign_holder_commitment(holder_commitment, &self.secp_ctx) {
+ Ok(sig) => Some(holder_commitment.add_holder_sig(funding_redeemscript, sig)),
+ Err(_) => return None,
+ }
+ } else {
+ None
+ }
+ }
+
+ #[cfg(any(test, feature="unsafe_revoked_tx_signing"))]
+ pub(super) fn get_fully_signed_copy_holder_tx(&mut self, funding_redeemscript: &Script) -> Option<Transaction> {
+ if let Some(ref mut holder_commitment) = self.holder_commitment {
+ let holder_commitment = holder_commitment.clone();
+ match self.key_storage.sign_holder_commitment(&holder_commitment, &self.secp_ctx) {
+ Ok(sig) => Some(holder_commitment.add_holder_sig(funding_redeemscript, sig)),
+ Err(_) => return None,
+ }
+ } else {
+ None
+ }
+ }
+
+ pub(super) fn get_fully_signed_htlc_tx(&mut self, outp: &::bitcoin::OutPoint, preimage: &Option<PaymentPreimage>) -> Option<Transaction> {
+ let mut htlc_tx = None;
+ if self.holder_commitment.is_some() {
+ let commitment_txid = self.holder_commitment.as_ref().unwrap().txid();
+ if commitment_txid == outp.txid {
+ self.sign_latest_holder_htlcs();
+ if let &Some(ref htlc_sigs) = &self.holder_htlc_sigs {
+ let &(ref htlc_idx, ref htlc_sig) = htlc_sigs[outp.vout as usize].as_ref().unwrap();
+ htlc_tx = Some(self.holder_commitment.as_ref().unwrap()
+ .get_signed_htlc_tx(*htlc_idx, htlc_sig, preimage, self.on_holder_tx_csv));
+ }
+ }
+ }
+ if self.prev_holder_commitment.is_some() {
+ let commitment_txid = self.prev_holder_commitment.as_ref().unwrap().txid();
+ if commitment_txid == outp.txid {
+ self.sign_prev_holder_htlcs();
+ if let &Some(ref htlc_sigs) = &self.prev_holder_htlc_sigs {
+ let &(ref htlc_idx, ref htlc_sig) = htlc_sigs[outp.vout as usize].as_ref().unwrap();
+ htlc_tx = Some(self.prev_holder_commitment.as_ref().unwrap()
+ .get_signed_htlc_tx(*htlc_idx, htlc_sig, preimage, self.on_holder_tx_csv));
+ }
+ }
+ }
+ htlc_tx
+ }
+
+ #[cfg(any(test,feature = "unsafe_revoked_tx_signing"))]
+ pub(super) fn unsafe_get_fully_signed_htlc_tx(&mut self, outp: &::bitcoin::OutPoint, preimage: &Option<PaymentPreimage>) -> Option<Transaction> {
+ let latest_had_sigs = self.holder_htlc_sigs.is_some();
+ let prev_had_sigs = self.prev_holder_htlc_sigs.is_some();
+ let ret = self.get_fully_signed_htlc_tx(outp, preimage);
+ if !latest_had_sigs {
+ self.holder_htlc_sigs = None;
+ }
+ if !prev_had_sigs {
+ self.prev_holder_htlc_sigs = None;
+ }
+ ret
+ }