Avoid unwrap'ing `channel_parameters` in to_counterparty signing
authorMatt Corallo <git@bluematt.me>
Sun, 1 Oct 2023 00:15:22 +0000 (00:15 +0000)
committerMatt Corallo <git@bluematt.me>
Sun, 1 Oct 2023 00:40:20 +0000 (00:40 +0000)
Previously, `StaticPaymentOutputDescriptor`s did not include
`channel_parameters` for the signer. As a result, when going to
spend old `StaticPaymentOutputDescriptor`s,
`InMemorySigner::sign_counterparty_payment_input` may be called
with `channel_parameters` set to `None`. This should be fine, but
in fa2a2efef47b5da48ac7a239f3d8a835a7f28164 we started relying on
it (indirectly via `channel_features`) for signing. This caused an
`unwrap` when spending old output descriptors.

This is fixed here by simply avoiding the unwrap and assuming old
`StaticPaymentOutputDescriptor`s represent non-anchor channels.

lightning/src/sign/mod.rs

index 39f1001c480fd45926aed14355d78068028bfdc5..0c293a98c9070e60f8d1f0c5d9284d365d3e7633 100644 (file)
@@ -947,14 +947,20 @@ impl InMemorySigner {
                if spend_tx.input[input_idx].previous_output != descriptor.outpoint.into_bitcoin_outpoint() { return Err(()); }
 
                let remotepubkey = bitcoin::PublicKey::new(self.pubkeys().payment_point);
-               let witness_script = if self.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
+               // We cannot always assume that `channel_parameters` is set, so can't just call
+               // `self.channel_parameters()` or anything that relies on it
+               let supports_anchors_zero_fee_htlc_tx = self.channel_parameters.as_ref()
+                       .map(|params| params.channel_type_features.supports_anchors_zero_fee_htlc_tx())
+                       .unwrap_or(false);
+
+               let witness_script = if 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 = if self.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
+               let payment_script = if supports_anchors_zero_fee_htlc_tx {
                        witness_script.to_v0_p2wsh()
                } else {
                        Script::new_v0_p2wpkh(&remotepubkey.wpubkey_hash().unwrap())
@@ -965,7 +971,7 @@ impl InMemorySigner {
                let mut witness = Vec::with_capacity(2);
                witness.push(remotesig.serialize_der().to_vec());
                witness[0].push(EcdsaSighashType::All as u8);
-               if self.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
+               if supports_anchors_zero_fee_htlc_tx {
                        witness.push(witness_script.to_bytes());
                } else {
                        witness.push(remotepubkey.to_bytes());