Merge pull request #3063 from jirijakes/upgrade-bitcoin-031
[rust-lightning] / lightning / src / ln / channelmanager.rs
index a382b38ba6d6648a87246e04e4d0bc54138822ed..7bfeeac6def5cef5144c5a0fe536073ac2bd7c45 100644 (file)
@@ -21,7 +21,7 @@ use bitcoin::blockdata::block::Header;
 use bitcoin::blockdata::transaction::Transaction;
 use bitcoin::blockdata::constants::ChainHash;
 use bitcoin::key::constants::SECRET_KEY_SIZE;
-use bitcoin::network::constants::Network;
+use bitcoin::network::Network;
 
 use bitcoin::hashes::Hash;
 use bitcoin::hashes::sha256::Hash as Sha256;
@@ -681,6 +681,7 @@ struct ClaimingPayment {
        receiver_node_id: PublicKey,
        htlcs: Vec<events::ClaimedHTLC>,
        sender_intended_value: Option<u64>,
+       onion_fields: Option<RecipientOnionFields>,
 }
 impl_writeable_tlv_based!(ClaimingPayment, {
        (0, amount_msat, required),
@@ -688,6 +689,7 @@ impl_writeable_tlv_based!(ClaimingPayment, {
        (4, receiver_node_id, required),
        (5, htlcs, optional_vec),
        (7, sender_intended_value, option),
+       (9, onion_fields, option),
 });
 
 struct ClaimablePayment {
@@ -1168,7 +1170,7 @@ where
 ///
 /// ```
 /// use bitcoin::BlockHash;
-/// use bitcoin::network::constants::Network;
+/// use bitcoin::network::Network;
 /// use lightning::chain::BestBlock;
 /// # use lightning::chain::channelmonitor::ChannelMonitor;
 /// use lightning::ln::channelmanager::{ChainParameters, ChannelManager, ChannelManagerReadArgs};
@@ -4633,7 +4635,7 @@ where
                let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                let mut result = Ok(());
 
-               if !funding_transaction.is_coin_base() {
+               if !funding_transaction.is_coinbase() {
                        for inp in funding_transaction.input.iter() {
                                if inp.witness.is_empty() {
                                        result = result.and(Err(APIError::APIMisuseError {
@@ -4689,9 +4691,9 @@ where
                                is_batch_funding,
                                |chan, tx| {
                                        let mut output_index = None;
-                                       let expected_spk = chan.context.get_funding_redeemscript().to_v0_p2wsh();
+                                       let expected_spk = chan.context.get_funding_redeemscript().to_p2wsh();
                                        for (idx, outp) in tx.output.iter().enumerate() {
-                                               if outp.script_pubkey == expected_spk && outp.value == chan.context.get_value_satoshis() {
+                                               if outp.script_pubkey == expected_spk && outp.value.to_sat() == chan.context.get_value_satoshis() {
                                                        if output_index.is_some() {
                                                                return Err("Multiple outputs matched the expected script and value");
                                                        }
@@ -6325,19 +6327,27 @@ where
                                        }
                                }
 
-                               let htlcs = payment.htlcs.iter().map(events::ClaimedHTLC::from).collect();
-                               let sender_intended_value = payment.htlcs.first().map(|htlc| htlc.total_msat);
-                               let dup_purpose = claimable_payments.pending_claiming_payments.insert(payment_hash,
-                                       ClaimingPayment { amount_msat: payment.htlcs.iter().map(|source| source.value).sum(),
-                                       payment_purpose: payment.purpose, receiver_node_id, htlcs, sender_intended_value
-                               });
-                               if dup_purpose.is_some() {
-                                       debug_assert!(false, "Shouldn't get a duplicate pending claim event ever");
-                                       log_error!(self.logger, "Got a duplicate pending claimable event on payment hash {}! Please report this bug",
-                                               &payment_hash);
-                               }
+                               let claiming_payment = claimable_payments.pending_claiming_payments
+                                       .entry(payment_hash)
+                                       .and_modify(|_| {
+                                               debug_assert!(false, "Shouldn't get a duplicate pending claim event ever");
+                                               log_error!(self.logger, "Got a duplicate pending claimable event on payment hash {}! Please report this bug",
+                                                       &payment_hash);
+                                       })
+                                       .or_insert_with(|| {
+                                               let htlcs = payment.htlcs.iter().map(events::ClaimedHTLC::from).collect();
+                                               let sender_intended_value = payment.htlcs.first().map(|htlc| htlc.total_msat);
+                                               ClaimingPayment {
+                                                       amount_msat: payment.htlcs.iter().map(|source| source.value).sum(),
+                                                       payment_purpose: payment.purpose,
+                                                       receiver_node_id,
+                                                       htlcs,
+                                                       sender_intended_value,
+                                                       onion_fields: payment.onion_fields,
+                                               }
+                                       });
 
-                               if let Some(RecipientOnionFields { ref custom_tlvs, .. }) = payment.onion_fields {
+                               if let Some(RecipientOnionFields { ref custom_tlvs, .. }) = claiming_payment.onion_fields {
                                        if !custom_tlvs_known && custom_tlvs.iter().any(|(typ, _)| typ % 2 == 0) {
                                                log_info!(self.logger, "Rejecting payment with payment hash {} as we cannot accept payment with unknown even TLVs: {}",
                                                        &payment_hash, log_iter!(custom_tlvs.iter().map(|(typ, _)| typ).filter(|typ| *typ % 2 == 0)));
@@ -6744,6 +6754,7 @@ where
                                                receiver_node_id,
                                                htlcs,
                                                sender_intended_value: sender_intended_total_msat,
+                                               onion_fields,
                                        }) = payment {
                                                self.pending_events.lock().unwrap().push_back((events::Event::PaymentClaimed {
                                                        payment_hash,
@@ -6752,6 +6763,7 @@ where
                                                        receiver_node_id: Some(receiver_node_id),
                                                        htlcs,
                                                        sender_intended_total_msat,
+                                                       onion_fields,
                                                }, None));
                                        }
                                },
@@ -7251,7 +7263,7 @@ where
                                        match phase.get_mut() {
                                                ChannelPhase::UnfundedOutboundV1(chan) => {
                                                        try_chan_phase_entry!(self, chan.accept_channel(&msg, &self.default_configuration.channel_handshake_limits, &peer_state.latest_features), phase);
-                                                       (chan.context.get_value_satoshis(), chan.context.get_funding_redeemscript().to_v0_p2wsh(), chan.context.get_user_id())
+                                                       (chan.context.get_value_satoshis(), chan.context.get_funding_redeemscript().to_p2wsh(), chan.context.get_user_id())
                                                },
                                                _ => {
                                                        return Err(MsgHandleErrInternal::send_err_msg_no_close(format!("Got an unexpected accept_channel message from peer with counterparty_node_id {}", counterparty_node_id), msg.common_fields.temporary_channel_id));
@@ -9963,11 +9975,14 @@ where
                                                        }
                                                        &mut chan.context
                                                },
-                                               // We retain UnfundedOutboundV1 channel for some time in case
-                                               // peer unexpectedly disconnects, and intends to reconnect again.
-                                               ChannelPhase::UnfundedOutboundV1(_) => {
-                                                       return true;
-                                               },
+                                               // If we get disconnected and haven't yet committed to a funding
+                                               // transaction, we can replay the `open_channel` on reconnection, so don't
+                                               // bother dropping the channel here. However, if we already committed to
+                                               // the funding transaction we don't yet support replaying the funding
+                                               // handshake (and bailing if the peer rejects it), so we force-close in
+                                               // that case.
+                                               ChannelPhase::UnfundedOutboundV1(chan) if chan.is_resumable() => return true,
+                                               ChannelPhase::UnfundedOutboundV1(chan) => &mut chan.context,
                                                // Unfunded inbound channels will always be removed.
                                                ChannelPhase::UnfundedInboundV1(chan) => {
                                                        &mut chan.context
@@ -12270,6 +12285,7 @@ where
                                                amount_msat: claimable_amt_msat,
                                                htlcs: payment.htlcs.iter().map(events::ClaimedHTLC::from).collect(),
                                                sender_intended_total_msat: payment.htlcs.first().map(|htlc| htlc.total_msat),
+                                               onion_fields: payment.onion_fields,
                                        }, None));
                                }
                        }
@@ -13808,10 +13824,12 @@ pub mod bench {
        use crate::util::test_utils;
        use crate::util::config::{UserConfig, MaxDustHTLCExposure};
 
+       use bitcoin::amount::Amount;
        use bitcoin::blockdata::locktime::absolute::LockTime;
        use bitcoin::hashes::Hash;
        use bitcoin::hashes::sha256::Hash as Sha256;
        use bitcoin::{Transaction, TxOut};
+       use bitcoin::transaction::Version;
 
        use crate::sync::{Arc, Mutex, RwLock};
 
@@ -13888,8 +13906,8 @@ pub mod bench {
 
                let tx;
                if let Event::FundingGenerationReady { temporary_channel_id, output_script, .. } = get_event!(node_a_holder, Event::FundingGenerationReady) {
-                       tx = Transaction { version: 2, lock_time: LockTime::ZERO, input: Vec::new(), output: vec![TxOut {
-                               value: 8_000_000, script_pubkey: output_script,
+                       tx = Transaction { version: Version::TWO, lock_time: LockTime::ZERO, input: Vec::new(), output: vec![TxOut {
+                               value: Amount::from_sat(8_000_000), script_pubkey: output_script,
                        }]};
                        node_a.funding_transaction_generated(&temporary_channel_id, &node_b.get_our_node_id(), tx.clone()).unwrap();
                } else { panic!(); }