@@ -32,7 +32,7 @@ use crate::ln::types::ChannelId;
32
32
use crate::types::payment::{PaymentPreimage, PaymentHash};
33
33
use crate::types::features::{ChannelTypeFeatures, InitFeatures};
34
34
use crate::ln::interactivetxs::{
35
- get_output_weight, calculate_change_output_value, HandleTxCompleteValue, HandleTxCompleteResult, InteractiveTxConstructor,
35
+ estimate_input_weight, get_output_weight, calculate_change_output_value, HandleTxCompleteValue, HandleTxCompleteResult, InteractiveTxConstructor,
36
36
InteractiveTxConstructorArgs, InteractiveTxMessageSend, InteractiveTxSigningSession, InteractiveTxMessageSendResult,
37
37
OutputOwned, SharedOwnedOutput, TX_COMMON_FIELDS_WEIGHT,
38
38
};
@@ -1142,7 +1142,7 @@ pub(super) enum Channel<SP: Deref> where SP::Target: SignerProvider {
1142
1142
Funded(FundedChannel<SP>),
1143
1143
#[cfg(splicing)]
1144
1144
/// Used during splicing, channel is funded but a new funding is being renegotiated.
1145
- RefundingV2(FundedChannel <SP>),
1145
+ RefundingV2(SplicingChannel <SP>),
1146
1146
}
1147
1147
1148
1148
impl<SP: Deref> Channel<SP> where
@@ -1156,7 +1156,7 @@ impl<SP: Deref> Channel<SP> where
1156
1156
Channel::UnfundedInboundV1(chan) => &chan.context,
1157
1157
Channel::UnfundedV2(chan) => &chan.context,
1158
1158
#[cfg(splicing)]
1159
- Channel::RefundingV2(chan) => &chan.context,
1159
+ Channel::RefundingV2(chan) => &chan.pre_funded. context,
1160
1160
}
1161
1161
}
1162
1162
@@ -1167,7 +1167,7 @@ impl<SP: Deref> Channel<SP> where
1167
1167
Channel::UnfundedInboundV1(ref mut chan) => &mut chan.context,
1168
1168
Channel::UnfundedV2(ref mut chan) => &mut chan.context,
1169
1169
#[cfg(splicing)]
1170
- Channel::RefundingV2(ref mut chan) => &mut chan.context,
1170
+ Channel::RefundingV2(ref mut chan) => &mut chan.pre_funded. context,
1171
1171
}
1172
1172
}
1173
1173
@@ -1183,22 +1183,29 @@ impl<SP: Deref> Channel<SP> where
1183
1183
}
1184
1184
1185
1185
pub fn is_funded(&self) -> bool {
1186
- matches!(self, Channel::Funded(_))
1186
+ match self {
1187
+ Channel::Funded(_) => true,
1188
+ #[cfg(splicing)]
1189
+ Channel::RefundingV2(_) => true,
1190
+ _ => false,
1191
+ }
1187
1192
}
1188
1193
1189
1194
pub fn as_funded(&self) -> Option<&FundedChannel<SP>> {
1190
- if let Channel::Funded(channel) = self {
1191
- Some(channel)
1192
- } else {
1193
- None
1195
+ match self {
1196
+ Channel::Funded(channel) => Some(channel),
1197
+ #[cfg(splicing)]
1198
+ Channel::RefundingV2(channel) => Some(&channel.pre_funded),
1199
+ _ => None,
1194
1200
}
1195
1201
}
1196
1202
1197
1203
pub fn as_funded_mut(&mut self) -> Option<&mut FundedChannel<SP>> {
1198
- if let Channel::Funded(channel) = self {
1199
- Some(channel)
1200
- } else {
1201
- None
1204
+ match self {
1205
+ Channel::Funded(channel) => Some(channel),
1206
+ #[cfg(splicing)]
1207
+ Channel::RefundingV2(channel) => Some(&mut channel.pre_funded),
1208
+ _ => None,
1202
1209
}
1203
1210
}
1204
1211
@@ -1239,10 +1246,11 @@ impl<SP: Deref> Channel<SP> where
1239
1246
}
1240
1247
1241
1248
pub fn as_unfunded_v2_mut(&mut self) -> Option<&mut PendingV2Channel<SP>> {
1242
- if let Channel::UnfundedV2(channel) = self {
1243
- Some(channel)
1244
- } else {
1245
- None
1249
+ match self {
1250
+ Channel::UnfundedV2(channel) => Some(channel),
1251
+ #[cfg(splicing)]
1252
+ Channel::RefundingV2(channel) => Some(&mut channel.post_pending),
1253
+ _ => None,
1246
1254
}
1247
1255
}
1248
1256
@@ -1294,7 +1302,7 @@ impl<SP: Deref> Channel<SP> where
1294
1302
},
1295
1303
Channel::UnfundedV2(_) => None,
1296
1304
#[cfg(splicing)]
1297
- Channel::RefundingV2(chan) => Some(chan.signer_maybe_unblocked(logger)),
1305
+ Channel::RefundingV2(chan) => Some(chan.pre_funded. signer_maybe_unblocked(logger)),
1298
1306
}
1299
1307
}
1300
1308
@@ -1423,6 +1431,55 @@ where
1423
1431
}
1424
1432
}
1425
1433
1434
+ /// Struct holding together various state dureing splicing negotiation
1435
+ #[cfg(splicing)]
1436
+ pub(super) struct SplicingChannel<SP: Deref> where SP::Target: SignerProvider {
1437
+ pub pre_funded: FundedChannel<SP>,
1438
+ pub post_pending: PendingV2Channel<SP>,
1439
+ pub post_funded: Option<FundedChannel<SP>>,
1440
+ }
1441
+
1442
+ #[cfg(splicing)]
1443
+ impl<SP: Deref> SplicingChannel<SP> where SP::Target: SignerProvider {
1444
+ pub(super) fn new(pre_funded: FundedChannel<SP>, post_pending: PendingV2Channel<SP>) -> Self {
1445
+ Self {
1446
+ pre_funded,
1447
+ post_pending,
1448
+ post_funded: None,
1449
+ }
1450
+ }
1451
+
1452
+ pub fn splice_init<ES: Deref, L: Deref>(
1453
+ &mut self, msg: &msgs::SpliceInit, signer_provider: &SP, entropy_source: &ES, holder_node_id: PublicKey, logger: &L,
1454
+ ) -> Result<msgs::SpliceAck,ChannelError> where ES::Target: EntropySource, L::Target: Logger {
1455
+ self.post_pending.splice_init(msg, signer_provider, entropy_source, holder_node_id, logger)
1456
+ }
1457
+
1458
+ pub fn splice_ack<ES: Deref, L: Deref>(
1459
+ &mut self, msg: &msgs::SpliceAck, our_funding_contribution: i64, signer_provider: &SP, entropy_source: &ES, holder_node_id: PublicKey, logger: &L,
1460
+ ) -> Result<Option<InteractiveTxMessageSend>, ChannelError> where ES::Target: EntropySource, L::Target: Logger {
1461
+ self.post_pending.splice_ack(msg, our_funding_contribution, signer_provider, entropy_source, holder_node_id, logger)
1462
+ }
1463
+
1464
+ pub fn tx_add_input(&mut self, msg: &msgs::TxAddInput) -> InteractiveTxMessageSendResult {
1465
+ self.post_pending.tx_add_input(msg)
1466
+ }
1467
+
1468
+ pub fn tx_add_output(&mut self, msg: &msgs::TxAddOutput)-> InteractiveTxMessageSendResult {
1469
+ self.post_pending.tx_add_output(msg)
1470
+ }
1471
+
1472
+ pub fn tx_complete(&mut self, msg: &msgs::TxComplete) -> HandleTxCompleteResult {
1473
+ self.post_pending.tx_complete(msg)
1474
+ }
1475
+
1476
+ pub fn funding_tx_constructed<L: Deref>(
1477
+ &mut self, signing_session: &mut InteractiveTxSigningSession, logger: &L
1478
+ ) -> Result<(msgs::CommitmentSigned, Option<Event>), ChannelError> where L::Target: Logger {
1479
+ self.post_pending.funding_tx_constructed(signing_session, logger)
1480
+ }
1481
+ }
1482
+
1426
1483
/// Contains all state common to unfunded inbound/outbound channels.
1427
1484
pub(super) struct UnfundedChannelContext {
1428
1485
/// A counter tracking how many ticks have elapsed since this unfunded channel was
@@ -1455,7 +1512,7 @@ impl UnfundedChannelContext {
1455
1512
/// Info about a pending splice, used in the pre-splice channel
1456
1513
#[cfg(splicing)]
1457
1514
#[derive(Clone)]
1458
- struct PendingSplicePre {
1515
+ pub(super) struct PendingSplicePre {
1459
1516
pub our_funding_contribution: i64,
1460
1517
pub funding_feerate_perkw: u32,
1461
1518
pub locktime: u32,
@@ -4869,6 +4926,54 @@ fn get_v2_channel_reserve_satoshis(channel_value_satoshis: u64, dust_limit_satos
4869
4926
cmp::min(channel_value_satoshis, cmp::max(q, dust_limit_satoshis))
4870
4927
}
4871
4928
4929
+ pub(super) fn maybe_add_funding_change_output<SP: Deref>(signer_provider: &SP, is_initiator: bool,
4930
+ our_funding_satoshis: u64, funding_inputs_prev_outputs: &Vec<TxOut>,
4931
+ funding_outputs: &mut Vec<OutputOwned>, funding_feerate_sat_per_1000_weight: u32,
4932
+ total_input_satoshis: u64, holder_dust_limit_satoshis: u64, channel_keys_id: [u8; 32],
4933
+ ) -> Result<Option<TxOut>, ChannelError> where
4934
+ SP::Target: SignerProvider,
4935
+ {
4936
+ let our_funding_inputs_weight = funding_inputs_prev_outputs.iter().fold(0u64, |weight, prev_output| {
4937
+ weight.saturating_add(estimate_input_weight(prev_output).to_wu())
4938
+ });
4939
+ let our_funding_outputs_weight = funding_outputs.iter().fold(0u64, |weight, out| {
4940
+ weight.saturating_add(get_output_weight(&out.tx_out().script_pubkey).to_wu())
4941
+ });
4942
+ let our_contributed_weight = our_funding_outputs_weight.saturating_add(our_funding_inputs_weight);
4943
+ let mut fees_sats = fee_for_weight(funding_feerate_sat_per_1000_weight, our_contributed_weight);
4944
+
4945
+ // If we are the initiator, we must pay for weight of all common fields in the funding transaction.
4946
+ if is_initiator {
4947
+ let common_fees = fee_for_weight(funding_feerate_sat_per_1000_weight, TX_COMMON_FIELDS_WEIGHT);
4948
+ fees_sats = fees_sats.saturating_add(common_fees);
4949
+ }
4950
+
4951
+ let remaining_value = total_input_satoshis
4952
+ .saturating_sub(our_funding_satoshis)
4953
+ .saturating_sub(fees_sats);
4954
+
4955
+ if remaining_value < holder_dust_limit_satoshis {
4956
+ Ok(None)
4957
+ } else {
4958
+ let change_script = signer_provider.get_destination_script(channel_keys_id).map_err(
4959
+ |_| ChannelError::Close((
4960
+ "Failed to get change script as new destination script".to_owned(),
4961
+ ClosureReason::ProcessingError { err: "Failed to get change script as new destination script".to_owned() }
4962
+ ))
4963
+ )?;
4964
+ let mut change_output = TxOut {
4965
+ value: Amount::from_sat(remaining_value),
4966
+ script_pubkey: change_script,
4967
+ };
4968
+ let change_output_weight = get_output_weight(&change_output.script_pubkey).to_wu();
4969
+
4970
+ let change_output_fee = fee_for_weight(funding_feerate_sat_per_1000_weight, change_output_weight);
4971
+ change_output.value = Amount::from_sat(remaining_value.saturating_sub(change_output_fee));
4972
+ funding_outputs.push(OutputOwned::Single(change_output.clone()));
4973
+ Ok(Some(change_output))
4974
+ }
4975
+ }
4976
+
4872
4977
pub(super) fn calculate_our_funding_satoshis(
4873
4978
is_initiator: bool, funding_inputs: &[(TxIn, TransactionU16LenLimited)],
4874
4979
total_witness_weight: Weight, funding_feerate_sat_per_1000_weight: u32,
@@ -4941,7 +5046,7 @@ pub(super) struct FundedChannel<SP: Deref> where SP::Target: SignerProvider {
4941
5046
holder_commitment_point: HolderCommitmentPoint,
4942
5047
/// Info about an in-progress, pending splice (if any), on the pre-splice channel
4943
5048
#[cfg(splicing)]
4944
- pending_splice_pre: Option<PendingSplicePre>,
5049
+ pub pending_splice_pre: Option<PendingSplicePre>,
4945
5050
/// Info about an in-progress, pending splice (if any), on the post-splice channel
4946
5051
#[cfg(splicing)]
4947
5052
pending_splice_post: Option<PendingSplicePost>,
@@ -8632,11 +8737,11 @@ impl<SP: Deref> FundedChannel<SP> where
8632
8737
Ok(msg)
8633
8738
}
8634
8739
8635
- /// Handle splice_init
8740
+ /// Checks during handling splice_init
8636
8741
#[cfg(splicing)]
8637
- pub fn splice_init <ES: Deref, L : Deref>(
8638
- &mut self, msg: &msgs::SpliceInit, _signer_provider: &SP, _entropy_source: &ES, _holder_node_id: PublicKey, logger: &L,
8639
- ) -> Result<msgs::SpliceAck , ChannelError> where ES::Target: EntropySource, L::Target: Logger {
8742
+ pub fn splice_init_checks <ES: Deref>(
8743
+ &mut self, msg: &msgs::SpliceInit, _signer_provider: &SP, _entropy_source: &ES, _holder_node_id: PublicKey,
8744
+ ) -> Result<() , ChannelError> where ES::Target: EntropySource {
8640
8745
let their_funding_contribution_satoshis = msg.funding_contribution_satoshis;
8641
8746
// TODO(splicing): Currently not possible to contribute on the splicing-acceptor side
8642
8747
let our_funding_contribution_satoshis = 0i64;
@@ -8677,52 +8782,7 @@ impl<SP: Deref> FundedChannel<SP> where
8677
8782
// Early check for reserve requirement, assuming maximum balance of full channel value
8678
8783
// This will also be checked later at tx_complete
8679
8784
let _res = self.context.check_balance_meets_reserve_requirements(post_balance, post_channel_value)?;
8680
-
8681
- // TODO(splicing): Store msg.funding_pubkey
8682
-
8683
- // Apply start of splice change in the state
8684
- self.context.splice_start(false, logger);
8685
-
8686
- let splice_ack_msg = self.context.get_splice_ack(our_funding_contribution_satoshis);
8687
-
8688
- // TODO(splicing): start interactive funding negotiation
8689
- // let _msg = self.begin_interactive_funding_tx_construction(signer_provider, entropy_source, holder_node_id)
8690
- // .map_err(|err| ChannelError::Warn(format!("Failed to start interactive transaction construction, {:?}", err)))?;
8691
-
8692
- Ok(splice_ack_msg)
8693
- }
8694
-
8695
- /// Handle splice_ack
8696
- #[cfg(splicing)]
8697
- pub fn splice_ack<ES: Deref, L: Deref>(
8698
- &mut self, msg: &msgs::SpliceAck, _signer_provider: &SP, _entropy_source: &ES, _holder_node_id: PublicKey, logger: &L,
8699
- ) -> Result<Option<InteractiveTxMessageSend>, ChannelError> where ES::Target: EntropySource, L::Target: Logger {
8700
- let their_funding_contribution_satoshis = msg.funding_contribution_satoshis;
8701
-
8702
- // check if splice is pending
8703
- let pending_splice = if let Some(pending_splice) = &self.pending_splice_pre {
8704
- pending_splice
8705
- } else {
8706
- return Err(ChannelError::Warn(format!("Channel is not in pending splice")));
8707
- };
8708
-
8709
- let our_funding_contribution = pending_splice.our_funding_contribution;
8710
-
8711
- let pre_channel_value = self.context.get_value_satoshis();
8712
- let post_channel_value = PendingSplicePre::compute_post_value(pre_channel_value, our_funding_contribution, their_funding_contribution_satoshis);
8713
- let post_balance = PendingSplicePre::add_checked(self.context.value_to_self_msat, our_funding_contribution);
8714
- // Early check for reserve requirement, assuming maximum balance of full channel value
8715
- // This will also be checked later at tx_complete
8716
- let _res = self.context.check_balance_meets_reserve_requirements(post_balance, post_channel_value)?;
8717
-
8718
- // Apply start of splice change in the state
8719
- self.context.splice_start(true, logger);
8720
-
8721
- // TODO(splicing): start interactive funding negotiation
8722
- // let tx_msg_opt = self.begin_interactive_funding_tx_construction(signer_provider, entropy_source, holder_node_id)
8723
- // .map_err(|err| ChannelError::Warn(format!("V2 channel rejected due to sender error, {:?}", err)))?;
8724
- // Ok(tx_msg_opt)
8725
- Ok(None)
8785
+ Ok(())
8726
8786
}
8727
8787
8728
8788
// Send stuff to our remote peers:
@@ -9965,6 +10025,56 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
9965
10025
}
9966
10026
}
9967
10027
10028
+ pub fn into_channel(self, signing_session: InteractiveTxSigningSession) -> Result<FundedChannel<SP>, ChannelError>{
10029
+ let holder_commitment_point = self.unfunded_context.holder_commitment_point.ok_or(ChannelError::close(
10030
+ format!("Expected to have holder commitment points available upon finishing interactive tx construction for channel {}",
10031
+ self.context.channel_id())))?;
10032
+ let channel = FundedChannel {
10033
+ context: self.context,
10034
+ interactive_tx_signing_session: Some(signing_session),
10035
+ holder_commitment_point,
10036
+ #[cfg(splicing)]
10037
+ pending_splice_pre: None,
10038
+ #[cfg(splicing)]
10039
+ pending_splice_post: self.pending_splice_post,
10040
+ };
10041
+
10042
+ Ok(channel)
10043
+ }
10044
+
10045
+ /// Handle splice_ack
10046
+ #[cfg(splicing)]
10047
+ pub fn splice_ack<ES: Deref, L: Deref>(
10048
+ &mut self, msg: &msgs::SpliceAck, our_funding_contribution: i64, signer_provider: &SP, entropy_source: &ES, holder_node_id: PublicKey, logger: &L,
10049
+ ) -> Result<Option<InteractiveTxMessageSend>, ChannelError> where ES::Target: EntropySource, L::Target: Logger {
10050
+ let their_funding_contribution_satoshis = msg.funding_contribution_satoshis;
10051
+
10052
+ // check if splice is pending
10053
+ let pending_splice = if let Some(pending_splice) = &self.pending_splice_post {
10054
+ pending_splice
10055
+ } else {
10056
+ return Err(ChannelError::Warn(format!("Channel is not in pending splice")));
10057
+ };
10058
+
10059
+ let pre_channel_value = self.context.get_value_satoshis();
10060
+ let post_channel_value = PendingSplicePre::compute_post_value(pre_channel_value, our_funding_contribution, their_funding_contribution_satoshis);
10061
+ let post_balance = PendingSplicePre::add_checked(self.context.value_to_self_msat, our_funding_contribution);
10062
+ // Early check for reserve requirement, assuming maximum balance of full channel value
10063
+ // This will also be checked later at tx_complete
10064
+ let _res = self.context.check_balance_meets_reserve_requirements(post_balance, post_channel_value)?;
10065
+
10066
+ // We need the current funding tx as an extra input
10067
+ let prev_funding_input = pending_splice.get_input_of_previous_funding()?;
10068
+
10069
+ // Apply start of splice change in the state
10070
+ self.context.splice_start(true, logger);
10071
+
10072
+ // Start interactive funding negotiation, with the previous funding transaction as an extra shared input
10073
+ let tx_msg_opt = self.begin_interactive_funding_tx_construction(signer_provider, entropy_source, holder_node_id, Some(prev_funding_input))
10074
+ .map_err(|err| ChannelError::Warn(format!("V2 channel rejected due to sender error, {:?}", err)))?;
10075
+ Ok(tx_msg_opt)
10076
+ }
10077
+
9968
10078
/// Creates a new dual-funded channel from a remote side's request for one.
9969
10079
/// Assumes chain_hash has already been checked and corresponds with what we expect!
9970
10080
#[allow(dead_code)] // TODO(dual_funding): Remove once V2 channels is enabled.
@@ -10149,21 +10259,27 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
10149
10259
self.generate_accept_channel_v2_message()
10150
10260
}
10151
10261
10152
- pub fn into_channel(self, signing_session: InteractiveTxSigningSession) -> Result<FundedChannel<SP>, ChannelError>{
10153
- let holder_commitment_point = self.unfunded_context.holder_commitment_point.ok_or(ChannelError::close(
10154
- format!("Expected to have holder commitment points available upon finishing interactive tx construction for channel {}",
10155
- self.context.channel_id())))?;
10156
- let channel = FundedChannel {
10157
- context: self.context,
10158
- interactive_tx_signing_session: Some(signing_session),
10159
- holder_commitment_point,
10160
- #[cfg(splicing)]
10161
- pending_splice_pre: None,
10162
- #[cfg(splicing)]
10163
- pending_splice_post: self.pending_splice_post,
10164
- };
10262
+ /// Handle splice_init
10263
+ /// See also [`splice_init_checks`]
10264
+ #[cfg(splicing)]
10265
+ pub fn splice_init<ES: Deref, L: Deref>(
10266
+ &mut self, _msg: &msgs::SpliceInit, signer_provider: &SP, entropy_source: &ES, holder_node_id: PublicKey, logger: &L,
10267
+ ) -> Result<msgs::SpliceAck,ChannelError> where ES::Target: EntropySource, L::Target: Logger {
10268
+ // TODO(splicing): Currently not possible to contribute on the splicing-acceptor side
10269
+ let our_funding_contribution_satoshis = 0i64;
10165
10270
10166
- Ok(channel)
10271
+ // TODO(splicing): Store msg.funding_pubkey
10272
+
10273
+ // Apply start of splice change in the state
10274
+ self.context.splice_start(false, logger);
10275
+
10276
+ let splice_ack_msg = self.context.get_splice_ack(our_funding_contribution_satoshis);
10277
+
10278
+ // Start interactive funding negotiation. No extra input, as we are not the splice initiator
10279
+ let _msg = self.begin_interactive_funding_tx_construction(signer_provider, entropy_source, holder_node_id, None)
10280
+ .map_err(|err| ChannelError::Warn(format!("Failed to start interactive transaction construction, {:?}", err)))?;
10281
+
10282
+ Ok(splice_ack_msg)
10167
10283
}
10168
10284
}
10169
10285
0 commit comments