Merge pull request #2621 from G8XSU/dont-persist-erroneous-update
authorMatt Corallo <649246+TheBlueMatt@users.noreply.github.com>
Fri, 29 Sep 2023 23:45:57 +0000 (23:45 +0000)
committerGitHub <noreply@github.com>
Fri, 29 Sep 2023 23:45:57 +0000 (23:45 +0000)
Persist entire monitor if there is an error while applying monitor_update

20 files changed:
fuzz/src/router.rs
lightning-persister/src/fs_store.rs
lightning/src/chain/chainmonitor.rs
lightning/src/chain/channelmonitor.rs
lightning/src/events/bump_transaction.rs
lightning/src/events/mod.rs
lightning/src/ln/chan_utils.rs
lightning/src/ln/channel.rs
lightning/src/ln/channelmanager.rs
lightning/src/ln/functional_tests.rs
lightning/src/ln/monitor_tests.rs
lightning/src/ln/outbound_payment.rs
lightning/src/ln/reload_tests.rs
lightning/src/ln/reorg_tests.rs
lightning/src/ln/shutdown_tests.rs
lightning/src/routing/router.rs
lightning/src/sign/mod.rs
lightning/src/sign/type_resolver.rs
lightning/src/util/test_utils.rs
pending_changelog/remove_balance_msat.txt [deleted file]

index b7d45bf729f4d6c488c5916de536a5cf6f02f6dc..7f4e7ad401904716cbe01b3a258a3e752a43128a 100644 (file)
@@ -233,6 +233,7 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
                                                        force_close_spend_delay: None,
                                                        is_outbound: true, is_channel_ready: true,
                                                        is_usable: true, is_public: true,
+                                                       balance_msat: 0,
                                                        outbound_capacity_msat: capacity.saturating_mul(1000),
                                                        next_outbound_htlc_limit_msat: capacity.saturating_mul(1000),
                                                        next_outbound_htlc_minimum_msat: 0,
index 3475544849f9420398851818c0d805c4d7f48e6f..c665d8083cb194e2934263e6eef982585bb37b67 100644 (file)
@@ -436,7 +436,7 @@ mod tests {
        }
 
        // Test that if the store's path to channel data is read-only, writing a
-       // monitor to it results in the store returning an InProgress.
+       // monitor to it results in the store returning an UnrecoverableError.
        // Windows ignores the read-only flag for folders, so this test is Unix-only.
        #[cfg(not(target_os = "windows"))]
        #[test]
@@ -458,7 +458,7 @@ mod tests {
                let update_id = update_map.get(&added_monitors[0].0.to_channel_id()).unwrap();
 
                // Set the store's directory to read-only, which should result in
-               // returning a permanent failure when we then attempt to persist a
+               // returning an unrecoverable failure when we then attempt to persist a
                // channel update.
                let path = &store.get_data_dir();
                let mut perms = fs::metadata(path).unwrap().permissions();
index d70ebd40d667ad840c012197484d4f94d1f2ced4..261c0471ca4089dfaa1d21ca0e8c8f810f90c7a5 100644 (file)
@@ -110,7 +110,7 @@ impl MonitorUpdateId {
 ///    If at some point no further progress can be made towards persisting the pending updates, the
 ///    node should simply shut down.
 ///
-///  * If the persistence has failed and cannot be retried further (e.g. because of some timeout),
+///  * If the persistence has failed and cannot be retried further (e.g. because of an outage),
 ///    [`ChannelMonitorUpdateStatus::UnrecoverableError`] can be used, though this will result in
 ///    an immediate panic and future operations in LDK generally failing.
 ///
@@ -125,7 +125,10 @@ impl MonitorUpdateId {
 ///  [`ChainMonitor::channel_monitor_updated`] must be called once for *each* update which occurs.
 ///
 ///  If at some point no further progress can be made towards persisting a pending update, the node
-///  should simply shut down.
+///  should simply shut down. Until then, the background task should either loop indefinitely, or
+///  persistence should be regularly retried with [`ChainMonitor::list_pending_monitor_updates`]
+///  and [`ChainMonitor::get_monitor`] (note that if a full monitor is persisted all pending
+///  monitor updates may be marked completed).
 ///
 /// # Using remote watchtowers
 ///
@@ -432,7 +435,8 @@ where C::Target: chain::Filter,
        /// claims which are awaiting confirmation.
        ///
        /// Includes the balances from each [`ChannelMonitor`] *except* those included in
-       /// `ignored_channels`.
+       /// `ignored_channels`, allowing you to filter out balances from channels which are still open
+       /// (and whose balance should likely be pulled from the [`ChannelDetails`]).
        ///
        /// See [`ChannelMonitor::get_claimable_balances`] for more details on the exact criteria for
        /// inclusion in the return value.
index 3f9c83bb54393290c40b9a6784bcce7dd48c53da..25bfa14d5420ac266b6254acfaba55b1c2e413ce 100644 (file)
 
 use bitcoin::blockdata::block::BlockHeader;
 use bitcoin::blockdata::transaction::{OutPoint as BitcoinOutPoint, TxOut, Transaction};
-use bitcoin::blockdata::script::{Script, Builder};
-use bitcoin::blockdata::opcodes;
+use bitcoin::blockdata::script::Script;
 
 use bitcoin::hashes::Hash;
 use bitcoin::hashes::sha256::Hash as Sha256;
-use bitcoin::hash_types::{Txid, BlockHash, WPubkeyHash};
+use bitcoin::hash_types::{Txid, BlockHash};
 
 use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature};
 use bitcoin::secp256k1::{SecretKey, PublicKey};
@@ -1141,8 +1140,9 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
                          best_block: BestBlock, counterparty_node_id: PublicKey) -> ChannelMonitor<Signer> {
 
                assert!(commitment_transaction_number_obscure_factor <= (1 << 48));
-               let payment_key_hash = WPubkeyHash::hash(&keys.pubkeys().payment_point.serialize());
-               let counterparty_payment_script = Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&payment_key_hash[..]).into_script();
+               let counterparty_payment_script = chan_utils::get_counterparty_payment_script(
+                       &channel_parameters.channel_type_features, &keys.pubkeys().payment_point
+               );
 
                let counterparty_channel_parameters = channel_parameters.counterparty_parameters.as_ref().unwrap();
                let counterparty_delayed_payment_base_key = counterparty_channel_parameters.pubkeys.delayed_payment_basepoint;
@@ -1669,6 +1669,49 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
                        current_height, &broadcaster, &fee_estimator, &logger,
                );
        }
+
+       /// Returns the descriptors for relevant outputs (i.e., those that we can spend) within the
+       /// transaction if they exist and the transaction has at least [`ANTI_REORG_DELAY`]
+       /// confirmations. For [`SpendableOutputDescriptor::DelayedPaymentOutput`] descriptors to be
+       /// returned, the transaction must have at least `max(ANTI_REORG_DELAY, to_self_delay)`
+       /// confirmations.
+       ///
+       /// Descriptors returned by this method are primarily exposed via [`Event::SpendableOutputs`]
+       /// once they are no longer under reorg risk. This method serves as a way to retrieve these
+       /// descriptors at a later time, either for historical purposes, or to replay any
+       /// missed/unhandled descriptors. For the purpose of gathering historical records, if the
+       /// channel close has fully resolved (i.e., [`ChannelMonitor::get_claimable_balances`] returns
+       /// an empty set), you can retrieve all spendable outputs by providing all descendant spending
+       /// transactions starting from the channel's funding transaction and going down three levels.
+       ///
+       /// `tx` is a transaction we'll scan the outputs of. Any transaction can be provided. If any
+       /// outputs which can be spent by us are found, at least one descriptor is returned.
+       ///
+       /// `confirmation_height` must be the height of the block in which `tx` was included in.
+       pub fn get_spendable_outputs(&self, tx: &Transaction, confirmation_height: u32) -> Vec<SpendableOutputDescriptor> {
+               let inner = self.inner.lock().unwrap();
+               let current_height = inner.best_block.height;
+               let mut spendable_outputs = inner.get_spendable_outputs(tx);
+               spendable_outputs.retain(|descriptor| {
+                       let mut conf_threshold = current_height.saturating_sub(ANTI_REORG_DELAY) + 1;
+                       if let SpendableOutputDescriptor::DelayedPaymentOutput(descriptor) = descriptor {
+                               conf_threshold = cmp::min(conf_threshold,
+                                       current_height.saturating_sub(descriptor.to_self_delay as u32) + 1);
+                       }
+                       conf_threshold >= confirmation_height
+               });
+               spendable_outputs
+       }
+
+       #[cfg(test)]
+       pub fn get_counterparty_payment_script(&self) -> Script{
+               self.inner.lock().unwrap().counterparty_payment_script.clone()
+       }
+
+       #[cfg(test)]
+       pub fn set_counterparty_payment_script(&self, script: Script) {
+               self.inner.lock().unwrap().counterparty_payment_script = script;
+       }
 }
 
 impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
@@ -2236,6 +2279,7 @@ macro_rules! fail_unbroadcast_htlcs {
 
 #[cfg(test)]
 pub fn deliberately_bogus_accepted_htlc_witness_program() -> Vec<u8> {
+       use bitcoin::blockdata::opcodes;
        let mut ret = [opcodes::all::OP_NOP.to_u8(); 136];
        ret[131] = opcodes::all::OP_DROP.to_u8();
        ret[132] = opcodes::all::OP_DROP.to_u8();
@@ -2476,6 +2520,18 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
        {
                self.payment_preimages.insert(payment_hash.clone(), payment_preimage.clone());
 
+               let confirmed_spend_txid = self.funding_spend_confirmed.or_else(|| {
+                       self.onchain_events_awaiting_threshold_conf.iter().find_map(|event| match event.event {
+                               OnchainEvent::FundingSpendConfirmation { .. } => Some(event.txid),
+                               _ => None,
+                       })
+               });
+               let confirmed_spend_txid = if let Some(txid) = confirmed_spend_txid {
+                       txid
+               } else {
+                       return;
+               };
+
                // If the channel is force closed, try to claim the output from this preimage.
                // First check if a counterparty commitment transaction has been broadcasted:
                macro_rules! claim_htlcs {
@@ -2485,14 +2541,24 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                        }
                }
                if let Some(txid) = self.current_counterparty_commitment_txid {
-                       if let Some(commitment_number) = self.counterparty_commitment_txn_on_chain.get(&txid) {
-                               claim_htlcs!(*commitment_number, txid);
+                       if txid == confirmed_spend_txid {
+                               if let Some(commitment_number) = self.counterparty_commitment_txn_on_chain.get(&txid) {
+                                       claim_htlcs!(*commitment_number, txid);
+                               } else {
+                                       debug_assert!(false);
+                                       log_error!(logger, "Detected counterparty commitment tx on-chain without tracking commitment number");
+                               }
                                return;
                        }
                }
                if let Some(txid) = self.prev_counterparty_commitment_txid {
-                       if let Some(commitment_number) = self.counterparty_commitment_txn_on_chain.get(&txid) {
-                               claim_htlcs!(*commitment_number, txid);
+                       if txid == confirmed_spend_txid {
+                               if let Some(commitment_number) = self.counterparty_commitment_txn_on_chain.get(&txid) {
+                                       claim_htlcs!(*commitment_number, txid);
+                               } else {
+                                       debug_assert!(false);
+                                       log_error!(logger, "Detected counterparty commitment tx on-chain without tracking commitment number");
+                               }
                                return;
                        }
                }
@@ -2503,13 +2569,22 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                // *we* sign a holder commitment transaction, not when e.g. a watchtower broadcasts one of our
                // holder commitment transactions.
                if self.broadcasted_holder_revokable_script.is_some() {
-                       // Assume that the broadcasted commitment transaction confirmed in the current best
-                       // block. Even if not, its a reasonable metric for the bump criteria on the HTLC
-                       // transactions.
-                       let (claim_reqs, _) = self.get_broadcasted_holder_claims(&self.current_holder_commitment_tx, self.best_block.height());
-                       self.onchain_tx_handler.update_claims_view_from_requests(claim_reqs, self.best_block.height(), self.best_block.height(), broadcaster, fee_estimator, logger);
-                       if let Some(ref tx) = self.prev_holder_signed_commitment_tx {
-                               let (claim_reqs, _) = self.get_broadcasted_holder_claims(&tx, self.best_block.height());
+                       let holder_commitment_tx = if self.current_holder_commitment_tx.txid == confirmed_spend_txid {
+                               Some(&self.current_holder_commitment_tx)
+                       } else if let Some(prev_holder_commitment_tx) = &self.prev_holder_signed_commitment_tx {
+                               if prev_holder_commitment_tx.txid == confirmed_spend_txid {
+                                       Some(prev_holder_commitment_tx)
+                               } else {
+                                       None
+                               }
+                       } else {
+                               None
+                       };
+                       if let Some(holder_commitment_tx) = holder_commitment_tx {
+                               // Assume that the broadcasted commitment transaction confirmed in the current best
+                               // block. Even if not, its a reasonable metric for the bump criteria on the HTLC
+                               // transactions.
+                               let (claim_reqs, _) = self.get_broadcasted_holder_claims(&holder_commitment_tx, self.best_block.height());
                                self.onchain_tx_handler.update_claims_view_from_requests(claim_reqs, self.best_block.height(), self.best_block.height(), broadcaster, fee_estimator, logger);
                        }
                }
@@ -3441,7 +3516,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                }
                                self.is_resolving_htlc_output(&tx, height, &block_hash, &logger);
 
-                               self.is_paying_spendable_output(&tx, height, &block_hash, &logger);
+                               self.check_tx_and_push_spendable_outputs(&tx, height, &block_hash, &logger);
                        }
                }
 
@@ -3987,34 +4062,18 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                }
        }
 
-       /// Check if any transaction broadcasted is paying fund back to some address we can assume to own
-       fn is_paying_spendable_output<L: Deref>(&mut self, tx: &Transaction, height: u32, block_hash: &BlockHash, logger: &L) where L::Target: Logger {
-               let mut spendable_output = None;
-               for (i, outp) in tx.output.iter().enumerate() { // There is max one spendable output for any channel tx, including ones generated by us
-                       if i > ::core::u16::MAX as usize {
-                               // While it is possible that an output exists on chain which is greater than the
-                               // 2^16th output in a given transaction, this is only possible if the output is not
-                               // in a lightning transaction and was instead placed there by some third party who
-                               // wishes to give us money for no reason.
-                               // Namely, any lightning transactions which we pre-sign will never have anywhere
-                               // near 2^16 outputs both because such transactions must have ~2^16 outputs who's
-                               // scripts are not longer than one byte in length and because they are inherently
-                               // non-standard due to their size.
-                               // Thus, it is completely safe to ignore such outputs, and while it may result in
-                               // us ignoring non-lightning fund to us, that is only possible if someone fills
-                               // nearly a full block with garbage just to hit this case.
-                               continue;
-                       }
+       fn get_spendable_outputs(&self, tx: &Transaction) -> Vec<SpendableOutputDescriptor> {
+               let mut spendable_outputs = Vec::new();
+               for (i, outp) in tx.output.iter().enumerate() {
                        if outp.script_pubkey == self.destination_script {
-                               spendable_output =  Some(SpendableOutputDescriptor::StaticOutput {
+                               spendable_outputs.push(SpendableOutputDescriptor::StaticOutput {
                                        outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
                                        output: outp.clone(),
                                });
-                               break;
                        }
                        if let Some(ref broadcasted_holder_revokable_script) = self.broadcasted_holder_revokable_script {
                                if broadcasted_holder_revokable_script.0 == outp.script_pubkey {
-                                       spendable_output =  Some(SpendableOutputDescriptor::DelayedPaymentOutput(DelayedPaymentOutputDescriptor {
+                                       spendable_outputs.push(SpendableOutputDescriptor::DelayedPaymentOutput(DelayedPaymentOutputDescriptor {
                                                outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
                                                per_commitment_point: broadcasted_holder_revokable_script.1,
                                                to_self_delay: self.on_holder_tx_csv,
@@ -4023,27 +4082,33 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
                                                channel_keys_id: self.channel_keys_id,
                                                channel_value_satoshis: self.channel_value_satoshis,
                                        }));
-                                       break;
                                }
                        }
                        if self.counterparty_payment_script == outp.script_pubkey {
-                               spendable_output = Some(SpendableOutputDescriptor::StaticPaymentOutput(StaticPaymentOutputDescriptor {
+                               spendable_outputs.push(SpendableOutputDescriptor::StaticPaymentOutput(StaticPaymentOutputDescriptor {
                                        outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
                                        output: outp.clone(),
                                        channel_keys_id: self.channel_keys_id,
                                        channel_value_satoshis: self.channel_value_satoshis,
+                                       channel_transaction_parameters: Some(self.onchain_tx_handler.channel_transaction_parameters.clone()),
                                }));
-                               break;
                        }
                        if self.shutdown_script.as_ref() == Some(&outp.script_pubkey) {
-                               spendable_output = Some(SpendableOutputDescriptor::StaticOutput {
+                               spendable_outputs.push(SpendableOutputDescriptor::StaticOutput {
                                        outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
                                        output: outp.clone(),
                                });
-                               break;
                        }
                }
-               if let Some(spendable_output) = spendable_output {
+               spendable_outputs
+       }
+
+       /// Checks if the confirmed transaction is paying funds back to some address we can assume to
+       /// own.
+       fn check_tx_and_push_spendable_outputs<L: Deref>(
+               &mut self, tx: &Transaction, height: u32, block_hash: &BlockHash, logger: &L,
+       ) where L::Target: Logger {
+               for spendable_output in self.get_spendable_outputs(tx) {
                        let entry = OnchainEventEntry {
                                txid: tx.txid(),
                                transaction: Some(tx.clone()),
@@ -4128,7 +4193,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
                        1 => { None },
                        _ => return Err(DecodeError::InvalidValue),
                };
-               let counterparty_payment_script = Readable::read(reader)?;
+               let mut counterparty_payment_script: Script = Readable::read(reader)?;
                let shutdown_script = {
                        let script = <Script as Readable>::read(reader)?;
                        if script.is_empty() { None } else { Some(script) }
@@ -4329,6 +4394,17 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
                        (17, initial_counterparty_commitment_info, option),
                });
 
+               // Monitors for anchor outputs channels opened in v0.0.116 suffered from a bug in which the
+               // wrong `counterparty_payment_script` was being tracked. Fix it now on deserialization to
+               // give them a chance to recognize the spendable output.
+               if onchain_tx_handler.channel_type_features().supports_anchors_zero_fee_htlc_tx() &&
+                       counterparty_payment_script.is_v0_p2wpkh()
+               {
+                       let payment_point = onchain_tx_handler.channel_transaction_parameters.holder_pubkeys.payment_point;
+                       counterparty_payment_script =
+                               chan_utils::get_to_countersignatory_with_anchors_redeemscript(&payment_point).to_v0_p2wsh();
+               }
+
                Ok((best_block.block_hash(), ChannelMonitor::from_impl(ChannelMonitorImpl {
                        latest_update_id,
                        commitment_transaction_number_obscure_factor,
index 35e9da60544ddc680535983767117e9faf732afd..55c12d23e749cf020a7308f998ab686f28ea22d3 100644 (file)
@@ -26,7 +26,7 @@ use crate::ln::chan_utils::{
 use crate::ln::features::ChannelTypeFeatures;
 use crate::ln::PaymentPreimage;
 use crate::prelude::*;
-use crate::sign::{EcdsaChannelSigner, SignerProvider, WriteableEcdsaChannelSigner};
+use crate::sign::{EcdsaChannelSigner, SignerProvider, WriteableEcdsaChannelSigner, P2WPKH_WITNESS_WEIGHT};
 use crate::sync::Mutex;
 use crate::util::logger::Logger;
 
@@ -384,12 +384,6 @@ pub struct Utxo {
 }
 
 impl Utxo {
-       const P2WPKH_WITNESS_WEIGHT: u64 = 1 /* num stack items */ +
-               1 /* sig length */ +
-               73 /* sig including sighash flag */ +
-               1 /* pubkey length */ +
-               33 /* pubkey */;
-
        /// Returns a `Utxo` with the `satisfaction_weight` estimate for a legacy P2PKH output.
        pub fn new_p2pkh(outpoint: OutPoint, value: u64, pubkey_hash: &PubkeyHash) -> Self {
                let script_sig_size = 1 /* script_sig length */ +
@@ -419,7 +413,7 @@ impl Utxo {
                                value,
                                script_pubkey: Script::new_p2sh(&Script::new_v0_p2wpkh(pubkey_hash).script_hash()),
                        },
-                       satisfaction_weight: script_sig_size * WITNESS_SCALE_FACTOR as u64 + Self::P2WPKH_WITNESS_WEIGHT,
+                       satisfaction_weight: script_sig_size * WITNESS_SCALE_FACTOR as u64 + P2WPKH_WITNESS_WEIGHT,
                }
        }
 
@@ -431,7 +425,7 @@ impl Utxo {
                                value,
                                script_pubkey: Script::new_v0_p2wpkh(pubkey_hash),
                        },
-                       satisfaction_weight: EMPTY_SCRIPT_SIG_WEIGHT + Self::P2WPKH_WITNESS_WEIGHT,
+                       satisfaction_weight: EMPTY_SCRIPT_SIG_WEIGHT + P2WPKH_WITNESS_WEIGHT,
                }
        }
 }
index 269887a3dbac06fc1ba24dcda084f5c2c2115de2..c8c736c1f713db79a72336fbb44b2ba0ae76abea 100644 (file)
@@ -517,6 +517,7 @@ pub enum Event {
        /// or was explicitly abandoned by [`ChannelManager::abandon_payment`].
        ///
        /// [`ChannelManager::abandon_payment`]: crate::ln::channelmanager::ChannelManager::abandon_payment
+       #[cfg(invreqfailed)]
        InvoiceRequestFailed {
                /// The `payment_id` to have been associated with payment for the requested invoice.
                payment_id: PaymentId,
@@ -1163,6 +1164,7 @@ impl Writeable for Event {
                                        (8, funding_txo, required),
                                });
                        },
+                       #[cfg(invreqfailed)]
                        &Event::InvoiceRequestFailed { ref payment_id } => {
                                33u8.write(writer)?;
                                write_tlv_fields!(writer, {
@@ -1556,6 +1558,7 @@ impl MaybeReadable for Event {
                                };
                                f()
                        },
+                       #[cfg(invreqfailed)]
                        33u8 => {
                                let f = || {
                                        _init_and_read_len_prefixed_tlv_fields!(reader, {
index 7521da01f97496932c357e0c0f974e37eee3b2bc..d1489e2716836f928d5bdc04450f3d8722d4fbc9 100644 (file)
@@ -19,7 +19,7 @@ use bitcoin::util::address::Payload;
 use bitcoin::hashes::{Hash, HashEngine};
 use bitcoin::hashes::sha256::Hash as Sha256;
 use bitcoin::hashes::ripemd160::Hash as Ripemd160;
-use bitcoin::hash_types::{Txid, PubkeyHash};
+use bitcoin::hash_types::{Txid, PubkeyHash, WPubkeyHash};
 
 use crate::chain::chaininterface::fee_for_weight;
 use crate::chain::package::WEIGHT_REVOKED_OUTPUT;
@@ -475,7 +475,7 @@ impl_writeable_tlv_based!(TxCreationKeys, {
 });
 
 /// One counterparty's public keys which do not change over the life of a channel.
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
 pub struct ChannelPublicKeys {
        /// The public key which is used to sign all commitment transactions, as it appears in the
        /// on-chain channel lock-in 2-of-2 multisig output.
@@ -556,6 +556,16 @@ pub fn get_revokeable_redeemscript(revocation_key: &PublicKey, contest_delay: u1
        res
 }
 
+/// Returns the script for the counterparty's output on a holder's commitment transaction based on
+/// the channel type.
+pub fn get_counterparty_payment_script(channel_type_features: &ChannelTypeFeatures, payment_key: &PublicKey) -> Script {
+       if channel_type_features.supports_anchors_zero_fee_htlc_tx() {
+               get_to_countersignatory_with_anchors_redeemscript(payment_key).to_v0_p2wsh()
+       } else {
+               Script::new_v0_p2wpkh(&WPubkeyHash::hash(&payment_key.serialize()))
+       }
+}
+
 /// Information about an HTLC as it appears in a commitment transaction
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct HTLCOutputInCommitment {
@@ -853,7 +863,7 @@ pub fn build_anchor_input_witness(funding_key: &PublicKey, funding_sig: &Signatu
 ///
 /// Normally, this is converted to the broadcaster/countersignatory-organized DirectedChannelTransactionParameters
 /// before use, via the as_holder_broadcastable and as_counterparty_broadcastable functions.
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
 pub struct ChannelTransactionParameters {
        /// Holder public keys
        pub holder_pubkeys: ChannelPublicKeys,
@@ -873,7 +883,7 @@ pub struct ChannelTransactionParameters {
 }
 
 /// Late-bound per-channel counterparty data used to build transactions.
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
 pub struct CounterpartyChannelTransactionParameters {
        /// Counter-party public keys
        pub pubkeys: ChannelPublicKeys,
index 55e56be2a79377079377591f14ad1fef33311f17..a61a8de82debecd5906c0ee95bdcdb420aae48f4 100644 (file)
@@ -66,6 +66,8 @@ pub struct ChannelValueStat {
 }
 
 pub struct AvailableBalances {
+       /// The amount that would go to us if we close the channel, ignoring any on-chain fees.
+       pub balance_msat: u64,
        /// Total amount available for our counterparty to send to us.
        pub inbound_capacity_msat: u64,
        /// Total amount available for us to send to our counterparty.
@@ -1655,6 +1657,14 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider  {
                let inbound_stats = context.get_inbound_pending_htlc_stats(None);
                let outbound_stats = context.get_outbound_pending_htlc_stats(None);
 
+               let mut balance_msat = context.value_to_self_msat;
+               for ref htlc in context.pending_inbound_htlcs.iter() {
+                       if let InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::Fulfill(_)) = htlc.state {
+                               balance_msat += htlc.amount_msat;
+                       }
+               }
+               balance_msat -= outbound_stats.pending_htlcs_value_msat;
+
                let outbound_capacity_msat = context.value_to_self_msat
                                .saturating_sub(outbound_stats.pending_htlcs_value_msat)
                                .saturating_sub(
@@ -1771,6 +1781,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider  {
                        outbound_capacity_msat,
                        next_outbound_htlc_limit_msat: available_capacity_msat,
                        next_outbound_htlc_minimum_msat,
+                       balance_msat,
                }
        }
 
@@ -4808,6 +4819,7 @@ impl<SP: Deref> Channel<SP> where
                NS::Target: NodeSigner,
                L::Target: Logger
        {
+               let mut msgs = (None, None);
                if let Some(funding_txo) = self.context.get_funding_txo() {
                        for &(index_in_block, tx) in txdata.iter() {
                                // Check if the transaction is the expected funding transaction, and if it is,
@@ -4863,7 +4875,7 @@ impl<SP: Deref> Channel<SP> where
                                        if let Some(channel_ready) = self.check_get_channel_ready(height) {
                                                log_info!(logger, "Sending a channel_ready to our peer for channel {}", &self.context.channel_id);
                                                let announcement_sigs = self.get_announcement_sigs(node_signer, genesis_block_hash, user_config, height, logger);
-                                               return Ok((Some(channel_ready), announcement_sigs));
+                                               msgs = (Some(channel_ready), announcement_sigs);
                                        }
                                }
                                for inp in tx.input.iter() {
@@ -4874,7 +4886,7 @@ impl<SP: Deref> Channel<SP> where
                                }
                        }
                }
-               Ok((None, None))
+               Ok(msgs)
        }
 
        /// When a new block is connected, we check the height of the block against outbound holding
@@ -5537,14 +5549,20 @@ impl<SP: Deref> Channel<SP> where
                }
        }
 
-       pub fn channel_update(&mut self, msg: &msgs::ChannelUpdate) -> Result<(), ChannelError> {
-               self.context.counterparty_forwarding_info = Some(CounterpartyForwardingInfo {
+       /// Applies the `ChannelUpdate` and returns a boolean indicating whether a change actually
+       /// happened.
+       pub fn channel_update(&mut self, msg: &msgs::ChannelUpdate) -> Result<bool, ChannelError> {
+               let new_forwarding_info = Some(CounterpartyForwardingInfo {
                        fee_base_msat: msg.contents.fee_base_msat,
                        fee_proportional_millionths: msg.contents.fee_proportional_millionths,
                        cltv_expiry_delta: msg.contents.cltv_expiry_delta
                });
+               let did_change = self.context.counterparty_forwarding_info != new_forwarding_info;
+               if did_change {
+                       self.context.counterparty_forwarding_info = new_forwarding_info;
+               }
 
-               Ok(())
+               Ok(did_change)
        }
 
        /// Begins the shutdown process, getting a message for the remote peer and returning all
@@ -8140,7 +8158,7 @@ mod tests {
                        },
                        signature: Signature::from(unsafe { FFISignature::new() })
                };
-               node_a_chan.channel_update(&update).unwrap();
+               assert!(node_a_chan.channel_update(&update).unwrap());
 
                // The counterparty can send an update with a higher minimum HTLC, but that shouldn't
                // change our official htlc_minimum_msat.
@@ -8153,6 +8171,8 @@ mod tests {
                        },
                        None => panic!("expected counterparty forwarding info to be Some")
                }
+
+               assert!(!node_a_chan.channel_update(&update).unwrap());
        }
 
        #[cfg(feature = "_test_vectors")]
index 392f3e1cb052cf196b50b2b7e3734b62ab167e4c..3f6a2a6b20dfcc692df81fad93ac93c4d37a068e 100644 (file)
@@ -1448,12 +1448,6 @@ pub struct ChannelCounterparty {
 }
 
 /// Details of a channel, as returned by [`ChannelManager::list_channels`] and [`ChannelManager::list_usable_channels`]
-///
-/// Balances of a channel are available through [`ChainMonitor::get_claimable_balances`] and
-/// [`ChannelMonitor::get_claimable_balances`], calculated with respect to the corresponding on-chain
-/// transactions.
-///
-/// [`ChainMonitor::get_claimable_balances`]: crate::chain::chainmonitor::ChainMonitor::get_claimable_balances
 #[derive(Clone, Debug, PartialEq)]
 pub struct ChannelDetails {
        /// The channel's ID (prior to funding transaction generation, this is a random 32 bytes,
@@ -1535,11 +1529,24 @@ pub struct ChannelDetails {
        ///
        /// This value will be `None` for objects serialized with LDK versions prior to 0.0.115.
        pub feerate_sat_per_1000_weight: Option<u32>,
+       /// Our total balance.  This is the amount we would get if we close the channel.
+       /// This value is not exact. Due to various in-flight changes and feerate changes, exactly this
+       /// amount is not likely to be recoverable on close.
+       ///
+       /// This does not include any pending HTLCs which are not yet fully resolved (and, thus, whose
+       /// balance is not available for inclusion in new outbound HTLCs). This further does not include
+       /// any pending outgoing HTLCs which are awaiting some other resolution to be sent.
+       /// This does not consider any on-chain fees.
+       ///
+       /// See also [`ChannelDetails::outbound_capacity_msat`]
+       pub balance_msat: u64,
        /// The available outbound capacity for sending HTLCs to the remote peer. This does not include
        /// any pending HTLCs which are not yet fully resolved (and, thus, whose balance is not
        /// available for inclusion in new outbound HTLCs). This further does not include any pending
        /// outgoing HTLCs which are awaiting some other resolution to be sent.
        ///
+       /// See also [`ChannelDetails::balance_msat`]
+       ///
        /// This value is not exact. Due to various in-flight changes, feerate changes, and our
        /// conflict-avoidance policy, exactly this amount is not likely to be spendable. However, we
        /// should be able to spend nearly this amount.
@@ -1549,8 +1556,8 @@ pub struct ChannelDetails {
        /// the current state and per-HTLC limit(s). This is intended for use when routing, allowing us
        /// to use a limit as close as possible to the HTLC limit we can currently send.
        ///
-       /// See also [`ChannelDetails::next_outbound_htlc_minimum_msat`] and
-       /// [`ChannelDetails::outbound_capacity_msat`].
+       /// See also [`ChannelDetails::next_outbound_htlc_minimum_msat`],
+       /// [`ChannelDetails::balance_msat`], and [`ChannelDetails::outbound_capacity_msat`].
        pub next_outbound_htlc_limit_msat: u64,
        /// The minimum value for sending a single HTLC to the remote peer. This is the equivalent of
        /// [`ChannelDetails::next_outbound_htlc_limit_msat`] but represents a lower-bound, rather than
@@ -1680,6 +1687,7 @@ impl ChannelDetails {
                        channel_value_satoshis: context.get_value_satoshis(),
                        feerate_sat_per_1000_weight: Some(context.get_feerate_sat_per_1000_weight()),
                        unspendable_punishment_reserve: to_self_reserve_satoshis,
+                       balance_msat: balance.balance_msat,
                        inbound_capacity_msat: balance.inbound_capacity_msat,
                        outbound_capacity_msat: balance.outbound_capacity_msat,
                        next_outbound_htlc_limit_msat: balance.next_outbound_htlc_limit_msat,
@@ -3471,9 +3479,8 @@ where
        /// In general, a path may raise:
        ///  * [`APIError::InvalidRoute`] when an invalid route or forwarding parameter (cltv_delta, fee,
        ///    node public key) is specified.
-       ///  * [`APIError::ChannelUnavailable`] if the next-hop channel is not available for updates
-       ///    (including due to previous monitor update failure or new permanent monitor update
-       ///    failure).
+       ///  * [`APIError::ChannelUnavailable`] if the next-hop channel is not available as it has been
+       ///    closed, doesn't exist, or the peer is currently disconnected.
        ///  * [`APIError::MonitorUpdateInProgress`] if a new monitor update failure prevented sending the
        ///    relevant updates.
        ///
@@ -3542,19 +3549,10 @@ where
        /// wait until you receive either a [`Event::PaymentFailed`] or [`Event::PaymentSent`] event to
        /// determine the ultimate status of a payment.
        ///
-       /// # Requested Invoices
-       ///
-       /// In the case of paying a [`Bolt12Invoice`], abandoning the payment prior to receiving the
-       /// invoice will result in an [`Event::InvoiceRequestFailed`] and prevent any attempts at paying
-       /// it once received. The other events may only be generated once the invoice has been received.
-       ///
        /// # Restart Behavior
        ///
        /// If an [`Event::PaymentFailed`] is generated and we restart without first persisting the
-       /// [`ChannelManager`], another [`Event::PaymentFailed`] may be generated; likewise for
-       /// [`Event::InvoiceRequestFailed`].
-       ///
-       /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
+       /// [`ChannelManager`], another [`Event::PaymentFailed`] may be generated.
        pub fn abandon_payment(&self, payment_id: PaymentId) {
                let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                self.pending_outbound_payments.abandon_payment(payment_id, PaymentFailureReason::UserAbandoned, &self.pending_events);
@@ -3895,7 +3893,7 @@ where
                                btree_map::Entry::Vacant(vacant) => Some(vacant.insert(Vec::new())),
                        }
                });
-               for (channel_idx, &(temporary_channel_id, counterparty_node_id)) in temporary_channels.iter().enumerate() {
+               for &(temporary_channel_id, counterparty_node_id) in temporary_channels.iter() {
                        result = result.and_then(|_| self.funding_transaction_generated_intern(
                                temporary_channel_id,
                                counterparty_node_id,
@@ -6757,7 +6755,12 @@ where
                                                return Ok(NotifyOption::SkipPersistNoEvents);
                                        } else {
                                                log_debug!(self.logger, "Received channel_update {:?} for channel {}.", msg, chan_id);
-                                               try_chan_phase_entry!(self, chan.channel_update(&msg), chan_phase_entry);
+                                               let did_change = try_chan_phase_entry!(self, chan.channel_update(&msg), chan_phase_entry);
+                                               // If nothing changed after applying their update, we don't need to bother
+                                               // persisting.
+                                               if !did_change {
+                                                       return Ok(NotifyOption::SkipPersistNoEvents);
+                                               }
                                        }
                                } else {
                                        return try_chan_phase_entry!(self, Err(ChannelError::Close(
@@ -6972,8 +6975,7 @@ where
        fn maybe_generate_initial_closing_signed(&self) -> bool {
                let mut handle_errors: Vec<(PublicKey, Result<(), _>)> = Vec::new();
                let mut has_update = false;
-               let mut shutdown_result = None;
-               let mut unbroadcasted_batch_funding_txid = None;
+               let mut shutdown_results = Vec::new();
                {
                        let per_peer_state = self.per_peer_state.read().unwrap();
 
@@ -6984,7 +6986,7 @@ where
                                peer_state.channel_by_id.retain(|channel_id, phase| {
                                        match phase {
                                                ChannelPhase::Funded(chan) => {
-                                                       unbroadcasted_batch_funding_txid = chan.context.unbroadcasted_batch_funding_txid();
+                                                       let unbroadcasted_batch_funding_txid = chan.context.unbroadcasted_batch_funding_txid();
                                                        match chan.maybe_propose_closing_signed(&self.fee_estimator, &self.logger) {
                                                                Ok((msg_opt, tx_opt)) => {
                                                                        if let Some(msg) = msg_opt {
@@ -7007,7 +7009,7 @@ where
                                                                                log_info!(self.logger, "Broadcasting {}", log_tx!(tx));
                                                                                self.tx_broadcaster.broadcast_transactions(&[&tx]);
                                                                                update_maps_on_chan_removal!(self, &chan.context);
-                                                                               shutdown_result = Some((None, Vec::new(), unbroadcasted_batch_funding_txid));
+                                                                               shutdown_results.push((None, Vec::new(), unbroadcasted_batch_funding_txid));
                                                                                false
                                                                        } else { true }
                                                                },
@@ -7029,7 +7031,7 @@ where
                        let _ = handle_error!(self, err, counterparty_node_id);
                }
 
-               if let Some(shutdown_result) = shutdown_result {
+               for shutdown_result in shutdown_results.drain(..) {
                        self.finish_close_channel(shutdown_result);
                }
 
@@ -8415,7 +8417,7 @@ impl Writeable for ChannelDetails {
                        (10, self.channel_value_satoshis, required),
                        (12, self.unspendable_punishment_reserve, option),
                        (14, user_channel_id_low, required),
-                       (16, self.next_outbound_htlc_limit_msat, required),  // Forwards compatibility for removed balance_msat field.
+                       (16, self.balance_msat, required),
                        (18, self.outbound_capacity_msat, required),
                        (19, self.next_outbound_htlc_limit_msat, required),
                        (20, self.inbound_capacity_msat, required),
@@ -8451,7 +8453,7 @@ impl Readable for ChannelDetails {
                        (10, channel_value_satoshis, required),
                        (12, unspendable_punishment_reserve, option),
                        (14, user_channel_id_low, required),
-                       (16, _balance_msat, option),  // Backwards compatibility for removed balance_msat field.
+                       (16, balance_msat, required),
                        (18, outbound_capacity_msat, required),
                        // Note that by the time we get past the required read above, outbound_capacity_msat will be
                        // filled in, so we can safely unwrap it here.
@@ -8477,8 +8479,6 @@ impl Readable for ChannelDetails {
                let user_channel_id = user_channel_id_low as u128 +
                        ((user_channel_id_high_opt.unwrap_or(0 as u64) as u128) << 64);
 
-               let _balance_msat: Option<u64> = _balance_msat;
-
                Ok(Self {
                        inbound_scid_alias,
                        channel_id: channel_id.0.unwrap(),
@@ -8491,6 +8491,7 @@ impl Readable for ChannelDetails {
                        channel_value_satoshis: channel_value_satoshis.0.unwrap(),
                        unspendable_punishment_reserve,
                        user_channel_id,
+                       balance_msat: balance_msat.0.unwrap(),
                        outbound_capacity_msat: outbound_capacity_msat.0.unwrap(),
                        next_outbound_htlc_limit_msat: next_outbound_htlc_limit_msat.0.unwrap(),
                        next_outbound_htlc_minimum_msat: next_outbound_htlc_minimum_msat.0.unwrap(),
index 19ba81235f2df3bb8bad508ab39787aebb95b053..5e90ee7e92e31d0005dd65b35ac22c68a9eb9c98 100644 (file)
@@ -10625,3 +10625,60 @@ fn test_batch_funding_close_after_funding_signed() {
        // Ensure the channels don't exist anymore.
        assert!(nodes[0].node.list_channels().is_empty());
 }
+
+fn do_test_funding_and_commitment_tx_confirm_same_block(confirm_remote_commitment: bool) {
+       // Tests that a node will forget the channel (when it only requires 1 confirmation) if the
+       // funding and commitment transaction confirm in the same block.
+       let chanmon_cfgs = create_chanmon_cfgs(2);
+       let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
+       let mut min_depth_1_block_cfg = test_default_channel_config();
+       min_depth_1_block_cfg.channel_handshake_config.minimum_depth = 1;
+       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(min_depth_1_block_cfg), Some(min_depth_1_block_cfg)]);
+       let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+
+       let funding_tx = create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 1_000_000, 0);
+       let chan_id = chain::transaction::OutPoint { txid: funding_tx.txid(), index: 0 }.to_channel_id();
+
+       assert_eq!(nodes[0].node.list_channels().len(), 1);
+       assert_eq!(nodes[1].node.list_channels().len(), 1);
+
+       let (closing_node, other_node) = if confirm_remote_commitment {
+               (&nodes[1], &nodes[0])
+       } else {
+               (&nodes[0], &nodes[1])
+       };
+
+       closing_node.node.force_close_broadcasting_latest_txn(&chan_id, &other_node.node.get_our_node_id()).unwrap();
+       let mut msg_events = closing_node.node.get_and_clear_pending_msg_events();
+       assert_eq!(msg_events.len(), 1);
+       match msg_events.pop().unwrap() {
+               MessageSendEvent::HandleError { action: msgs::ErrorAction::SendErrorMessage { .. }, .. } => {},
+               _ => panic!("Unexpected event"),
+       }
+       check_added_monitors(closing_node, 1);
+       check_closed_event(closing_node, 1, ClosureReason::HolderForceClosed, false, &[other_node.node.get_our_node_id()], 1_000_000);
+
+       let commitment_tx = {
+               let mut txn = closing_node.tx_broadcaster.txn_broadcast();
+               assert_eq!(txn.len(), 1);
+               let commitment_tx = txn.pop().unwrap();
+               check_spends!(commitment_tx, funding_tx);
+               commitment_tx
+       };
+
+       mine_transactions(&nodes[0], &[&funding_tx, &commitment_tx]);
+       mine_transactions(&nodes[1], &[&funding_tx, &commitment_tx]);
+
+       check_closed_broadcast(other_node, 1, true);
+       check_added_monitors(other_node, 1);
+       check_closed_event(other_node, 1, ClosureReason::CommitmentTxConfirmed, false, &[closing_node.node.get_our_node_id()], 1_000_000);
+
+       assert!(nodes[0].node.list_channels().is_empty());
+       assert!(nodes[1].node.list_channels().is_empty());
+}
+
+#[test]
+fn test_funding_and_commitment_tx_confirm_same_block() {
+       do_test_funding_and_commitment_tx_confirm_same_block(false);
+       do_test_funding_and_commitment_tx_confirm_same_block(true);
+}
index 9cf3f4ca29a323b16f5d76114a9a413138f2633f..905a4dc82d9fd066ad3aded10ad17332d2acfb10 100644 (file)
@@ -9,7 +9,7 @@
 
 //! Further functional tests which test blockchain reorganizations.
 
-use crate::sign::EcdsaChannelSigner;
+use crate::sign::{EcdsaChannelSigner, SpendableOutputDescriptor};
 use crate::chain::channelmonitor::{ANTI_REORG_DELAY, LATENCY_GRACE_PERIOD_BLOCKS, Balance};
 use crate::chain::transaction::OutPoint;
 use crate::chain::chaininterface::{LowerBoundedFeeEstimator, compute_feerate_sat_per_1000_weight};
@@ -21,6 +21,7 @@ use crate::ln::msgs::ChannelMessageHandler;
 use crate::util::config::UserConfig;
 use crate::util::crypto::sign;
 use crate::util::ser::Writeable;
+use crate::util::scid_utils::block_from_scid;
 use crate::util::test_utils;
 
 use bitcoin::blockdata::transaction::EcdsaSighashType;
@@ -92,7 +93,7 @@ fn chanmon_fail_from_stale_commitment() {
        expect_payment_failed_with_update!(nodes[0], payment_hash, false, update_a.contents.short_channel_id, true);
 }
 
-fn test_spendable_output<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, spendable_tx: &Transaction) {
+fn test_spendable_output<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, spendable_tx: &Transaction) -> Vec<SpendableOutputDescriptor> {
        let mut spendable = node.chain_monitor.chain_monitor.get_and_clear_pending_events();
        assert_eq!(spendable.len(), 1);
        if let Event::SpendableOutputs { outputs, .. } = spendable.pop().unwrap() {
@@ -100,6 +101,7 @@ fn test_spendable_output<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, spendable_t
                let spend_tx = node.keys_manager.backing.spend_spendable_outputs(&[&outputs[0]], Vec::new(),
                        Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, None, &Secp256k1::new()).unwrap();
                check_spends!(spend_tx, spendable_tx);
+               outputs
        } else { panic!(); }
 }
 
@@ -196,8 +198,8 @@ fn chanmon_claim_value_coop_close() {
        assert_eq!(shutdown_tx, nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0));
        assert_eq!(shutdown_tx.len(), 1);
 
-       mine_transaction(&nodes[0], &shutdown_tx[0]);
-       mine_transaction(&nodes[1], &shutdown_tx[0]);
+       let shutdown_tx_conf_height_a = block_from_scid(&mine_transaction(&nodes[0], &shutdown_tx[0]));
+       let shutdown_tx_conf_height_b = block_from_scid(&mine_transaction(&nodes[1], &shutdown_tx[0]));
 
        assert!(nodes[0].node.list_channels().is_empty());
        assert!(nodes[1].node.list_channels().is_empty());
@@ -216,16 +218,33 @@ fn chanmon_claim_value_coop_close() {
                }],
                nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
 
-       connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1);
-       connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1);
+       connect_blocks(&nodes[0], ANTI_REORG_DELAY - 2);
+       connect_blocks(&nodes[1], ANTI_REORG_DELAY - 2);
+
+       assert!(get_monitor!(nodes[0], chan_id)
+               .get_spendable_outputs(&shutdown_tx[0], shutdown_tx_conf_height_a).is_empty());
+       assert!(get_monitor!(nodes[1], chan_id)
+               .get_spendable_outputs(&shutdown_tx[0], shutdown_tx_conf_height_b).is_empty());
+
+       connect_blocks(&nodes[0], 1);
+       connect_blocks(&nodes[1], 1);
 
        assert_eq!(Vec::<Balance>::new(),
                nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
        assert_eq!(Vec::<Balance>::new(),
                nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
 
-       test_spendable_output(&nodes[0], &shutdown_tx[0]);
-       test_spendable_output(&nodes[1], &shutdown_tx[0]);
+       let spendable_outputs_a = test_spendable_output(&nodes[0], &shutdown_tx[0]);
+       assert_eq!(
+               get_monitor!(nodes[0], chan_id).get_spendable_outputs(&shutdown_tx[0], shutdown_tx_conf_height_a),
+               spendable_outputs_a
+       );
+
+       let spendable_outputs_b = test_spendable_output(&nodes[1], &shutdown_tx[0]);
+       assert_eq!(
+               get_monitor!(nodes[1], chan_id).get_spendable_outputs(&shutdown_tx[0], shutdown_tx_conf_height_b),
+               spendable_outputs_b
+       );
 
        check_closed_event!(nodes[0], 1, ClosureReason::CooperativeClosure, [nodes[1].node.get_our_node_id()], 1000000);
        check_closed_event!(nodes[1], 1, ClosureReason::CooperativeClosure, [nodes[0].node.get_our_node_id()], 1000000);
@@ -618,7 +637,7 @@ fn test_balances_on_local_commitment_htlcs() {
        // First confirm the commitment transaction on nodes[0], which should leave us with three
        // claimable balances.
        let node_a_commitment_claimable = nodes[0].best_block_info().1 + BREAKDOWN_TIMEOUT as u32;
-       mine_transaction(&nodes[0], &as_txn[0]);
+       let commitment_tx_conf_height_a = block_from_scid(&mine_transaction(&nodes[0], &as_txn[0]));
        check_added_monitors!(nodes[0], 1);
        check_closed_broadcast!(nodes[0], true);
        check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed, [nodes[1].node.get_our_node_id()], 1000000);
@@ -710,13 +729,20 @@ fn test_balances_on_local_commitment_htlcs() {
 
        // Connect blocks until the commitment transaction's CSV expires, providing us the relevant
        // `SpendableOutputs` event and removing the claimable balance entry.
-       connect_blocks(&nodes[0], node_a_commitment_claimable - nodes[0].best_block_info().1);
+       connect_blocks(&nodes[0], node_a_commitment_claimable - nodes[0].best_block_info().1 - 1);
+       assert!(get_monitor!(nodes[0], chan_id)
+               .get_spendable_outputs(&as_txn[0], commitment_tx_conf_height_a).is_empty());
+       connect_blocks(&nodes[0], 1);
        assert_eq!(vec![Balance::ClaimableAwaitingConfirmations {
                        amount_satoshis: 10_000,
                        confirmation_height: node_a_htlc_claimable,
                }],
                nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
-       test_spendable_output(&nodes[0], &as_txn[0]);
+       let to_self_spendable_output = test_spendable_output(&nodes[0], &as_txn[0]);
+       assert_eq!(
+               get_monitor!(nodes[0], chan_id).get_spendable_outputs(&as_txn[0], commitment_tx_conf_height_a),
+               to_self_spendable_output
+       );
 
        // Connect blocks until the HTLC-Timeout's CSV expires, providing us the relevant
        // `SpendableOutputs` event and removing the claimable balance entry.
@@ -2268,8 +2294,8 @@ fn test_anchors_aggregated_revoked_htlc_tx() {
 
        assert!(nodes[1].chain_monitor.chain_monitor.get_and_clear_pending_events().is_empty());
        let spendable_output_events = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events();
-       assert_eq!(spendable_output_events.len(), 2);
-       for event in spendable_output_events.iter() {
+       assert_eq!(spendable_output_events.len(), 4);
+       for event in spendable_output_events {
                if let Event::SpendableOutputs { outputs, channel_id } = event {
                        assert_eq!(outputs.len(), 1);
                        assert!(vec![chan_b.2, chan_a.2].contains(&channel_id.unwrap()));
@@ -2277,7 +2303,11 @@ fn test_anchors_aggregated_revoked_htlc_tx() {
                                &[&outputs[0]], Vec::new(), Script::new_op_return(&[]), 253, None, &Secp256k1::new(),
                        ).unwrap();
 
-                       check_spends!(spend_tx, revoked_claim_transactions.get(&spend_tx.input[0].previous_output.txid).unwrap());
+                       if let SpendableOutputDescriptor::StaticPaymentOutput(_) = &outputs[0] {
+                               check_spends!(spend_tx, &revoked_commitment_a, &revoked_commitment_b);
+                       } else {
+                               check_spends!(spend_tx, revoked_claim_transactions.get(&spend_tx.input[0].previous_output.txid).unwrap());
+                       }
                } else {
                        panic!("unexpected event");
                }
@@ -2295,3 +2325,90 @@ fn test_anchors_aggregated_revoked_htlc_tx() {
        // revoked commitment which Bob has the preimage for.
        assert_eq!(nodes[1].chain_monitor.chain_monitor.get_claimable_balances(&[]).len(), 6);
 }
+
+fn do_test_anchors_monitor_fixes_counterparty_payment_script_on_reload(confirm_commitment_before_reload: bool) {
+       // Tests that we'll fix a ChannelMonitor's `counterparty_payment_script` for an anchor outputs
+       // channel upon deserialization.
+       let chanmon_cfgs = create_chanmon_cfgs(2);
+       let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
+       let persister;
+       let chain_monitor;
+       let mut user_config = test_default_channel_config();
+       user_config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
+       user_config.manually_accept_inbound_channels = true;
+       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(user_config), Some(user_config)]);
+       let node_deserialized;
+       let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+
+       let (_, _, chan_id, funding_tx) = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, 50_000_000);
+
+       // Set the monitor's `counterparty_payment_script` to a dummy P2WPKH script.
+       let secp = Secp256k1::new();
+       let privkey = bitcoin::PrivateKey::from_slice(&[1; 32], bitcoin::Network::Testnet).unwrap();
+       let pubkey = bitcoin::PublicKey::from_private_key(&secp, &privkey);
+       let p2wpkh_script = Script::new_v0_p2wpkh(&pubkey.wpubkey_hash().unwrap());
+       get_monitor!(nodes[1], chan_id).set_counterparty_payment_script(p2wpkh_script.clone());
+       assert_eq!(get_monitor!(nodes[1], chan_id).get_counterparty_payment_script(), p2wpkh_script);
+
+       // Confirm the counterparty's commitment and reload the monitor (either before or after) such
+       // that we arrive at the correct `counterparty_payment_script` after the reload.
+       nodes[0].node.force_close_broadcasting_latest_txn(&chan_id, &nodes[1].node.get_our_node_id()).unwrap();
+       check_added_monitors(&nodes[0], 1);
+       check_closed_broadcast(&nodes[0], 1, true);
+       check_closed_event!(&nodes[0], 1, ClosureReason::HolderForceClosed, false,
+                [nodes[1].node.get_our_node_id()], 100000);
+
+       let commitment_tx = {
+               let mut txn = nodes[0].tx_broadcaster.unique_txn_broadcast();
+               assert_eq!(txn.len(), 1);
+               assert_eq!(txn[0].output.len(), 4);
+               check_spends!(txn[0], funding_tx);
+               txn.pop().unwrap()
+       };
+
+       mine_transaction(&nodes[0], &commitment_tx);
+       let commitment_tx_conf_height = if confirm_commitment_before_reload {
+               // We should expect our round trip serialization check to fail as we're writing the monitor
+               // with the incorrect P2WPKH script but reading it with the correct P2WSH script.
+               *nodes[1].chain_monitor.expect_monitor_round_trip_fail.lock().unwrap() = Some(chan_id);
+               let commitment_tx_conf_height = block_from_scid(&mine_transaction(&nodes[1], &commitment_tx));
+               let serialized_monitor = get_monitor!(nodes[1], chan_id).encode();
+               reload_node!(nodes[1], user_config, &nodes[1].node.encode(), &[&serialized_monitor], persister, chain_monitor, node_deserialized);
+               commitment_tx_conf_height
+       } else {
+               let serialized_monitor = get_monitor!(nodes[1], chan_id).encode();
+               reload_node!(nodes[1], user_config, &nodes[1].node.encode(), &[&serialized_monitor], persister, chain_monitor, node_deserialized);
+               let commitment_tx_conf_height = block_from_scid(&mine_transaction(&nodes[1], &commitment_tx));
+               check_added_monitors(&nodes[1], 1);
+               check_closed_broadcast(&nodes[1], 1, true);
+               commitment_tx_conf_height
+       };
+       check_closed_event!(&nodes[1], 1, ClosureReason::CommitmentTxConfirmed, false,
+                [nodes[0].node.get_our_node_id()], 100000);
+       assert!(get_monitor!(nodes[1], chan_id).get_counterparty_payment_script().is_v0_p2wsh());
+
+       connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1);
+       connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1);
+
+       if confirm_commitment_before_reload {
+               // If we saw the commitment before our `counterparty_payment_script` was fixed, we'll never
+               // get the spendable output event for the `to_remote` output, so we'll need to get it
+               // manually via `get_spendable_outputs`.
+               check_added_monitors(&nodes[1], 1);
+               let outputs = get_monitor!(nodes[1], chan_id).get_spendable_outputs(&commitment_tx, commitment_tx_conf_height);
+               assert_eq!(outputs.len(), 1);
+               let spend_tx = nodes[1].keys_manager.backing.spend_spendable_outputs(
+                       &[&outputs[0]], Vec::new(), Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(),
+                       253, None, &secp
+               ).unwrap();
+               check_spends!(spend_tx, &commitment_tx);
+       } else {
+               test_spendable_output(&nodes[1], &commitment_tx);
+       }
+}
+
+#[test]
+fn test_anchors_monitor_fixes_counterparty_payment_script_on_reload() {
+       do_test_anchors_monitor_fixes_counterparty_payment_script_on_reload(false);
+       do_test_anchors_monitor_fixes_counterparty_payment_script_on_reload(true);
+}
index 2522f99fbe85dbecd751034215207cbda23ad5ab..1642f28efc7b36dbfa7739bf886ebb58b9eb7c70 100644 (file)
@@ -1502,6 +1502,9 @@ impl OutboundPayments {
                &self, pending_events: &Mutex<VecDeque<(events::Event, Option<EventCompletionAction>)>>)
        {
                let mut pending_outbound_payments = self.pending_outbound_payments.lock().unwrap();
+               #[cfg(not(invreqfailed))]
+               let pending_events = pending_events.lock().unwrap();
+               #[cfg(invreqfailed)]
                let mut pending_events = pending_events.lock().unwrap();
                pending_outbound_payments.retain(|payment_id, payment| {
                        // If an outbound payment was completed, and no pending HTLCs remain, we should remove it
@@ -1540,6 +1543,7 @@ impl OutboundPayments {
                                if *timer_ticks_without_response <= INVOICE_REQUEST_TIMEOUT_TICKS {
                                        true
                                } else {
+                                       #[cfg(invreqfailed)]
                                        pending_events.push_back(
                                                (events::Event::InvoiceRequestFailed { payment_id: *payment_id }, None)
                                        );
@@ -1692,6 +1696,7 @@ impl OutboundPayments {
                                        payment.remove();
                                }
                        } else if let PendingOutboundPayment::AwaitingInvoice { .. } = payment.get() {
+                               #[cfg(invreqfailed)]
                                pending_events.lock().unwrap().push_back((events::Event::InvoiceRequestFailed {
                                        payment_id,
                                }, None));
@@ -1782,7 +1787,9 @@ mod tests {
        use crate::ln::channelmanager::{PaymentId, RecipientOnionFields};
        use crate::ln::features::{ChannelFeatures, NodeFeatures};
        use crate::ln::msgs::{ErrorAction, LightningError};
-       use crate::ln::outbound_payment::{Bolt12PaymentError, INVOICE_REQUEST_TIMEOUT_TICKS, OutboundPayments, Retry, RetryableSendFailure};
+       use crate::ln::outbound_payment::{Bolt12PaymentError, OutboundPayments, Retry, RetryableSendFailure};
+       #[cfg(invreqfailed)]
+       use crate::ln::outbound_payment::INVOICE_REQUEST_TIMEOUT_TICKS;
        use crate::offers::invoice::DEFAULT_RELATIVE_EXPIRY;
        use crate::offers::offer::OfferBuilder;
        use crate::offers::test_utils::*;
@@ -1985,6 +1992,7 @@ mod tests {
        }
 
        #[test]
+       #[cfg(invreqfailed)]
        fn removes_stale_awaiting_invoice() {
                let pending_events = Mutex::new(VecDeque::new());
                let outbound_payments = OutboundPayments::new();
@@ -2023,6 +2031,7 @@ mod tests {
        }
 
        #[test]
+       #[cfg(invreqfailed)]
        fn removes_abandoned_awaiting_invoice() {
                let pending_events = Mutex::new(VecDeque::new());
                let outbound_payments = OutboundPayments::new();
index 151861411b997002de4792d5c031ed8079faee2e..5f4009d642949ca42d0b1bbe73401b9bb657b233 100644 (file)
@@ -25,7 +25,6 @@ use crate::util::ser::{Writeable, ReadableArgs};
 use crate::util::config::UserConfig;
 use crate::util::string::UntrustedString;
 
-use bitcoin::{PackedLockTime, Transaction, TxOut};
 use bitcoin::hash_types::BlockHash;
 
 use crate::prelude::*;
index cb3471763d4b7e2075761ed466b718cd64d6797d..b745453a3c6799e012ddf3368be4136ef4831653 100644 (file)
@@ -9,10 +9,11 @@
 
 //! Further functional tests which test blockchain reorganizations.
 
+use crate::chain::chaininterface::LowerBoundedFeeEstimator;
 use crate::chain::channelmonitor::{ANTI_REORG_DELAY, LATENCY_GRACE_PERIOD_BLOCKS};
 use crate::chain::transaction::OutPoint;
 use crate::chain::Confirm;
-use crate::events::{Event, MessageSendEventsProvider, ClosureReason, HTLCDestination};
+use crate::events::{Event, MessageSendEventsProvider, ClosureReason, HTLCDestination, MessageSendEvent};
 use crate::ln::msgs::{ChannelMessageHandler, Init};
 use crate::util::test_utils;
 use crate::util::ser::Writeable;
@@ -617,3 +618,139 @@ fn test_to_remote_after_local_detection() {
        do_test_to_remote_after_local_detection(ConnectStyle::TransactionsFirstReorgsOnlyTip);
        do_test_to_remote_after_local_detection(ConnectStyle::FullBlockViaListen);
 }
+
+#[test]
+fn test_htlc_preimage_claim_holder_commitment_after_counterparty_commitment_reorg() {
+       // We detect a counterparty commitment confirm onchain, followed by a reorg and a confirmation
+       // of a holder commitment. Then, if we learn of the preimage for an HTLC in both commitments,
+       // test that we only claim the currently confirmed commitment.
+       let chanmon_cfgs = create_chanmon_cfgs(2);
+       let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
+       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None, None]);
+       let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+
+       let (_, _, chan_id, funding_tx) = create_announced_chan_between_nodes(&nodes, 0, 1);
+
+       // Route an HTLC which we will claim onchain with the preimage.
+       let (payment_preimage, payment_hash, ..) = route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
+
+       // Force close with the latest counterparty commitment, confirm it, and reorg it with the latest
+       // holder commitment.
+       nodes[0].node.force_close_broadcasting_latest_txn(&chan_id, &nodes[1].node.get_our_node_id()).unwrap();
+       check_closed_broadcast(&nodes[0], 1, true);
+       check_added_monitors(&nodes[0], 1);
+       check_closed_event(&nodes[0], 1, ClosureReason::HolderForceClosed, false, &[nodes[1].node.get_our_node_id()], 100000);
+
+       nodes[1].node.force_close_broadcasting_latest_txn(&chan_id, &nodes[0].node.get_our_node_id()).unwrap();
+       check_closed_broadcast(&nodes[1], 1, true);
+       check_added_monitors(&nodes[1], 1);
+       check_closed_event(&nodes[1], 1, ClosureReason::HolderForceClosed, false, &[nodes[0].node.get_our_node_id()], 100000);
+
+       let mut txn = nodes[0].tx_broadcaster.txn_broadcast();
+       assert_eq!(txn.len(), 1);
+       let commitment_tx_a = txn.pop().unwrap();
+       check_spends!(commitment_tx_a, funding_tx);
+
+       let mut txn = nodes[1].tx_broadcaster.txn_broadcast();
+       assert_eq!(txn.len(), 1);
+       let commitment_tx_b = txn.pop().unwrap();
+       check_spends!(commitment_tx_b, funding_tx);
+
+       mine_transaction(&nodes[0], &commitment_tx_a);
+       mine_transaction(&nodes[1], &commitment_tx_a);
+
+       disconnect_blocks(&nodes[0], 1);
+       disconnect_blocks(&nodes[1], 1);
+
+       mine_transaction(&nodes[0], &commitment_tx_b);
+       mine_transaction(&nodes[1], &commitment_tx_b);
+
+       // Provide the preimage now, such that we only claim from the holder commitment (since it's
+       // currently confirmed) and not the counterparty's.
+       get_monitor!(nodes[1], chan_id).provide_payment_preimage(
+               &payment_hash, &payment_preimage, &nodes[1].tx_broadcaster,
+               &LowerBoundedFeeEstimator(nodes[1].fee_estimator), &nodes[1].logger
+       );
+
+       let mut txn = nodes[1].tx_broadcaster.txn_broadcast();
+       assert_eq!(txn.len(), 1);
+       let htlc_success_tx = txn.pop().unwrap();
+       check_spends!(htlc_success_tx, commitment_tx_b);
+}
+
+#[test]
+fn test_htlc_preimage_claim_prev_counterparty_commitment_after_current_counterparty_commitment_reorg() {
+       // We detect a counterparty commitment confirm onchain, followed by a reorg and a
+       // confirmation of the previous (still unrevoked) counterparty commitment. Then, if we learn
+       // of the preimage for an HTLC in both commitments, test that we only claim the currently
+       // confirmed commitment.
+       let chanmon_cfgs = create_chanmon_cfgs(2);
+       let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
+       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None, None]);
+       let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+
+       let (_, _, chan_id, funding_tx) = create_announced_chan_between_nodes(&nodes, 0, 1);
+
+       // Route an HTLC which we will claim onchain with the preimage.
+       let (payment_preimage, payment_hash, ..) = route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
+
+       // Obtain the current commitment, which will become the previous after a fee update.
+       let prev_commitment_a = &get_local_commitment_txn!(nodes[0], chan_id)[0];
+
+       *nodes[0].fee_estimator.sat_per_kw.lock().unwrap() *= 4;
+       nodes[0].node.timer_tick_occurred();
+       check_added_monitors(&nodes[0], 1);
+       let mut msg_events = nodes[0].node.get_and_clear_pending_msg_events();
+       assert_eq!(msg_events.len(), 1);
+       let (update_fee, commit_sig) = if let MessageSendEvent::UpdateHTLCs { node_id, mut updates } = msg_events.pop().unwrap() {
+               assert_eq!(node_id, nodes[1].node.get_our_node_id());
+               (updates.update_fee.take().unwrap(), updates.commitment_signed)
+       } else {
+               panic!("Unexpected message send event");
+       };
+
+       // Handle the fee update on the other side, but don't send the last RAA such that the previous
+       // commitment is still valid (unrevoked).
+       nodes[1].node().handle_update_fee(&nodes[0].node.get_our_node_id(), &update_fee);
+       let _last_revoke_and_ack = commitment_signed_dance!(nodes[1], nodes[0], commit_sig, false, true, false, true);
+
+       // Force close with the latest commitment, confirm it, and reorg it with the previous commitment.
+       nodes[0].node.force_close_broadcasting_latest_txn(&chan_id, &nodes[1].node.get_our_node_id()).unwrap();
+       check_closed_broadcast(&nodes[0], 1, true);
+       check_added_monitors(&nodes[0], 1);
+       check_closed_event(&nodes[0], 1, ClosureReason::HolderForceClosed, false, &[nodes[1].node.get_our_node_id()], 100000);
+
+       let mut txn = nodes[0].tx_broadcaster.txn_broadcast();
+       assert_eq!(txn.len(), 1);
+       let current_commitment_a = txn.pop().unwrap();
+       assert_ne!(current_commitment_a.txid(), prev_commitment_a.txid());
+       check_spends!(current_commitment_a, funding_tx);
+
+       mine_transaction(&nodes[0], &current_commitment_a);
+       mine_transaction(&nodes[1], &current_commitment_a);
+
+       check_closed_broadcast(&nodes[1], 1, true);
+       check_added_monitors(&nodes[1], 1);
+       check_closed_event(&nodes[1], 1, ClosureReason::CommitmentTxConfirmed, false, &[nodes[0].node.get_our_node_id()], 100000);
+
+       disconnect_blocks(&nodes[0], 1);
+       disconnect_blocks(&nodes[1], 1);
+
+       mine_transaction(&nodes[0], &prev_commitment_a);
+       mine_transaction(&nodes[1], &prev_commitment_a);
+
+       // Provide the preimage now, such that we only claim from the previous commitment (since it's
+       // currently confirmed) and not the latest.
+       get_monitor!(nodes[1], chan_id).provide_payment_preimage(
+               &payment_hash, &payment_preimage, &nodes[1].tx_broadcaster,
+               &LowerBoundedFeeEstimator(nodes[1].fee_estimator), &nodes[1].logger
+       );
+
+       let mut txn = nodes[1].tx_broadcaster.txn_broadcast();
+       assert_eq!(txn.len(), 1);
+       let htlc_preimage_tx = txn.pop().unwrap();
+       check_spends!(htlc_preimage_tx, prev_commitment_a);
+       // Make sure it was indeed a preimage claim and not a revocation claim since the previous
+       // commitment (still unrevoked) is the currently confirmed closing transaction.
+       assert_eq!(htlc_preimage_tx.input[0].witness.second_to_last().unwrap(), &payment_preimage.0[..]);
+}
index 07bb72ce9cb7036179adff1083b23d39b1c76ea3..47361693693db731a85dee326f85ca54eeecad5f 100644 (file)
@@ -264,7 +264,7 @@ fn shutdown_on_unfunded_channel() {
        nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 1_000_000, 100_000, 0, None).unwrap();
        let open_chan = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 
-       // P2WSH
+       // Create a dummy P2WPKH script
        let script = Builder::new().push_int(0)
                .push_slice(&[0; 20])
                .into_script();
index 33182f7cb0d87f94723356345e0a2f3199b5eeb1..1297322fbd49d6c0a16582e2b06be5858bfff6f2 100644 (file)
@@ -2870,6 +2870,7 @@ mod tests {
                        inbound_scid_alias: None,
                        channel_value_satoshis: 0,
                        user_channel_id: 0,
+                       balance_msat: 0,
                        outbound_capacity_msat,
                        next_outbound_htlc_limit_msat: outbound_capacity_msat,
                        next_outbound_htlc_minimum_msat: 0,
@@ -7780,6 +7781,7 @@ pub(crate) mod bench_utils {
                        outbound_scid_alias: None,
                        channel_value_satoshis: 10_000_000_000,
                        user_channel_id: 0,
+                       balance_msat: 10_000_000_000,
                        outbound_capacity_msat: 10_000_000_000,
                        next_outbound_htlc_minimum_msat: 0,
                        next_outbound_htlc_limit_msat: 10_000_000_000,
index 5b42796a94f9586fe2dd42fd7210fada4be7297f..39f1001c480fd45926aed14355d78068028bfdc5 100644 (file)
@@ -107,6 +107,12 @@ impl_writeable_tlv_based!(DelayedPaymentOutputDescriptor, {
        (12, channel_value_satoshis, required),
 });
 
+pub(crate) const P2WPKH_WITNESS_WEIGHT: u64 = 1 /* num stack items */ +
+       1 /* sig length */ +
+       73 /* sig including sighash flag */ +
+       1 /* pubkey length */ +
+       33 /* pubkey */;
+
 /// Information about a spendable output to our "payment key".
 ///
 /// See [`SpendableOutputDescriptor::StaticPaymentOutput`] for more details on how to spend this.
@@ -121,20 +127,52 @@ pub struct StaticPaymentOutputDescriptor {
        pub channel_keys_id: [u8; 32],
        /// The value of the channel which this transactions spends.
        pub channel_value_satoshis: u64,
+       /// The necessary channel parameters that need to be provided to the re-derived signer through
+       /// [`ChannelSigner::provide_channel_parameters`].
+       ///
+       /// Added as optional, but always `Some` if the descriptor was produced in v0.0.117 or later.
+       pub channel_transaction_parameters: Option<ChannelTransactionParameters>,
 }
 impl StaticPaymentOutputDescriptor {
+       /// Returns the `witness_script` of the spendable output.
+       ///
+       /// Note that this will only return `Some` for [`StaticPaymentOutputDescriptor`]s that
+       /// originated from an anchor outputs channel, as they take the form of a P2WSH script.
+       pub fn witness_script(&self) -> Option<Script> {
+               self.channel_transaction_parameters.as_ref()
+                       .and_then(|channel_params|
+                                if channel_params.channel_type_features.supports_anchors_zero_fee_htlc_tx() {
+                                       let payment_point = channel_params.holder_pubkeys.payment_point;
+                                       Some(chan_utils::get_to_countersignatory_with_anchors_redeemscript(&payment_point))
+                                } else {
+                                        None
+                                }
+                       )
+       }
+
        /// The maximum length a well-formed witness spending one of these should have.
        /// Note: If you have the grind_signatures feature enabled, this will be at least 1 byte
        /// shorter.
-       // Calculated as 1 byte legnth + 73 byte signature, 1 byte empty vec push, 1 byte length plus
-       // redeemscript push length.
-       pub const MAX_WITNESS_LENGTH: usize = 1 + 73 + 34;
+       pub fn max_witness_length(&self) -> usize {
+               if self.channel_transaction_parameters.as_ref()
+                       .map(|channel_params| channel_params.channel_type_features.supports_anchors_zero_fee_htlc_tx())
+                       .unwrap_or(false)
+               {
+                       let witness_script_weight = 1 /* pubkey push */ + 33 /* pubkey */ +
+                               1 /* OP_CHECKSIGVERIFY */ + 1 /* OP_1 */ + 1 /* OP_CHECKSEQUENCEVERIFY */;
+                       1 /* num witness items */ + 1 /* sig push */ + 73 /* sig including sighash flag */ +
+                               1 /* witness script push */ + witness_script_weight
+               } else {
+                       P2WPKH_WITNESS_WEIGHT as usize
+               }
+       }
 }
 impl_writeable_tlv_based!(StaticPaymentOutputDescriptor, {
        (0, outpoint, required),
        (2, output, required),
        (4, channel_keys_id, required),
        (6, channel_value_satoshis, required),
+       (7, channel_transaction_parameters, option),
 });
 
 /// Describes the necessary information to spend a spendable output.
@@ -201,15 +239,23 @@ pub enum SpendableOutputDescriptor {
        /// [`DelayedPaymentOutputDescriptor::to_self_delay`] contained here to
        /// [`chan_utils::get_revokeable_redeemscript`].
        DelayedPaymentOutput(DelayedPaymentOutputDescriptor),
-       /// An output to a P2WPKH, spendable exclusively by our payment key (i.e., the private key
-       /// which corresponds to the `payment_point` in [`ChannelSigner::pubkeys`]). The witness
-       /// in the spending input is, thus, simply:
+       /// An output spendable exclusively by our payment key (i.e., the private key that corresponds
+       /// to the `payment_point` in [`ChannelSigner::pubkeys`]). The output type depends on the
+       /// channel type negotiated.
+       ///
+       /// On an anchor outputs channel, the witness in the spending input is:
+       /// ```bitcoin
+       /// <BIP 143 signature> <witness script>
+       /// ```
+       ///
+       /// Otherwise, it is:
        /// ```bitcoin
        /// <BIP 143 signature> <payment key>
        /// ```
        ///
        /// These are generally the result of our counterparty having broadcast the current state,
-       /// allowing us to claim the non-HTLC-encumbered outputs immediately.
+       /// allowing us to claim the non-HTLC-encumbered outputs immediately, or after one confirmation
+       /// in the case of anchor outputs channels.
        StaticPaymentOutput(StaticPaymentOutputDescriptor),
 }
 
@@ -280,13 +326,22 @@ impl SpendableOutputDescriptor {
                        match outp {
                                SpendableOutputDescriptor::StaticPaymentOutput(descriptor) => {
                                        if !output_set.insert(descriptor.outpoint) { return Err(()); }
+                                       let sequence =
+                                               if descriptor.channel_transaction_parameters.as_ref()
+                                                       .map(|channel_params| channel_params.channel_type_features.supports_anchors_zero_fee_htlc_tx())
+                                                       .unwrap_or(false)
+                                               {
+                                                       Sequence::from_consensus(1)
+                                               } else {
+                                                       Sequence::ZERO
+                                               };
                                        input.push(TxIn {
                                                previous_output: descriptor.outpoint.into_bitcoin_outpoint(),
                                                script_sig: Script::new(),
-                                               sequence: Sequence::ZERO,
+                                               sequence,
                                                witness: Witness::new(),
                                        });
-                                       witness_weight += StaticPaymentOutputDescriptor::MAX_WITNESS_LENGTH;
+                                       witness_weight += descriptor.max_witness_length();
                                        #[cfg(feature = "grind_signatures")]
                                        { witness_weight -= 1; } // Guarantees a low R signature
                                        input_value += descriptor.output.value;
@@ -891,18 +946,30 @@ impl InMemorySigner {
                if !spend_tx.input[input_idx].script_sig.is_empty() { return Err(()); }
                if spend_tx.input[input_idx].previous_output != descriptor.outpoint.into_bitcoin_outpoint() { return Err(()); }
 
-               let remotepubkey = self.pubkeys().payment_point;
-               let witness_script = bitcoin::Address::p2pkh(&::bitcoin::PublicKey{compressed: true, inner: remotepubkey}, Network::Testnet).script_pubkey();
+               let remotepubkey = bitcoin::PublicKey::new(self.pubkeys().payment_point);
+               let witness_script = if self.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
+                       chan_utils::get_to_countersignatory_with_anchors_redeemscript(&remotepubkey.inner)
+               } else {
+                       Script::new_p2pkh(&remotepubkey.pubkey_hash())
+               };
                let sighash = hash_to_message!(&sighash::SighashCache::new(spend_tx).segwit_signature_hash(input_idx, &witness_script, descriptor.output.value, EcdsaSighashType::All).unwrap()[..]);
                let remotesig = sign_with_aux_rand(secp_ctx, &sighash, &self.payment_key, &self);
-               let payment_script = bitcoin::Address::p2wpkh(&::bitcoin::PublicKey{compressed: true, inner: remotepubkey}, Network::Bitcoin).unwrap().script_pubkey();
+               let payment_script = if self.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
+                       witness_script.to_v0_p2wsh()
+               } else {
+                       Script::new_v0_p2wpkh(&remotepubkey.wpubkey_hash().unwrap())
+               };
 
                if payment_script != descriptor.output.script_pubkey { return Err(()); }
 
                let mut witness = Vec::with_capacity(2);
                witness.push(remotesig.serialize_der().to_vec());
                witness[0].push(EcdsaSighashType::All as u8);
-               witness.push(remotepubkey.serialize().to_vec());
+               if self.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
+                       witness.push(witness_script.to_bytes());
+               } else {
+                       witness.push(remotepubkey.to_bytes());
+               }
                Ok(witness)
        }
 
@@ -1353,9 +1420,11 @@ impl KeysManager {
                                SpendableOutputDescriptor::StaticPaymentOutput(descriptor) => {
                                        let input_idx = psbt.unsigned_tx.input.iter().position(|i| i.previous_output == descriptor.outpoint.into_bitcoin_outpoint()).ok_or(())?;
                                        if keys_cache.is_none() || keys_cache.as_ref().unwrap().1 != descriptor.channel_keys_id {
-                                               keys_cache = Some((
-                                                       self.derive_channel_keys(descriptor.channel_value_satoshis, &descriptor.channel_keys_id),
-                                                       descriptor.channel_keys_id));
+                                               let mut signer = self.derive_channel_keys(descriptor.channel_value_satoshis, &descriptor.channel_keys_id);
+                                               if let Some(channel_params) = descriptor.channel_transaction_parameters.as_ref() {
+                                                       signer.provide_channel_parameters(channel_params);
+                                               }
+                                               keys_cache = Some((signer, descriptor.channel_keys_id));
                                        }
                                        let witness = Witness::from_vec(keys_cache.as_ref().unwrap().0.sign_counterparty_payment_input(&psbt.unsigned_tx, input_idx, &descriptor, &secp_ctx)?);
                                        psbt.inputs[input_idx].final_script_witness = Some(witness);
index 8b6e8091785663df18c5ac197eed3c679b2a15d5..73d2cceb3e85f9d84bf2404d7d9cbbfc204598d0 100644 (file)
@@ -24,6 +24,7 @@ impl<ECS: EcdsaChannelSigner> ChannelSignerType<ECS>{
                }
        }
 
+       #[allow(unused)]
        pub(crate) fn as_mut_ecdsa(&mut self) -> Option<&mut ECS> {
                match self {
                        ChannelSignerType::Ecdsa(ecs) => Some(ecs)
index bc9c0a32dd05c82019ff7cb21218e3a27a1001b1..4bcaca57f81ca61cd2af4d499d6ffbfa4f1b51e0 100644 (file)
@@ -207,6 +207,9 @@ pub struct TestChainMonitor<'a> {
        /// ChannelForceClosed event for the given channel_id with should_broadcast set to the given
        /// boolean.
        pub expect_channel_force_closed: Mutex<Option<(ChannelId, bool)>>,
+       /// If this is set to Some(), the next round trip serialization check will not hold after an
+       /// update_channel call (not watch_channel) for the given channel_id.
+       pub expect_monitor_round_trip_fail: Mutex<Option<ChannelId>>,
 }
 impl<'a> TestChainMonitor<'a> {
        pub fn new(chain_source: Option<&'a TestChainSource>, broadcaster: &'a chaininterface::BroadcasterInterface, logger: &'a TestLogger, fee_estimator: &'a TestFeeEstimator, persister: &'a chainmonitor::Persist<TestChannelSigner>, keys_manager: &'a TestKeysInterface) -> Self {
@@ -217,6 +220,7 @@ impl<'a> TestChainMonitor<'a> {
                        chain_monitor: chainmonitor::ChainMonitor::new(chain_source, broadcaster, logger, fee_estimator, persister),
                        keys_manager,
                        expect_channel_force_closed: Mutex::new(None),
+                       expect_monitor_round_trip_fail: Mutex::new(None),
                }
        }
 
@@ -267,7 +271,12 @@ impl<'a> chain::Watch<TestChannelSigner> for TestChainMonitor<'a> {
                monitor.write(&mut w).unwrap();
                let new_monitor = <(BlockHash, channelmonitor::ChannelMonitor<TestChannelSigner>)>::read(
                        &mut io::Cursor::new(&w.0), (self.keys_manager, self.keys_manager)).unwrap().1;
-               assert!(new_monitor == *monitor);
+               if let Some(chan_id) = self.expect_monitor_round_trip_fail.lock().unwrap().take() {
+                       assert_eq!(chan_id, funding_txo.to_channel_id());
+                       assert!(new_monitor != *monitor);
+               } else {
+                       assert!(new_monitor == *monitor);
+               }
                self.added_monitors.lock().unwrap().push((funding_txo, new_monitor));
                update_res
        }
diff --git a/pending_changelog/remove_balance_msat.txt b/pending_changelog/remove_balance_msat.txt
deleted file mode 100644 (file)
index 2ba5df1..0000000
+++ /dev/null
@@ -1 +0,0 @@
-* The `AvailableBalances::balance_msat` field has been removed in favor of `ChannelMonitor::get_claimable_balances`. `ChannelDetails` serialized with versions of LDK >= 0.0.117 will have their `balance_msat` field set to `next_outbound_htlc_limit_msat` when read by versions of LDK prior to 0.0.117 (#2476).