Skip to content

Commit 21e3ccc

Browse files
committed
Support holder funding key rotation during splicing
We introduce a scalar tweak that can be applied to the base funding key to obtain the channel's funding key used in the 2-of-2 multisig. This is used to derive additional keys from the same secret backing the base funding_pubkey, as we have to rotate keys for each successful splice attempt. The tweak is computed similar to existing tweaks used in [BOLT-3](https://github.com/lightning/bolts/blob/master/03-transactions.md#key-derivation): 1. We use the txid of the funding transaction the splice transaction is spending instead of the `per_commitment_point` to guarantee uniqueness. 2. We include the private key instead of the public key to guarantee only those with knowledge of it can re-derive the new funding key. tweak = SHA256(splice_parent_funding_txid || base_funding_secret_key) tweaked_funding_key = base_funding_key + tweak While the use of this tweak is not required (signers may choose to compute a tweak of their choice), signers must ensure their tweak guarantees the two properties mentioned above: uniqueness and derivable only by one or both of the channel participants.
1 parent 36ba27a commit 21e3ccc

File tree

10 files changed

+188
-53
lines changed

10 files changed

+188
-53
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1362,8 +1362,9 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
13621362
) -> ChannelMonitor<Signer> {
13631363

13641364
assert!(commitment_transaction_number_obscure_factor <= (1 << 48));
1365+
let holder_pubkeys = &channel_parameters.holder_pubkeys;
13651366
let counterparty_payment_script = chan_utils::get_counterparty_payment_script(
1366-
&channel_parameters.channel_type_features, &keys.pubkeys().payment_point
1367+
&channel_parameters.channel_type_features, &holder_pubkeys.payment_point
13671368
);
13681369

13691370
let counterparty_channel_parameters = channel_parameters.counterparty_parameters.as_ref().unwrap();
@@ -1372,7 +1373,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
13721373
let counterparty_commitment_params = CounterpartyCommitmentParameters { counterparty_delayed_payment_base_key, counterparty_htlc_base_key, on_counterparty_tx_csv };
13731374

13741375
let channel_keys_id = keys.channel_keys_id();
1375-
let holder_revocation_basepoint = keys.pubkeys().revocation_basepoint;
1376+
let holder_revocation_basepoint = holder_pubkeys.revocation_basepoint;
13761377

13771378
// block for Rust 1.34 compat
13781379
let (holder_commitment_tx, current_holder_commitment_number) = {
@@ -5423,6 +5424,7 @@ mod tests {
54235424
selected_contest_delay: 67,
54245425
}),
54255426
funding_outpoint: Some(funding_outpoint),
5427+
splice_parent_funding_txid: None,
54265428
channel_type_features: ChannelTypeFeatures::only_static_remote_key(),
54275429
channel_value_satoshis: 0,
54285430
};
@@ -5675,6 +5677,7 @@ mod tests {
56755677
selected_contest_delay: 67,
56765678
}),
56775679
funding_outpoint: Some(funding_outpoint),
5680+
splice_parent_funding_txid: None,
56785681
channel_type_features: ChannelTypeFeatures::only_static_remote_key(),
56795682
channel_value_satoshis: 0,
56805683
};

lightning/src/chain/onchaintx.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1352,6 +1352,7 @@ mod tests {
13521352
selected_contest_delay: 67,
13531353
}),
13541354
funding_outpoint: Some(funding_outpoint),
1355+
splice_parent_funding_txid: None,
13551356
channel_type_features: ChannelTypeFeatures::only_static_remote_key(),
13561357
channel_value_satoshis: 0,
13571358
};

lightning/src/chain/package.rs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -603,9 +603,14 @@ impl PackageSolvingData {
603603
}
604604
fn finalize_input<Signer: EcdsaChannelSigner>(&self, bumped_tx: &mut Transaction, i: usize, onchain_handler: &mut OnchainTxHandler<Signer>) -> bool {
605605
let channel_parameters = &onchain_handler.channel_transaction_parameters;
606+
let holder_pubkeys = &channel_parameters.holder_pubkeys;
606607
match self {
607608
PackageSolvingData::RevokedOutput(ref outp) => {
608-
let chan_keys = TxCreationKeys::derive_new(&onchain_handler.secp_ctx, &outp.per_commitment_point, &outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key, &onchain_handler.signer.pubkeys().revocation_basepoint, &onchain_handler.signer.pubkeys().htlc_basepoint);
609+
let chan_keys = TxCreationKeys::derive_new(
610+
&onchain_handler.secp_ctx, &outp.per_commitment_point,
611+
&outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key,
612+
&holder_pubkeys.revocation_basepoint, &holder_pubkeys.htlc_basepoint,
613+
);
609614
let witness_script = chan_utils::get_revokeable_redeemscript(&chan_keys.revocation_key, outp.on_counterparty_tx_csv, &chan_keys.broadcaster_delayed_payment_key);
610615
//TODO: should we panic on signer failure ?
611616
if let Ok(sig) = onchain_handler.signer.sign_justice_revoked_output(channel_parameters, &bumped_tx, i, outp.amount.to_sat(), &outp.per_commitment_key, &onchain_handler.secp_ctx) {
@@ -617,7 +622,11 @@ impl PackageSolvingData {
617622
} else { return false; }
618623
},
619624
PackageSolvingData::RevokedHTLCOutput(ref outp) => {
620-
let chan_keys = TxCreationKeys::derive_new(&onchain_handler.secp_ctx, &outp.per_commitment_point, &outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key, &onchain_handler.signer.pubkeys().revocation_basepoint, &onchain_handler.signer.pubkeys().htlc_basepoint);
625+
let chan_keys = TxCreationKeys::derive_new(
626+
&onchain_handler.secp_ctx, &outp.per_commitment_point,
627+
&outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key,
628+
&holder_pubkeys.revocation_basepoint, &holder_pubkeys.htlc_basepoint,
629+
);
621630
let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, &onchain_handler.channel_type_features(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key);
622631
//TODO: should we panic on signer failure ?
623632
if let Ok(sig) = onchain_handler.signer.sign_justice_revoked_htlc(channel_parameters, &bumped_tx, i, outp.amount, &outp.per_commitment_key, &outp.htlc, &onchain_handler.secp_ctx) {
@@ -629,7 +638,11 @@ impl PackageSolvingData {
629638
} else { return false; }
630639
},
631640
PackageSolvingData::CounterpartyOfferedHTLCOutput(ref outp) => {
632-
let chan_keys = TxCreationKeys::derive_new(&onchain_handler.secp_ctx, &outp.per_commitment_point, &outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key, &onchain_handler.signer.pubkeys().revocation_basepoint, &onchain_handler.signer.pubkeys().htlc_basepoint);
641+
let chan_keys = TxCreationKeys::derive_new(
642+
&onchain_handler.secp_ctx, &outp.per_commitment_point,
643+
&outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key,
644+
&holder_pubkeys.revocation_basepoint, &holder_pubkeys.htlc_basepoint,
645+
);
633646
let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, &onchain_handler.channel_type_features(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key);
634647

635648
if let Ok(sig) = onchain_handler.signer.sign_counterparty_htlc_transaction(channel_parameters, &bumped_tx, i, &outp.htlc.amount_msat / 1000, &outp.per_commitment_point, &outp.htlc, &onchain_handler.secp_ctx) {
@@ -641,7 +654,11 @@ impl PackageSolvingData {
641654
}
642655
},
643656
PackageSolvingData::CounterpartyReceivedHTLCOutput(ref outp) => {
644-
let chan_keys = TxCreationKeys::derive_new(&onchain_handler.secp_ctx, &outp.per_commitment_point, &outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key, &onchain_handler.signer.pubkeys().revocation_basepoint, &onchain_handler.signer.pubkeys().htlc_basepoint);
657+
let chan_keys = TxCreationKeys::derive_new(
658+
&onchain_handler.secp_ctx, &outp.per_commitment_point,
659+
&outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key,
660+
&holder_pubkeys.revocation_basepoint, &holder_pubkeys.htlc_basepoint,
661+
);
645662
let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, &onchain_handler.channel_type_features(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key);
646663

647664
if let Ok(sig) = onchain_handler.signer.sign_counterparty_htlc_transaction(channel_parameters, &bumped_tx, i, &outp.htlc.amount_msat / 1000, &outp.per_commitment_point, &outp.htlc, &onchain_handler.secp_ctx) {

lightning/src/ln/chan_utils.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,17 @@ pub struct ChannelTransactionParameters {
880880
pub counterparty_parameters: Option<CounterpartyChannelTransactionParameters>,
881881
/// The late-bound funding outpoint
882882
pub funding_outpoint: Option<chain::transaction::OutPoint>,
883+
/// The parent funding txid for a channel that has been spliced.
884+
///
885+
/// If a channel was funded with transaction A, and later spliced with transaction B, this field
886+
/// tracks the txid of transaction A.
887+
///
888+
/// See [`compute_funding_key_tweak`] and [`ChannelSigner::pubkeys`] for more context on how
889+
/// this may be used.
890+
///
891+
/// [`compute_funding_key_tweak`]: crate::sign::compute_funding_key_tweak
892+
/// [`ChannelSigner::pubkeys`]: crate::sign::ChannelSigner::pubkeys
893+
pub splice_parent_funding_txid: Option<Txid>,
883894
/// This channel's type, as negotiated during channel open. For old objects where this field
884895
/// wasn't serialized, it will default to static_remote_key at deserialization.
885896
pub channel_type_features: ChannelTypeFeatures,
@@ -963,6 +974,7 @@ impl ChannelTransactionParameters {
963974
funding_outpoint: Some(chain::transaction::OutPoint {
964975
txid: Txid::from_byte_array([42; 32]), index: 0
965976
}),
977+
splice_parent_funding_txid: None,
966978
channel_type_features: ChannelTypeFeatures::empty(),
967979
channel_value_satoshis,
968980
}
@@ -985,6 +997,7 @@ impl Writeable for ChannelTransactionParameters {
985997
(8, self.funding_outpoint, option),
986998
(10, legacy_deserialization_prevention_marker, option),
987999
(11, self.channel_type_features, required),
1000+
(12, self.splice_parent_funding_txid, option),
9881001
(13, self.channel_value_satoshis, required),
9891002
});
9901003
Ok(())
@@ -998,6 +1011,7 @@ impl ReadableArgs<u64> for ChannelTransactionParameters {
9981011
let mut is_outbound_from_holder = RequiredWrapper(None);
9991012
let mut counterparty_parameters = None;
10001013
let mut funding_outpoint = None;
1014+
let mut splice_parent_funding_txid = None;
10011015
let mut _legacy_deserialization_prevention_marker: Option<()> = None;
10021016
let mut channel_type_features = None;
10031017
let mut channel_value_satoshis = None;
@@ -1010,6 +1024,7 @@ impl ReadableArgs<u64> for ChannelTransactionParameters {
10101024
(8, funding_outpoint, option),
10111025
(10, _legacy_deserialization_prevention_marker, option),
10121026
(11, channel_type_features, option),
1027+
(12, splice_parent_funding_txid, option),
10131028
(13, channel_value_satoshis, option),
10141029
});
10151030

@@ -1028,6 +1043,7 @@ impl ReadableArgs<u64> for ChannelTransactionParameters {
10281043
is_outbound_from_holder: is_outbound_from_holder.0.unwrap(),
10291044
counterparty_parameters,
10301045
funding_outpoint,
1046+
splice_parent_funding_txid,
10311047
channel_type_features: channel_type_features.unwrap_or(ChannelTypeFeatures::only_static_remote_key()),
10321048
channel_value_satoshis,
10331049
})
@@ -1154,6 +1170,7 @@ impl HolderCommitmentTransaction {
11541170
is_outbound_from_holder: false,
11551171
counterparty_parameters: Some(CounterpartyChannelTransactionParameters { pubkeys: channel_pubkeys.clone(), selected_contest_delay: 0 }),
11561172
funding_outpoint: Some(chain::transaction::OutPoint { txid: Txid::all_zeros(), index: 0 }),
1173+
splice_parent_funding_txid: None,
11571174
channel_type_features: ChannelTypeFeatures::only_static_remote_key(),
11581175
channel_value_satoshis,
11591176
};
@@ -1953,19 +1970,20 @@ mod tests {
19531970
let keys_provider = test_utils::TestKeysInterface::new(&seed, network);
19541971
let signer = keys_provider.derive_channel_signer(keys_provider.generate_channel_keys_id(false, 0));
19551972
let counterparty_signer = keys_provider.derive_channel_signer(keys_provider.generate_channel_keys_id(true, 1));
1956-
let delayed_payment_base = &signer.pubkeys().delayed_payment_basepoint;
1973+
let holder_pubkeys = signer.pubkeys(None, &secp_ctx);
1974+
let delayed_payment_base = &holder_pubkeys.delayed_payment_basepoint;
19571975
let per_commitment_secret = SecretKey::from_slice(&<Vec<u8>>::from_hex("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100").unwrap()[..]).unwrap();
19581976
let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &per_commitment_secret);
1959-
let htlc_basepoint = &signer.pubkeys().htlc_basepoint;
1960-
let holder_pubkeys = signer.pubkeys();
1961-
let counterparty_pubkeys = counterparty_signer.pubkeys().clone();
1977+
let htlc_basepoint = &holder_pubkeys.htlc_basepoint;
1978+
let counterparty_pubkeys = counterparty_signer.pubkeys(None, &secp_ctx).clone();
19621979
let keys = TxCreationKeys::derive_new(&secp_ctx, &per_commitment_point, delayed_payment_base, htlc_basepoint, &counterparty_pubkeys.revocation_basepoint, &counterparty_pubkeys.htlc_basepoint);
19631980
let channel_parameters = ChannelTransactionParameters {
19641981
holder_pubkeys: holder_pubkeys.clone(),
19651982
holder_selected_contest_delay: 0,
19661983
is_outbound_from_holder: false,
19671984
counterparty_parameters: Some(CounterpartyChannelTransactionParameters { pubkeys: counterparty_pubkeys.clone(), selected_contest_delay: 0 }),
19681985
funding_outpoint: Some(chain::transaction::OutPoint { txid: Txid::all_zeros(), index: 0 }),
1986+
splice_parent_funding_txid: None,
19691987
channel_type_features: ChannelTypeFeatures::only_static_remote_key(),
19701988
channel_value_satoshis: 3000,
19711989
};

lightning/src/ln/channel.rs

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2410,7 +2410,6 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
24102410

24112411
let channel_keys_id = signer_provider.generate_channel_keys_id(true, user_id);
24122412
let holder_signer = signer_provider.derive_channel_signer(channel_keys_id);
2413-
let pubkeys = holder_signer.pubkeys().clone();
24142413

24152414
if config.channel_handshake_config.our_to_self_delay < BREAKDOWN_TIMEOUT {
24162415
return Err(ChannelError::close(format!("Configured with an unreasonable our_to_self_delay ({}) putting user funds at risks. It must be greater than {}", config.channel_handshake_config.our_to_self_delay, BREAKDOWN_TIMEOUT)));
@@ -2570,6 +2569,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
25702569

25712570
// TODO(dual_funding): Checks for `funding_feerate_sat_per_1000_weight`?
25722571

2572+
let pubkeys = holder_signer.pubkeys(None, &secp_ctx);
2573+
25732574
let funding = FundingScope {
25742575
value_to_self_msat,
25752576
counterparty_selected_channel_reserve_satoshis: Some(msg_channel_reserve_satoshis),
@@ -2594,6 +2595,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
25942595
pubkeys: counterparty_pubkeys,
25952596
}),
25962597
funding_outpoint: None,
2598+
splice_parent_funding_txid: None,
25972599
channel_type_features: channel_type.clone(),
25982600
channel_value_satoshis,
25992601
},
@@ -2733,11 +2735,10 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
27332735
config: &'a UserConfig,
27342736
current_chain_height: u32,
27352737
outbound_scid_alias: u64,
2736-
temporary_channel_id: Option<ChannelId>,
2738+
temporary_channel_id_fn: Option<impl Fn(&ChannelPublicKeys) -> ChannelId>,
27372739
holder_selected_channel_reserve_satoshis: u64,
27382740
channel_keys_id: [u8; 32],
27392741
holder_signer: <SP::Target as SignerProvider>::EcdsaSigner,
2740-
pubkeys: ChannelPublicKeys,
27412742
_logger: L,
27422743
) -> Result<(FundingScope, ChannelContext<SP>), APIError>
27432744
where
@@ -2803,7 +2804,9 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
28032804
Err(_) => return Err(APIError::ChannelUnavailable { err: "Failed to get destination script".to_owned()}),
28042805
};
28052806

2806-
let temporary_channel_id = temporary_channel_id.unwrap_or_else(|| ChannelId::temporary_from_entropy_source(entropy_source));
2807+
let pubkeys = holder_signer.pubkeys(None, &secp_ctx);
2808+
let temporary_channel_id = temporary_channel_id_fn.map(|f| f(&pubkeys))
2809+
.unwrap_or_else(|| ChannelId::temporary_from_entropy_source(entropy_source));
28072810

28082811
let funding = FundingScope {
28092812
value_to_self_msat,
@@ -2828,6 +2831,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
28282831
is_outbound_from_holder: true,
28292832
counterparty_parameters: None,
28302833
funding_outpoint: None,
2834+
splice_parent_funding_txid: None,
28312835
channel_type_features: channel_type.clone(),
28322836
// We'll add our counterparty's `funding_satoshis` when we receive `accept_channel2`.
28332837
channel_value_satoshis,
@@ -8160,7 +8164,9 @@ impl<SP: Deref> FundedChannel<SP> where
81608164
};
81618165
match &self.context.holder_signer {
81628166
ChannelSignerType::Ecdsa(ecdsa) => {
8163-
let our_bitcoin_sig = match ecdsa.sign_channel_announcement_with_funding_key(&announcement, &self.context.secp_ctx) {
8167+
let our_bitcoin_sig = match ecdsa.sign_channel_announcement_with_funding_key(
8168+
&self.funding.channel_transaction_parameters, &announcement, &self.context.secp_ctx,
8169+
) {
81648170
Err(_) => {
81658171
log_error!(logger, "Signer rejected channel_announcement signing. Channel will not be announced!");
81668172
return None;
@@ -8201,7 +8207,9 @@ impl<SP: Deref> FundedChannel<SP> where
82018207
.map_err(|_| ChannelError::Ignore("Failed to generate node signature for channel_announcement".to_owned()))?;
82028208
match &self.context.holder_signer {
82038209
ChannelSignerType::Ecdsa(ecdsa) => {
8204-
let our_bitcoin_sig = ecdsa.sign_channel_announcement_with_funding_key(&announcement, &self.context.secp_ctx)
8210+
let our_bitcoin_sig = ecdsa.sign_channel_announcement_with_funding_key(
8211+
&self.funding.channel_transaction_parameters, &announcement, &self.context.secp_ctx,
8212+
)
82058213
.map_err(|_| ChannelError::Ignore("Signer rejected channel_announcement".to_owned()))?;
82068214
Ok(msgs::ChannelAnnouncement {
82078215
node_signature_1: if were_node_one { our_node_sig } else { their_node_sig },
@@ -9007,7 +9015,10 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
90079015

90089016
let channel_keys_id = signer_provider.generate_channel_keys_id(false, user_id);
90099017
let holder_signer = signer_provider.derive_channel_signer(channel_keys_id);
9010-
let pubkeys = holder_signer.pubkeys().clone();
9018+
9019+
let temporary_channel_id_fn = temporary_channel_id.map(|id| {
9020+
move |_: &ChannelPublicKeys| id
9021+
});
90119022

90129023
let (funding, context) = ChannelContext::new_for_outbound_channel(
90139024
fee_estimator,
@@ -9021,11 +9032,10 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
90219032
config,
90229033
current_chain_height,
90239034
outbound_scid_alias,
9024-
temporary_channel_id,
9035+
temporary_channel_id_fn,
90259036
holder_selected_channel_reserve_satoshis,
90269037
channel_keys_id,
90279038
holder_signer,
9028-
pubkeys,
90299039
logger,
90309040
)?;
90319041
let unfunded_context = UnfundedChannelContext {
@@ -9564,9 +9574,10 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
95649574
{
95659575
let channel_keys_id = signer_provider.generate_channel_keys_id(false, user_id);
95669576
let holder_signer = signer_provider.derive_channel_signer(channel_keys_id);
9567-
let pubkeys = holder_signer.pubkeys().clone();
95689577

9569-
let temporary_channel_id = Some(ChannelId::temporary_v2_from_revocation_basepoint(&pubkeys.revocation_basepoint));
9578+
let temporary_channel_id_fn = Some(|pubkeys: &ChannelPublicKeys| {
9579+
ChannelId::temporary_v2_from_revocation_basepoint(&pubkeys.revocation_basepoint)
9580+
});
95709581

95719582
let holder_selected_channel_reserve_satoshis = get_v2_channel_reserve_satoshis(
95729583
funding_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS);
@@ -9590,11 +9601,10 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
95909601
config,
95919602
current_chain_height,
95929603
outbound_scid_alias,
9593-
temporary_channel_id,
9604+
temporary_channel_id_fn,
95949605
holder_selected_channel_reserve_satoshis,
95959606
channel_keys_id,
95969607
holder_signer,
9597-
pubkeys,
95989608
logger,
95999609
)?;
96009610
let unfunded_context = UnfundedChannelContext {

lightning/src/ln/dual_funding_tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ fn do_test_v2_channel_establishment(session: V2ChannelEstablishmentTestSession)
169169
holder_selected_contest_delay: open_channel_v2_msg.common_fields.to_self_delay,
170170
is_outbound_from_holder: true,
171171
funding_outpoint,
172+
splice_parent_funding_txid: None,
172173
channel_type_features,
173174
channel_value_satoshis: funding_satoshis,
174175
};

0 commit comments

Comments
 (0)