Skip to content

Commit 65569ed

Browse files
committed
Make InMemorySigner parameter-fetching utilities return Options
In the previous commit we fixed a bug where we were spuriously (indirectly) `unwrap`ing the `channel_parameters` in `InMemorySigner`. Here we make such bugs much less likely in the future by having the utilities which do the `unwrap`ing internally return `Option`s instead. This makes the `unwrap`s clear at the callsite.
1 parent 6a55dcc commit 65569ed

File tree

2 files changed

+80
-43
lines changed

2 files changed

+80
-43
lines changed

lightning/src/sign/mod.rs

Lines changed: 69 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -893,42 +893,61 @@ impl InMemorySigner {
893893

894894
/// Returns the counterparty's pubkeys.
895895
///
896-
/// Will panic if [`ChannelSigner::provide_channel_parameters`] has not been called before.
897-
pub fn counterparty_pubkeys(&self) -> &ChannelPublicKeys { &self.get_channel_parameters().counterparty_parameters.as_ref().unwrap().pubkeys }
896+
/// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called.
897+
pub fn counterparty_pubkeys(&self) -> Option<&ChannelPublicKeys> {
898+
self.get_channel_parameters()
899+
.and_then(|params| params.counterparty_parameters.as_ref().map(|params| &params.pubkeys))
900+
}
901+
898902
/// Returns the `contest_delay` value specified by our counterparty and applied on holder-broadcastable
899903
/// transactions, i.e., the amount of time that we have to wait to recover our funds if we
900904
/// broadcast a transaction.
901905
///
902-
/// Will panic if [`ChannelSigner::provide_channel_parameters`] has not been called before.
903-
pub fn counterparty_selected_contest_delay(&self) -> u16 { self.get_channel_parameters().counterparty_parameters.as_ref().unwrap().selected_contest_delay }
906+
/// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called.
907+
pub fn counterparty_selected_contest_delay(&self) -> Option<u16> {
908+
self.get_channel_parameters()
909+
.and_then(|params| params.counterparty_parameters.as_ref().map(|params| params.selected_contest_delay))
910+
}
911+
904912
/// Returns the `contest_delay` value specified by us and applied on transactions broadcastable
905913
/// by our counterparty, i.e., the amount of time that they have to wait to recover their funds
906914
/// if they broadcast a transaction.
907915
///
908-
/// Will panic if [`ChannelSigner::provide_channel_parameters`] has not been called before.
909-
pub fn holder_selected_contest_delay(&self) -> u16 { self.get_channel_parameters().holder_selected_contest_delay }
916+
/// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called.
917+
pub fn holder_selected_contest_delay(&self) -> Option<u16> {
918+
self.get_channel_parameters().map(|params| params.holder_selected_contest_delay)
919+
}
920+
910921
/// Returns whether the holder is the initiator.
911922
///
912-
/// Will panic if [`ChannelSigner::provide_channel_parameters`] has not been called before.
913-
pub fn is_outbound(&self) -> bool { self.get_channel_parameters().is_outbound_from_holder }
923+
/// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called.
924+
pub fn is_outbound(&self) -> Option<bool> {
925+
self.get_channel_parameters().map(|params| params.is_outbound_from_holder)
926+
}
927+
914928
/// Funding outpoint
915929
///
916-
/// Will panic if [`ChannelSigner::provide_channel_parameters`] has not been called before.
917-
pub fn funding_outpoint(&self) -> &OutPoint { self.get_channel_parameters().funding_outpoint.as_ref().unwrap() }
930+
/// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called.
931+
pub fn funding_outpoint(&self) -> Option<&OutPoint> {
932+
self.get_channel_parameters().map(|params| params.funding_outpoint.as_ref()).flatten()
933+
}
934+
918935
/// Returns a [`ChannelTransactionParameters`] for this channel, to be used when verifying or
919936
/// building transactions.
920937
///
921-
/// Will panic if [`ChannelSigner::provide_channel_parameters`] has not been called before.
922-
pub fn get_channel_parameters(&self) -> &ChannelTransactionParameters {
923-
self.channel_parameters.as_ref().unwrap()
938+
/// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called.
939+
pub fn get_channel_parameters(&self) -> Option<&ChannelTransactionParameters> {
940+
self.channel_parameters.as_ref()
924941
}
942+
925943
/// Returns the channel type features of the channel parameters. Should be helpful for
926944
/// determining a channel's category, i. e. legacy/anchors/taproot/etc.
927945
///
928-
/// Will panic if [`ChannelSigner::provide_channel_parameters`] has not been called before.
929-
pub fn channel_type_features(&self) -> &ChannelTypeFeatures {
930-
&self.get_channel_parameters().channel_type_features
946+
/// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called.
947+
pub fn channel_type_features(&self) -> Option<&ChannelTypeFeatures> {
948+
self.get_channel_parameters().map(|params| &params.channel_type_features)
931949
}
950+
932951
/// Sign the single input of `spend_tx` at index `input_idx`, which spends the output described
933952
/// by `descriptor`, returning the witness stack for the input.
934953
///
@@ -949,8 +968,8 @@ impl InMemorySigner {
949968
let remotepubkey = bitcoin::PublicKey::new(self.pubkeys().payment_point);
950969
// We cannot always assume that `channel_parameters` is set, so can't just call
951970
// `self.channel_parameters()` or anything that relies on it
952-
let supports_anchors_zero_fee_htlc_tx = self.channel_parameters.as_ref()
953-
.map(|params| params.channel_type_features.supports_anchors_zero_fee_htlc_tx())
971+
let supports_anchors_zero_fee_htlc_tx = self.channel_type_features()
972+
.map(|features| features.supports_anchors_zero_fee_htlc_tx())
954973
.unwrap_or(false);
955974

956975
let witness_script = if supports_anchors_zero_fee_htlc_tx {
@@ -1055,24 +1074,30 @@ impl ChannelSigner for InMemorySigner {
10551074
}
10561075
}
10571076

1077+
const MISSING_PARAMS_ERR: &'static str = "ChannelSigner::provide_channel_parameters must be called before signing operations";
1078+
10581079
impl EcdsaChannelSigner for InMemorySigner {
10591080
fn sign_counterparty_commitment(&self, commitment_tx: &CommitmentTransaction, _preimages: Vec<PaymentPreimage>, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<(Signature, Vec<Signature>), ()> {
10601081
let trusted_tx = commitment_tx.trust();
10611082
let keys = trusted_tx.keys();
10621083

10631084
let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key);
1064-
let channel_funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey);
1085+
let counterparty_keys = self.counterparty_pubkeys().expect(MISSING_PARAMS_ERR);
1086+
let channel_funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &counterparty_keys.funding_pubkey);
10651087

10661088
let built_tx = trusted_tx.built_transaction();
10671089
let commitment_sig = built_tx.sign_counterparty_commitment(&self.funding_key, &channel_funding_redeemscript, self.channel_value_satoshis, secp_ctx);
10681090
let commitment_txid = built_tx.txid;
10691091

10701092
let mut htlc_sigs = Vec::with_capacity(commitment_tx.htlcs().len());
10711093
for htlc in commitment_tx.htlcs() {
1072-
let channel_parameters = self.get_channel_parameters();
1073-
let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, commitment_tx.feerate_per_kw(), self.holder_selected_contest_delay(), htlc, &channel_parameters.channel_type_features, &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
1074-
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, self.channel_type_features(), &keys);
1075-
let htlc_sighashtype = if self.channel_type_features().supports_anchors_zero_fee_htlc_tx() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All };
1094+
let channel_parameters = self.get_channel_parameters().expect(MISSING_PARAMS_ERR);
1095+
let holder_selected_contest_delay =
1096+
self.holder_selected_contest_delay().expect(MISSING_PARAMS_ERR);
1097+
let chan_type = &channel_parameters.channel_type_features;
1098+
let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, commitment_tx.feerate_per_kw(), holder_selected_contest_delay, htlc, chan_type, &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
1099+
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, chan_type, &keys);
1100+
let htlc_sighashtype = if chan_type.supports_anchors_zero_fee_htlc_tx() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All };
10761101
let htlc_sighash = hash_to_message!(&sighash::SighashCache::new(&htlc_tx).segwit_signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, htlc_sighashtype).unwrap()[..]);
10771102
let holder_htlc_key = chan_utils::derive_private_key(&secp_ctx, &keys.per_commitment_point, &self.htlc_base_key);
10781103
htlc_sigs.push(sign(secp_ctx, &htlc_sighash, &holder_htlc_key));
@@ -1087,21 +1112,23 @@ impl EcdsaChannelSigner for InMemorySigner {
10871112

10881113
fn sign_holder_commitment_and_htlcs(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<(Signature, Vec<Signature>), ()> {
10891114
let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key);
1090-
let funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey);
1115+
let counterparty_keys = self.counterparty_pubkeys().expect(MISSING_PARAMS_ERR);
1116+
let funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &counterparty_keys.funding_pubkey);
10911117
let trusted_tx = commitment_tx.trust();
10921118
let sig = trusted_tx.built_transaction().sign_holder_commitment(&self.funding_key, &funding_redeemscript, self.channel_value_satoshis, &self, secp_ctx);
1093-
let channel_parameters = self.get_channel_parameters();
1119+
let channel_parameters = self.get_channel_parameters().expect(MISSING_PARAMS_ERR);
10941120
let htlc_sigs = trusted_tx.get_htlc_sigs(&self.htlc_base_key, &channel_parameters.as_holder_broadcastable(), &self, secp_ctx)?;
10951121
Ok((sig, htlc_sigs))
10961122
}
10971123

10981124
#[cfg(any(test,feature = "unsafe_revoked_tx_signing"))]
10991125
fn unsafe_sign_holder_commitment_and_htlcs(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<(Signature, Vec<Signature>), ()> {
11001126
let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key);
1101-
let funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey);
1127+
let counterparty_keys = self.counterparty_pubkeys().expect(MISSING_PARAMS_ERR);
1128+
let funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &counterparty_keys.funding_pubkey);
11021129
let trusted_tx = commitment_tx.trust();
11031130
let sig = trusted_tx.built_transaction().sign_holder_commitment(&self.funding_key, &funding_redeemscript, self.channel_value_satoshis, &self, secp_ctx);
1104-
let channel_parameters = self.get_channel_parameters();
1131+
let channel_parameters = self.get_channel_parameters().expect(MISSING_PARAMS_ERR);
11051132
let htlc_sigs = trusted_tx.get_htlc_sigs(&self.htlc_base_key, &channel_parameters.as_holder_broadcastable(), &self, secp_ctx)?;
11061133
Ok((sig, htlc_sigs))
11071134
}
@@ -1111,8 +1138,11 @@ impl EcdsaChannelSigner for InMemorySigner {
11111138
let per_commitment_point = PublicKey::from_secret_key(secp_ctx, &per_commitment_key);
11121139
let revocation_pubkey = chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &self.pubkeys().revocation_basepoint);
11131140
let witness_script = {
1114-
let counterparty_delayedpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.counterparty_pubkeys().delayed_payment_basepoint);
1115-
chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.holder_selected_contest_delay(), &counterparty_delayedpubkey)
1141+
let counterparty_keys = self.counterparty_pubkeys().expect(MISSING_PARAMS_ERR);
1142+
let holder_selected_contest_delay =
1143+
self.holder_selected_contest_delay().expect(MISSING_PARAMS_ERR);
1144+
let counterparty_delayedpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &counterparty_keys.delayed_payment_basepoint);
1145+
chan_utils::get_revokeable_redeemscript(&revocation_pubkey, holder_selected_contest_delay, &counterparty_delayedpubkey)
11161146
};
11171147
let mut sighash_parts = sighash::SighashCache::new(justice_tx);
11181148
let sighash = hash_to_message!(&sighash_parts.segwit_signature_hash(input, &witness_script, amount, EcdsaSighashType::All).unwrap()[..]);
@@ -1124,9 +1154,11 @@ impl EcdsaChannelSigner for InMemorySigner {
11241154
let per_commitment_point = PublicKey::from_secret_key(secp_ctx, &per_commitment_key);
11251155
let revocation_pubkey = chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &self.pubkeys().revocation_basepoint);
11261156
let witness_script = {
1127-
let counterparty_htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.counterparty_pubkeys().htlc_basepoint);
1157+
let counterparty_keys = self.counterparty_pubkeys().expect(MISSING_PARAMS_ERR);
1158+
let counterparty_htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &counterparty_keys.htlc_basepoint);
11281159
let holder_htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.pubkeys().htlc_basepoint);
1129-
chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, self.channel_type_features(), &counterparty_htlcpubkey, &holder_htlcpubkey, &revocation_pubkey)
1160+
let chan_type = self.channel_type_features().expect(MISSING_PARAMS_ERR);
1161+
chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, chan_type, &counterparty_htlcpubkey, &holder_htlcpubkey, &revocation_pubkey)
11301162
};
11311163
let mut sighash_parts = sighash::SighashCache::new(justice_tx);
11321164
let sighash = hash_to_message!(&sighash_parts.segwit_signature_hash(input, &witness_script, amount, EcdsaSighashType::All).unwrap()[..]);
@@ -1150,17 +1182,20 @@ impl EcdsaChannelSigner for InMemorySigner {
11501182
fn sign_counterparty_htlc_transaction(&self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()> {
11511183
let htlc_key = chan_utils::derive_private_key(&secp_ctx, &per_commitment_point, &self.htlc_base_key);
11521184
let revocation_pubkey = chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &self.pubkeys().revocation_basepoint);
1153-
let counterparty_htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.counterparty_pubkeys().htlc_basepoint);
1185+
let counterparty_keys = self.counterparty_pubkeys().expect(MISSING_PARAMS_ERR);
1186+
let counterparty_htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &counterparty_keys.htlc_basepoint);
11541187
let htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.pubkeys().htlc_basepoint);
1155-
let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, self.channel_type_features(), &counterparty_htlcpubkey, &htlcpubkey, &revocation_pubkey);
1188+
let chan_type = self.channel_type_features().expect(MISSING_PARAMS_ERR);
1189+
let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, chan_type, &counterparty_htlcpubkey, &htlcpubkey, &revocation_pubkey);
11561190
let mut sighash_parts = sighash::SighashCache::new(htlc_tx);
11571191
let sighash = hash_to_message!(&sighash_parts.segwit_signature_hash(input, &witness_script, amount, EcdsaSighashType::All).unwrap()[..]);
11581192
Ok(sign_with_aux_rand(secp_ctx, &sighash, &htlc_key, &self))
11591193
}
11601194

11611195
fn sign_closing_transaction(&self, closing_tx: &ClosingTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()> {
11621196
let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key);
1163-
let channel_funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey);
1197+
let counterparty_funding_key = &self.counterparty_pubkeys().expect(MISSING_PARAMS_ERR).funding_pubkey;
1198+
let channel_funding_redeemscript = make_funding_redeemscript(&funding_pubkey, counterparty_funding_key);
11641199
Ok(closing_tx.trust().sign(&self.funding_key, &channel_funding_redeemscript, self.channel_value_satoshis, secp_ctx))
11651200
}
11661201

lightning/src/util/test_channel_signer.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ impl TestChannelSigner {
8888
}
8989
}
9090

91-
pub fn channel_type_features(&self) -> &ChannelTypeFeatures { self.inner.channel_type_features() }
91+
pub fn channel_type_features(&self) -> &ChannelTypeFeatures { self.inner.channel_type_features().unwrap() }
9292

9393
#[cfg(test)]
9494
pub fn get_enforcement_state(&self) -> MutexGuard<EnforcementState> {
@@ -158,7 +158,7 @@ impl EcdsaChannelSigner for TestChannelSigner {
158158
fn sign_holder_commitment_and_htlcs(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<(Signature, Vec<Signature>), ()> {
159159
let trusted_tx = self.verify_holder_commitment_tx(commitment_tx, secp_ctx);
160160
let commitment_txid = trusted_tx.txid();
161-
let holder_csv = self.inner.counterparty_selected_contest_delay();
161+
let holder_csv = self.inner.counterparty_selected_contest_delay().unwrap();
162162

163163
let state = self.state.lock().unwrap();
164164
let commitment_number = trusted_tx.commitment_number();
@@ -219,7 +219,7 @@ impl EcdsaChannelSigner for TestChannelSigner {
219219
}
220220

221221
fn sign_closing_transaction(&self, closing_tx: &ClosingTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()> {
222-
closing_tx.verify(self.inner.funding_outpoint().into_bitcoin_outpoint())
222+
closing_tx.verify(self.inner.funding_outpoint().unwrap().into_bitcoin_outpoint())
223223
.expect("derived different closing transaction");
224224
Ok(self.inner.sign_closing_transaction(closing_tx, secp_ctx).unwrap())
225225
}
@@ -256,15 +256,17 @@ impl Writeable for TestChannelSigner {
256256

257257
impl TestChannelSigner {
258258
fn verify_counterparty_commitment_tx<'a, T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &'a CommitmentTransaction, secp_ctx: &Secp256k1<T>) -> TrustedCommitmentTransaction<'a> {
259-
commitment_tx.verify(&self.inner.get_channel_parameters().as_counterparty_broadcastable(),
260-
self.inner.counterparty_pubkeys(), self.inner.pubkeys(), secp_ctx)
261-
.expect("derived different per-tx keys or built transaction")
259+
commitment_tx.verify(
260+
&self.inner.get_channel_parameters().unwrap().as_counterparty_broadcastable(),
261+
self.inner.counterparty_pubkeys().unwrap(), self.inner.pubkeys(), secp_ctx
262+
).expect("derived different per-tx keys or built transaction")
262263
}
263264

264265
fn verify_holder_commitment_tx<'a, T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &'a CommitmentTransaction, secp_ctx: &Secp256k1<T>) -> TrustedCommitmentTransaction<'a> {
265-
commitment_tx.verify(&self.inner.get_channel_parameters().as_holder_broadcastable(),
266-
self.inner.pubkeys(), self.inner.counterparty_pubkeys(), secp_ctx)
267-
.expect("derived different per-tx keys or built transaction")
266+
commitment_tx.verify(
267+
&self.inner.get_channel_parameters().unwrap().as_holder_broadcastable(),
268+
self.inner.pubkeys(), self.inner.counterparty_pubkeys().unwrap(), secp_ctx
269+
).expect("derived different per-tx keys or built transaction")
268270
}
269271
}
270272

0 commit comments

Comments
 (0)