@@ -11,7 +11,6 @@ use bitcoin::amount::Amount;
11
11
use bitcoin::constants::ChainHash;
12
12
use bitcoin::script::{Script, ScriptBuf, Builder, WScriptHash};
13
13
use bitcoin::transaction::{Transaction, TxIn};
14
- use bitcoin::sighash;
15
14
use bitcoin::sighash::EcdsaSighashType;
16
15
use bitcoin::consensus::encode;
17
16
use bitcoin::absolute::LockTime;
@@ -25,7 +24,9 @@ use bitcoin::hash_types::{Txid, BlockHash};
25
24
use bitcoin::secp256k1::constants::PUBLIC_KEY_SIZE;
26
25
use bitcoin::secp256k1::{PublicKey,SecretKey};
27
26
use bitcoin::secp256k1::{Secp256k1,ecdsa::Signature};
28
- use bitcoin::secp256k1;
27
+ use bitcoin::{secp256k1, sighash};
28
+ #[cfg(splicing)]
29
+ use bitcoin::TxIn;
29
30
30
31
use crate::ln::types::ChannelId;
31
32
use crate::types::payment::{PaymentPreimage, PaymentHash};
@@ -1182,6 +1183,34 @@ impl UnfundedChannelContext {
1182
1183
}
1183
1184
}
1184
1185
1186
+ /// Info about a pending splice, used in the pre-splice channel
1187
+ #[cfg(splicing)]
1188
+ #[derive(Clone)]
1189
+ pub(crate) struct PendingSpliceInfoPre {
1190
+ pub our_funding_contribution: i64,
1191
+ pub funding_feerate_perkw: u32,
1192
+ pub locktime: u32,
1193
+ /// The funding inputs we will be contributing to the splice.
1194
+ /// TODO(splice): will be changed to TransactionU16LenLimited
1195
+ pub our_funding_inputs: Vec<(TxIn, Transaction)>,
1196
+ }
1197
+
1198
+ #[cfg(splicing)]
1199
+ impl PendingSpliceInfoPre {
1200
+ fn add_checked(base: u64, delta: i64) -> u64 {
1201
+ if delta >= 0 {
1202
+ base.saturating_add(delta as u64)
1203
+ } else {
1204
+ base.saturating_sub(delta.abs() as u64)
1205
+ }
1206
+ }
1207
+
1208
+ /// Compute the post-splice channel value from the pre-splice values and the peer contributions
1209
+ pub fn compute_post_value(pre_channel_value: u64, our_funding_contribution: i64, their_funding_contribution: i64) -> u64 {
1210
+ Self::add_checked(pre_channel_value, our_funding_contribution.saturating_add(their_funding_contribution))
1211
+ }
1212
+ }
1213
+
1185
1214
/// Contains everything about the channel including state, and various flags.
1186
1215
pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
1187
1216
config: LegacyChannelConfig,
@@ -1217,6 +1246,10 @@ pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
1217
1246
secp_ctx: Secp256k1<secp256k1::All>,
1218
1247
channel_value_satoshis: u64,
1219
1248
1249
+ /// Info about an in-progress, pending splice (if any), on the pre-splice channel
1250
+ #[cfg(splicing)]
1251
+ pub(crate) pending_splice_pre: Option<PendingSpliceInfoPre>,
1252
+
1220
1253
latest_monitor_update_id: u64,
1221
1254
1222
1255
holder_signer: ChannelSignerType<SP>,
@@ -2207,6 +2240,9 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
2207
2240
is_manual_broadcast: false,
2208
2241
2209
2242
next_funding_txid: None,
2243
+
2244
+ #[cfg(splicing)]
2245
+ pending_splice_pre: None,
2210
2246
};
2211
2247
2212
2248
Ok(channel_context)
@@ -2440,6 +2476,9 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
2440
2476
local_initiated_shutdown: None,
2441
2477
is_manual_broadcast: false,
2442
2478
next_funding_txid: None,
2479
+
2480
+ #[cfg(splicing)]
2481
+ pending_splice_pre: None,
2443
2482
})
2444
2483
}
2445
2484
@@ -4085,6 +4124,72 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
4085
4124
self.channel_transaction_parameters = channel_transaction_parameters;
4086
4125
self.get_initial_counterparty_commitment_signature(logger)
4087
4126
}
4127
+
4128
+ // /// Splice process starting; update state; update capacity, state, reset funding tx
4129
+ // #[cfg(splicing)]
4130
+ // pub(crate) fn splice_start<L: Deref>(&mut self, is_outgoing: bool, logger: &L) where L::Target: Logger {
4131
+ // // Set state, by this point handshake is complete
4132
+ // self.channel_state = ChannelState::NegotiatingFunding(NegotiatingFundingFlags::OUR_INIT_SENT | NegotiatingFundingFlags::THEIR_INIT_SENT);
4133
+
4134
+ // log_info!(logger,
4135
+ // "Splicing process started, new channel value {}, outgoing {}, channel_id {}",
4136
+ // self.channel_value_satoshis, is_outgoing, self.channel_id,
4137
+ // );
4138
+ // }
4139
+
4140
+ /// Get the splice message that can be sent during splice initiation.
4141
+ #[cfg(splicing)]
4142
+ pub fn get_splice_init(&self, our_funding_contribution_satoshis: i64, signer_provider: &SP,
4143
+ funding_feerate_perkw: u32, locktime: u32,
4144
+ ) -> msgs::SpliceInit {
4145
+ if !self.is_outbound() {
4146
+ panic!("Tried to initiate a splice on an inbound channel!");
4147
+ }
4148
+
4149
+ // At this point we are not committed to the new channel value yet, but the funding pubkey
4150
+ // depends on the channel value, so we create here a new funding pubkey with the new
4151
+ // channel value.
4152
+ // Note that channel_keys_id is supposed NOT to change
4153
+ let funding_pubkey = {
4154
+ // TODO: Funding pubkey generation requires the post channel value, but that is not known yet,
4155
+ // the acceptor contribution is missing. There is a need for a way to generate a new funding pubkey,
4156
+ // not based on the channel value
4157
+ let pre_channel_value = self.channel_value_satoshis;
4158
+ let placeholder_counterparty_contribution = 0;
4159
+ let incomplete_post_splice_channel_value = PendingSpliceInfoPre::compute_post_value(pre_channel_value,
4160
+ our_funding_contribution_satoshis, placeholder_counterparty_contribution);
4161
+ let holder_signer = signer_provider.derive_channel_signer(incomplete_post_splice_channel_value, self.channel_keys_id);
4162
+ holder_signer.pubkeys().funding_pubkey
4163
+ };
4164
+
4165
+ msgs::SpliceInit {
4166
+ channel_id: self.channel_id,
4167
+ funding_contribution_satoshis: our_funding_contribution_satoshis,
4168
+ funding_feerate_perkw,
4169
+ locktime,
4170
+ funding_pubkey,
4171
+ require_confirmed_inputs: None,
4172
+ }
4173
+ }
4174
+
4175
+ /// Get the splice_ack message that can be sent in response to splice initiation.
4176
+ #[cfg(splicing)]
4177
+ pub fn get_splice_ack(&mut self, our_funding_contribution_satoshis: i64) -> Result<msgs::SpliceAck, ChannelError> {
4178
+ if self.is_outbound() {
4179
+ panic!("Tried to accept a splice on an outound channel!");
4180
+ }
4181
+
4182
+ // TODO(splicing): checks
4183
+
4184
+ // Note: at this point keys are already updated
4185
+ let funding_pubkey = self.get_holder_pubkeys().funding_pubkey;
4186
+ Ok(msgs::SpliceAck {
4187
+ channel_id: self.channel_id,
4188
+ funding_contribution_satoshis: our_funding_contribution_satoshis,
4189
+ funding_pubkey,
4190
+ require_confirmed_inputs: None,
4191
+ })
4192
+ }
4088
4193
}
4089
4194
4090
4195
// Internal utility functions for channels
@@ -7807,6 +7912,28 @@ impl<SP: Deref> Channel<SP> where
7807
7912
}
7808
7913
}
7809
7914
7915
+ #[cfg(splicing)]
7916
+ pub fn splice_init<ES: Deref, L: Deref>(
7917
+ &mut self, our_funding_contribution_satoshis: i64,
7918
+ _signer_provider: &SP, _entropy_source: &ES, _holder_node_id: PublicKey, logger: &L
7919
+ )
7920
+ -> Result<msgs::SpliceAck, ChannelError>
7921
+ where ES::Target: EntropySource, L::Target: Logger
7922
+ {
7923
+ if !self.context.is_outbound() {
7924
+ // TODO(splicing): Enable starting in the line below
7925
+ // Apply start of splice change in the state
7926
+ // self.context.splice_start(false, logger);
7927
+
7928
+ let splice_ack_msg = self.context.get_splice_ack(our_funding_contribution_satoshis)?;
7929
+ // TODO(splicing): start interactive funding negotiation
7930
+ // let _msg = post_chan.begin_interactive_funding_tx_construction(signer_provider, entropy_source, holder_node_id)
7931
+ // .map_err(|err| ChannelError::Warn(format!("Failed to start interactive transaction construction, {:?}", err)))?;
7932
+ Ok(splice_ack_msg)
7933
+ } else {
7934
+ Err(ChannelError::Warn("Internal consistency error: splice_init on inbound channel".into()))
7935
+ }
7936
+ }
7810
7937
7811
7938
// Send stuff to our remote peers:
7812
7939
@@ -10123,6 +10250,9 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
10123
10250
// during a signing session, but have not received `tx_signatures` we MUST set `next_funding_txid`
10124
10251
// to the txid of that interactive transaction, else we MUST NOT set it.
10125
10252
next_funding_txid,
10253
+
10254
+ #[cfg(splicing)]
10255
+ pending_splice_pre: None,
10126
10256
},
10127
10257
interactive_tx_signing_session: None,
10128
10258
})
@@ -11907,4 +12037,69 @@ mod tests {
11907
12037
assert_eq!(node_a_chan.context.channel_state, ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::THEIR_CHANNEL_READY));
11908
12038
assert!(node_a_chan.check_get_channel_ready(0, &&logger).is_some());
11909
12039
}
12040
+
12041
+ #[cfg(all(test, splicing))]
12042
+ fn get_pre_and_post(pre_channel_value: u64, our_funding_contribution: i64, their_funding_contribution: i64) -> (u64, u64) {
12043
+ use crate::ln::channel::PendingSpliceInfoPre;
12044
+
12045
+ let post_channel_value = PendingSpliceInfoPre::compute_post_value(pre_channel_value, our_funding_contribution, their_funding_contribution);
12046
+ (pre_channel_value, post_channel_value)
12047
+ }
12048
+
12049
+ #[cfg(all(test, splicing))]
12050
+ #[test]
12051
+ fn test_splice_compute_post_value() {
12052
+ {
12053
+ // increase, small amounts
12054
+ let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 6_000, 0);
12055
+ assert_eq!(pre_channel_value, 9_000);
12056
+ assert_eq!(post_channel_value, 15_000);
12057
+ }
12058
+ {
12059
+ // increase, small amounts
12060
+ let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 4_000, 2_000);
12061
+ assert_eq!(pre_channel_value, 9_000);
12062
+ assert_eq!(post_channel_value, 15_000);
12063
+ }
12064
+ {
12065
+ // increase, small amounts
12066
+ let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 0, 6_000);
12067
+ assert_eq!(pre_channel_value, 9_000);
12068
+ assert_eq!(post_channel_value, 15_000);
12069
+ }
12070
+ {
12071
+ // decrease, small amounts
12072
+ let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, -6_000, 0);
12073
+ assert_eq!(pre_channel_value, 15_000);
12074
+ assert_eq!(post_channel_value, 9_000);
12075
+ }
12076
+ {
12077
+ // decrease, small amounts
12078
+ let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, -4_000, -2_000);
12079
+ assert_eq!(pre_channel_value, 15_000);
12080
+ assert_eq!(post_channel_value, 9_000);
12081
+ }
12082
+ {
12083
+ // increase and decrease
12084
+ let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, 4_000, -2_000);
12085
+ assert_eq!(pre_channel_value, 15_000);
12086
+ assert_eq!(post_channel_value, 17_000);
12087
+ }
12088
+ let base2: u64 = 2;
12089
+ let huge63i3 = (base2.pow(63) - 3) as i64;
12090
+ assert_eq!(huge63i3, 9223372036854775805);
12091
+ assert_eq!(-huge63i3, -9223372036854775805);
12092
+ {
12093
+ // increase, large amount
12094
+ let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, huge63i3, 3);
12095
+ assert_eq!(pre_channel_value, 9_000);
12096
+ assert_eq!(post_channel_value, 9223372036854784807);
12097
+ }
12098
+ {
12099
+ // increase, large amounts
12100
+ let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, huge63i3, huge63i3);
12101
+ assert_eq!(pre_channel_value, 9_000);
12102
+ assert_eq!(post_channel_value, 9223372036854784807);
12103
+ }
12104
+ }
11910
12105
}
0 commit comments