Skip to content

Commit e95ebf8

Browse files
committed
Properly handle funding key rotation during splices
When splicing, we're required by protocol to retain all the existing keys material except the funding key which we're allowed to rotate. In the original implementation we acknowledged that but figured we'd stick with a single `pubkey` method in the `ChannelSigner` anyway cause adding a specific method for it is annoying. Sadly, this was ultimately broken - in `FundingScope::for_splice`, we called the signer's `new_pubkeys` method (renamed from `pubkeys` after splicing initially landed), replacing all of the public keys the `Channel` would use rather than just the funding key. This can result in commitment signature mismatches if the signer changes any keys aside from the funding one. `InMemorySigner` did not do so, however, so we didn't notice the bug. Luckily-ish, in 189b8ac we started generating a fresh `remote_key` when splicing (at least when upgrading from 0.1 to 0.2 or when setting `KeysManager` to use v1 `remote_key` derivation). This breaks splicing cause we can't communicate the new `remote_key` to the counterparty during the splicing handshake. Ultimately this bug is because the API we had didn't communicate to the signer that we weren't allowed to change anything except the funding key, and allowed returning a `ChannelPublicKeys` which would break the channel. Here we fix this by renaming `new_pubkeys` `pubkeys` again (partially reverting 9d291e0 but keeping the changed requirements that `pubkeys` only be called once) and adding a new `ChannelSigner:new_funding_pubkey` method specifically for splicing. We also update `channel.rs` to correctly fetch the new funding pubkey before sending `splice_init`, storing it in the `PendingFunding` untl we build a `FundingScope`.
1 parent b84ad65 commit e95ebf8

File tree

7 files changed

+112
-76
lines changed

7 files changed

+112
-76
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7009,7 +7009,7 @@ mod tests {
70097009
let funding_outpoint = OutPoint { txid: Txid::all_zeros(), index: u16::MAX };
70107010
let channel_id = ChannelId::v1_from_funding_outpoint(funding_outpoint);
70117011
let channel_parameters = ChannelTransactionParameters {
7012-
holder_pubkeys: keys.new_pubkeys(None, &secp_ctx),
7012+
holder_pubkeys: keys.pubkeys(&secp_ctx),
70137013
holder_selected_contest_delay: 66,
70147014
is_outbound_from_holder: true,
70157015
counterparty_parameters: Some(CounterpartyChannelTransactionParameters {
@@ -7272,7 +7272,7 @@ mod tests {
72727272
let funding_outpoint = OutPoint { txid: Txid::all_zeros(), index: u16::MAX };
72737273
let channel_id = ChannelId::v1_from_funding_outpoint(funding_outpoint);
72747274
let channel_parameters = ChannelTransactionParameters {
7275-
holder_pubkeys: keys.new_pubkeys(None, &secp_ctx),
7275+
holder_pubkeys: keys.pubkeys(&secp_ctx),
72767276
holder_selected_contest_delay: 66,
72777277
is_outbound_from_holder: true,
72787278
counterparty_parameters: Some(CounterpartyChannelTransactionParameters {

lightning/src/chain/onchaintx.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1339,7 +1339,7 @@ mod tests {
13391339
// Use non-anchor channels so that HTLC-Timeouts are broadcast immediately instead of sent
13401340
// to the user for external funding.
13411341
let chan_params = ChannelTransactionParameters {
1342-
holder_pubkeys: signer.new_pubkeys(None, &secp_ctx),
1342+
holder_pubkeys: signer.pubkeys(&secp_ctx),
13431343
holder_selected_contest_delay: 66,
13441344
is_outbound_from_holder: true,
13451345
counterparty_parameters: Some(CounterpartyChannelTransactionParameters {

lightning/src/ln/chan_utils.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,11 +1018,11 @@ pub struct ChannelTransactionParameters {
10181018
/// If a channel was funded with transaction A, and later spliced with transaction B, this field
10191019
/// tracks the txid of transaction A.
10201020
///
1021-
/// See [`compute_funding_key_tweak`] and [`ChannelSigner::new_pubkeys`] for more context on how
1021+
/// See [`compute_funding_key_tweak`] and [`ChannelSigner::pubkeys`] for more context on how
10221022
/// this may be used.
10231023
///
10241024
/// [`compute_funding_key_tweak`]: crate::sign::compute_funding_key_tweak
1025-
/// [`ChannelSigner::new_pubkeys`]: crate::sign::ChannelSigner::new_pubkeys
1025+
/// [`ChannelSigner::pubkeys`]: crate::sign::ChannelSigner::pubkeys
10261026
pub splice_parent_funding_txid: Option<Txid>,
10271027
/// This channel's type, as negotiated during channel open. For old objects where this field
10281028
/// wasn't serialized, it will default to static_remote_key at deserialization.
@@ -2245,8 +2245,8 @@ mod tests {
22452245
let counterparty_signer = keys_provider.derive_channel_signer(keys_provider.generate_channel_keys_id(true, 1));
22462246
let per_commitment_secret = SecretKey::from_slice(&<Vec<u8>>::from_hex("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100").unwrap()[..]).unwrap();
22472247
let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &per_commitment_secret);
2248-
let holder_pubkeys = signer.new_pubkeys(None, &secp_ctx);
2249-
let counterparty_pubkeys = counterparty_signer.new_pubkeys(None, &secp_ctx).clone();
2248+
let holder_pubkeys = signer.pubkeys(&secp_ctx);
2249+
let counterparty_pubkeys = counterparty_signer.pubkeys(&secp_ctx).clone();
22502250
let channel_parameters = ChannelTransactionParameters {
22512251
holder_pubkeys: holder_pubkeys.clone(),
22522252
holder_selected_contest_delay: 0,

lightning/src/ln/channel.rs

Lines changed: 64 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2470,6 +2470,7 @@ impl FundingScope {
24702470
fn for_splice<SP: Deref>(
24712471
prev_funding: &Self, context: &ChannelContext<SP>, our_funding_contribution: SignedAmount,
24722472
their_funding_contribution: SignedAmount, counterparty_funding_pubkey: PublicKey,
2473+
our_new_holder_keys: ChannelPublicKeys,
24732474
) -> Self
24742475
where
24752476
SP::Target: SignerProvider,
@@ -2489,19 +2490,15 @@ impl FundingScope {
24892490
debug_assert!(post_value_to_self_msat.is_some());
24902491
let post_value_to_self_msat = post_value_to_self_msat.unwrap();
24912492

2492-
// Rotate the pubkeys using the prev_funding_txid as a tweak
2493-
let prev_funding_txid = prev_funding.get_funding_txid();
2494-
let holder_pubkeys = context.new_holder_pubkeys(prev_funding_txid);
2495-
24962493
let channel_parameters = &prev_funding.channel_transaction_parameters;
24972494
let mut post_channel_transaction_parameters = ChannelTransactionParameters {
2498-
holder_pubkeys,
2495+
holder_pubkeys: our_new_holder_keys,
24992496
holder_selected_contest_delay: channel_parameters.holder_selected_contest_delay,
25002497
// The 'outbound' attribute doesn't change, even if the splice initiator is the other node
25012498
is_outbound_from_holder: channel_parameters.is_outbound_from_holder,
25022499
counterparty_parameters: channel_parameters.counterparty_parameters.clone(),
25032500
funding_outpoint: None, // filled later
2504-
splice_parent_funding_txid: prev_funding_txid,
2501+
splice_parent_funding_txid: prev_funding.get_funding_txid(),
25052502
channel_type_features: channel_parameters.channel_type_features.clone(),
25062503
channel_value_satoshis: post_channel_value,
25072504
};
@@ -2637,6 +2634,7 @@ impl_writeable_tlv_based!(PendingFunding, {
26372634
enum FundingNegotiation {
26382635
AwaitingAck {
26392636
context: FundingNegotiationContext,
2637+
new_holder_funding_key: PublicKey,
26402638
},
26412639
ConstructingTransaction {
26422640
funding: FundingScope,
@@ -2667,7 +2665,7 @@ impl FundingNegotiation {
26672665

26682666
fn is_initiator(&self) -> bool {
26692667
match self {
2670-
FundingNegotiation::AwaitingAck { context } => context.is_initiator,
2668+
FundingNegotiation::AwaitingAck { context, .. } => context.is_initiator,
26712669
FundingNegotiation::ConstructingTransaction { interactive_tx_constructor, .. } => {
26722670
interactive_tx_constructor.is_initiator()
26732671
},
@@ -3510,7 +3508,7 @@ where
35103508

35113509
// TODO(dual_funding): Checks for `funding_feerate_sat_per_1000_weight`?
35123510

3513-
let pubkeys = holder_signer.new_pubkeys(None, &secp_ctx);
3511+
let pubkeys = holder_signer.pubkeys(&secp_ctx);
35143512

35153513
let funding = FundingScope {
35163514
value_to_self_msat,
@@ -3748,7 +3746,7 @@ where
37483746
Err(_) => return Err(APIError::ChannelUnavailable { err: "Failed to get destination script".to_owned()}),
37493747
};
37503748

3751-
let pubkeys = holder_signer.new_pubkeys(None, &secp_ctx);
3749+
let pubkeys = holder_signer.pubkeys(&secp_ctx);
37523750
let temporary_channel_id = temporary_channel_id_fn.map(|f| f(&pubkeys))
37533751
.unwrap_or_else(|| ChannelId::temporary_from_entropy_source(entropy_source));
37543752

@@ -4111,16 +4109,6 @@ where
41114109
return &mut self.holder_signer;
41124110
}
41134111

4114-
/// Returns holder pubkeys to use for the channel.
4115-
fn new_holder_pubkeys(&self, prev_funding_txid: Option<Txid>) -> ChannelPublicKeys {
4116-
match &self.holder_signer {
4117-
ChannelSignerType::Ecdsa(ecdsa) => ecdsa.new_pubkeys(prev_funding_txid, &self.secp_ctx),
4118-
// TODO (taproot|arik)
4119-
#[cfg(taproot)]
4120-
_ => todo!(),
4121-
}
4122-
}
4123-
41244112
/// Only allowed immediately after deserialization if get_outbound_scid_alias returns 0,
41254113
/// indicating we were written by LDK prior to 0.0.106 which did not set outbound SCID aliases
41264114
/// or prior to any channel actions during `Channel` initialization.
@@ -6891,7 +6879,7 @@ macro_rules! maybe_create_splice_funding_failed {
68916879
.map(|funding| funding.get_channel_type().clone());
68926880

68936881
let (contributed_inputs, contributed_outputs) = match funding_negotiation {
6894-
FundingNegotiation::AwaitingAck { context } => {
6882+
FundingNegotiation::AwaitingAck { context, .. } => {
68956883
context.$contributed_inputs_and_outputs()
68966884
},
68976885
FundingNegotiation::ConstructingTransaction {
@@ -11962,17 +11950,29 @@ where
1196211950
change_script,
1196311951
};
1196411952

11953+
// Rotate the funding pubkey using the prev_funding_txid as a tweak
11954+
let prev_funding_txid = self.funding.get_funding_txid();
11955+
let funding_pubkey = match (prev_funding_txid, &self.context.holder_signer) {
11956+
(None, _) => {
11957+
debug_assert!(false);
11958+
self.funding.get_holder_pubkeys().funding_pubkey
11959+
},
11960+
(Some(prev_funding_txid), ChannelSignerType::Ecdsa(ecdsa)) => {
11961+
ecdsa.new_funding_pubkey(prev_funding_txid, &self.context.secp_ctx)
11962+
},
11963+
#[cfg(taproot)]
11964+
_ => todo!(),
11965+
};
11966+
11967+
let funding_negotiation =
11968+
FundingNegotiation::AwaitingAck { context, new_holder_funding_key: funding_pubkey };
1196511969
self.pending_splice = Some(PendingFunding {
11966-
funding_negotiation: Some(FundingNegotiation::AwaitingAck { context }),
11970+
funding_negotiation: Some(funding_negotiation),
1196711971
negotiated_candidates: vec![],
1196811972
sent_funding_txid: None,
1196911973
received_funding_txid: None,
1197011974
});
1197111975

11972-
// Rotate the pubkeys using the prev_funding_txid as a tweak
11973-
let prev_funding_txid = self.funding.get_funding_txid();
11974-
let funding_pubkey = self.context.new_holder_pubkeys(prev_funding_txid).funding_pubkey;
11975-
1197611976
msgs::SpliceInit {
1197711977
channel_id: self.context.channel_id,
1197811978
funding_contribution_satoshis: adjusted_funding_contribution.to_sat(),
@@ -12056,12 +12056,29 @@ where
1205612056
self.validate_splice_contributions(our_funding_contribution, their_funding_contribution)
1205712057
.map_err(|e| ChannelError::WarnAndDisconnect(e))?;
1205812058

12059+
// Rotate the pubkeys using the prev_funding_txid as a tweak
12060+
let prev_funding_txid = self.funding.get_funding_txid();
12061+
let funding_pubkey = match (prev_funding_txid, &self.context.holder_signer) {
12062+
(None, _) => {
12063+
debug_assert!(false);
12064+
self.funding.get_holder_pubkeys().funding_pubkey
12065+
},
12066+
(Some(prev_funding_txid), ChannelSignerType::Ecdsa(ecdsa)) => {
12067+
ecdsa.new_funding_pubkey(prev_funding_txid, &self.context.secp_ctx)
12068+
},
12069+
#[cfg(taproot)]
12070+
_ => todo!(),
12071+
};
12072+
let mut new_keys = self.funding.get_holder_pubkeys().clone();
12073+
new_keys.funding_pubkey = funding_pubkey;
12074+
1205912075
Ok(FundingScope::for_splice(
1206012076
&self.funding,
1206112077
&self.context,
1206212078
our_funding_contribution,
1206312079
their_funding_contribution,
1206412080
msg.funding_pubkey,
12081+
new_keys,
1206512082
))
1206612083
}
1206712084

@@ -12206,8 +12223,7 @@ where
1220612223
// optimization, but for often-offline nodes it may be, as we may connect and immediately
1220712224
// go into splicing from both sides.
1220812225

12209-
let funding_pubkey = splice_funding.get_holder_pubkeys().funding_pubkey;
12210-
12226+
let new_funding_pubkey = splice_funding.get_holder_pubkeys().funding_pubkey;
1221112227
self.pending_splice = Some(PendingFunding {
1221212228
funding_negotiation: Some(FundingNegotiation::ConstructingTransaction {
1221312229
funding: splice_funding,
@@ -12221,7 +12237,7 @@ where
1222112237
Ok(msgs::SpliceAck {
1222212238
channel_id: self.context.channel_id,
1222312239
funding_contribution_satoshis: our_funding_contribution.to_sat(),
12224-
funding_pubkey,
12240+
funding_pubkey: new_funding_pubkey,
1222512241
require_confirmed_inputs: None,
1222612242
})
1222712243
}
@@ -12247,13 +12263,14 @@ where
1224712263
let pending_splice =
1224812264
self.pending_splice.as_mut().expect("We should have returned an error earlier!");
1224912265
// TODO: Good candidate for a let else statement once MSRV >= 1.65
12250-
let funding_negotiation_context = if let Some(FundingNegotiation::AwaitingAck { context }) =
12251-
pending_splice.funding_negotiation.take()
12252-
{
12253-
context
12254-
} else {
12255-
panic!("We should have returned an error earlier!");
12256-
};
12266+
let funding_negotiation_context =
12267+
if let Some(FundingNegotiation::AwaitingAck { context, .. }) =
12268+
pending_splice.funding_negotiation.take()
12269+
{
12270+
context
12271+
} else {
12272+
panic!("We should have returned an error earlier!");
12273+
};
1225712274

1225812275
let mut interactive_tx_constructor = funding_negotiation_context
1225912276
.into_interactive_tx_constructor(
@@ -12284,13 +12301,17 @@ where
1228412301
fn validate_splice_ack(&self, msg: &msgs::SpliceAck) -> Result<FundingScope, ChannelError> {
1228512302
// TODO(splicing): Add check that we are the splice (quiescence) initiator
1228612303

12287-
let funding_negotiation_context = match &self
12304+
let pending_splice = self
1228812305
.pending_splice
1228912306
.as_ref()
12290-
.ok_or(ChannelError::Ignore("Channel is not in pending splice".to_owned()))?
12307+
.ok_or_else(|| ChannelError::Ignore("Channel is not in pending splice".to_owned()))?;
12308+
12309+
let (funding_negotiation_context, new_holder_funding_key) = match &pending_splice
1229112310
.funding_negotiation
1229212311
{
12293-
Some(FundingNegotiation::AwaitingAck { context }) => context,
12312+
Some(FundingNegotiation::AwaitingAck { context, new_holder_funding_key }) => {
12313+
(context, new_holder_funding_key)
12314+
},
1229412315
Some(FundingNegotiation::ConstructingTransaction { .. })
1229512316
| Some(FundingNegotiation::AwaitingSignatures { .. }) => {
1229612317
return Err(ChannelError::WarnAndDisconnect(
@@ -12309,12 +12330,16 @@ where
1230912330
self.validate_splice_contributions(our_funding_contribution, their_funding_contribution)
1231012331
.map_err(|e| ChannelError::WarnAndDisconnect(e))?;
1231112332

12333+
let mut new_keys = self.funding.get_holder_pubkeys().clone();
12334+
new_keys.funding_pubkey = *new_holder_funding_key;
12335+
1231212336
Ok(FundingScope::for_splice(
1231312337
&self.funding,
1231412338
&self.context,
1231512339
our_funding_contribution,
1231612340
their_funding_contribution,
1231712341
msg.funding_pubkey,
12342+
new_keys,
1231812343
))
1231912344
}
1232012345

@@ -16475,7 +16500,7 @@ mod tests {
1647516500
[0; 32],
1647616501
);
1647716502

16478-
let holder_pubkeys = signer.new_pubkeys(None, &secp_ctx);
16503+
let holder_pubkeys = signer.pubkeys(&secp_ctx);
1647916504
assert_eq!(holder_pubkeys.funding_pubkey.serialize()[..],
1648016505
<Vec<u8>>::from_hex("023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb").unwrap()[..]);
1648116506
let keys_provider = Keys { signer: signer.clone() };

lightning/src/sign/mod.rs

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -272,12 +272,12 @@ pub enum SpendableOutputDescriptor {
272272
/// To derive the delayed payment key which is used to sign this input, you must pass the
273273
/// holder [`InMemorySigner::delayed_payment_base_key`] (i.e., the private key which
274274
/// corresponds to the [`ChannelPublicKeys::delayed_payment_basepoint`] in
275-
/// [`ChannelSigner::new_pubkeys`]) and the provided
275+
/// [`ChannelSigner::pubkeys`]) and the provided
276276
/// [`DelayedPaymentOutputDescriptor::per_commitment_point`] to
277277
/// [`chan_utils::derive_private_key`]. The DelayedPaymentKey can be generated without the
278278
/// secret key using [`DelayedPaymentKey::from_basepoint`] and only the
279279
/// [`ChannelPublicKeys::delayed_payment_basepoint`] which appears in
280-
/// [`ChannelSigner::new_pubkeys`].
280+
/// [`ChannelSigner::pubkeys`].
281281
///
282282
/// To derive the [`DelayedPaymentOutputDescriptor::revocation_pubkey`] provided here (which is
283283
/// used in the witness script generation), you must pass the counterparty
@@ -292,7 +292,7 @@ pub enum SpendableOutputDescriptor {
292292
/// [`chan_utils::get_revokeable_redeemscript`].
293293
DelayedPaymentOutput(DelayedPaymentOutputDescriptor),
294294
/// An output spendable exclusively by our payment key (i.e., the private key that corresponds
295-
/// to the `payment_point` in [`ChannelSigner::new_pubkeys`]). The output type depends on the
295+
/// to the `payment_point` in [`ChannelSigner::pubkeys`]). The output type depends on the
296296
/// channel type negotiated.
297297
///
298298
/// On an anchor outputs channel, the witness in the spending input is:
@@ -792,19 +792,25 @@ pub trait ChannelSigner {
792792
/// and pause future signing operations until this validation completes.
793793
fn validate_counterparty_revocation(&self, idx: u64, secret: &SecretKey) -> Result<(), ()>;
794794

795-
/// Returns a *new* set of holder channel public keys and basepoints. They may be the same as a
796-
/// previous value, but are also allowed to change arbitrarily. Signing methods must still
797-
/// support signing for any keys which have ever been returned. This should only be called
798-
/// either for new channels or new splices.
795+
/// Returns the holder channel public keys and basepoints. This should only be called once
796+
/// during channel creation and as such implementations are allowed undefined behavior if
797+
/// called more than once.
799798
///
800-
/// `splice_parent_funding_txid` can be used to compute a tweak to rotate the funding key in the
801-
/// 2-of-2 multisig script during a splice. See [`compute_funding_key_tweak`] for an example
802-
/// tweak and more details.
799+
/// This method is *not* asynchronous. Instead, the value must be computed locally or in
800+
/// advance and cached.
801+
fn pubkeys(&self, secp_ctx: &Secp256k1<secp256k1::All>) -> ChannelPublicKeys;
802+
803+
/// Returns a new funding pubkey (i.e. our public which is used in a 2-of-2 with the
804+
/// counterparty's key to to lock the funds on-chain) for a spliced channel.
805+
///
806+
/// `splice_parent_funding_txid` can be used to compute a tweak with which to rotate the base
807+
/// key (which will then be available later in signing operations via
808+
/// [`ChannelTransactionParameters::splice_parent_funding_txid`]).
803809
///
804810
/// This method is *not* asynchronous. Instead, the value must be cached locally.
805-
fn new_pubkeys(
806-
&self, splice_parent_funding_txid: Option<Txid>, secp_ctx: &Secp256k1<secp256k1::All>,
807-
) -> ChannelPublicKeys;
811+
fn new_funding_pubkey(
812+
&self, splice_parent_funding_txid: Txid, secp_ctx: &Secp256k1<secp256k1::All>,
813+
) -> PublicKey;
808814

809815
/// Returns an arbitrary identifier describing the set of keys which are provided back to you in
810816
/// some [`SpendableOutputDescriptor`] types. This should be sufficient to identify this
@@ -1457,17 +1463,13 @@ impl ChannelSigner for InMemorySigner {
14571463
Ok(())
14581464
}
14591465

1460-
fn new_pubkeys(
1461-
&self, splice_parent_funding_txid: Option<Txid>, secp_ctx: &Secp256k1<secp256k1::All>,
1462-
) -> ChannelPublicKeys {
1466+
fn pubkeys(&self, secp_ctx: &Secp256k1<secp256k1::All>) -> ChannelPublicKeys {
14631467
// Because splices always break downgrades, we go ahead and always use the new derivation
14641468
// here as its just much better.
1465-
let use_v2_derivation =
1466-
self.v2_remote_key_derivation || splice_parent_funding_txid.is_some();
14671469
let payment_key =
1468-
if use_v2_derivation { &self.payment_key_v2 } else { &self.payment_key_v1 };
1470+
if self.v2_remote_key_derivation { &self.payment_key_v2 } else { &self.payment_key_v1 };
14691471
let from_secret = |s: &SecretKey| PublicKey::from_secret_key(secp_ctx, s);
1470-
let mut pubkeys = ChannelPublicKeys {
1472+
let pubkeys = ChannelPublicKeys {
14711473
funding_pubkey: from_secret(&self.funding_key.0),
14721474
revocation_basepoint: RevocationBasepoint::from(from_secret(&self.revocation_base_key)),
14731475
payment_point: from_secret(payment_key),
@@ -1477,13 +1479,15 @@ impl ChannelSigner for InMemorySigner {
14771479
htlc_basepoint: HtlcBasepoint::from(from_secret(&self.htlc_base_key)),
14781480
};
14791481

1480-
if splice_parent_funding_txid.is_some() {
1481-
pubkeys.funding_pubkey =
1482-
self.funding_key(splice_parent_funding_txid).public_key(secp_ctx);
1483-
}
14841482
pubkeys
14851483
}
14861484

1485+
fn new_funding_pubkey(
1486+
&self, splice_parent_funding_txid: Txid, secp_ctx: &Secp256k1<secp256k1::All>,
1487+
) -> PublicKey {
1488+
self.funding_key(Some(splice_parent_funding_txid)).public_key(secp_ctx)
1489+
}
1490+
14871491
fn channel_keys_id(&self) -> [u8; 32] {
14881492
self.channel_keys_id
14891493
}

0 commit comments

Comments
 (0)