Skip to content

Commit 2799992

Browse files
committed
Partly handle splice_init, splice_ack messages, with tests
1 parent 0c31021 commit 2799992

File tree

5 files changed

+609
-11
lines changed

5 files changed

+609
-11
lines changed

lightning/src/ln/channel.rs

Lines changed: 197 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use bitcoin::amount::Amount;
1111
use bitcoin::constants::ChainHash;
1212
use bitcoin::script::{Script, ScriptBuf, Builder, WScriptHash};
1313
use bitcoin::transaction::{Transaction, TxIn};
14-
use bitcoin::sighash;
1514
use bitcoin::sighash::EcdsaSighashType;
1615
use bitcoin::consensus::encode;
1716
use bitcoin::absolute::LockTime;
@@ -25,7 +24,9 @@ use bitcoin::hash_types::{Txid, BlockHash};
2524
use bitcoin::secp256k1::constants::PUBLIC_KEY_SIZE;
2625
use bitcoin::secp256k1::{PublicKey,SecretKey};
2726
use bitcoin::secp256k1::{Secp256k1,ecdsa::Signature};
28-
use bitcoin::secp256k1;
27+
use bitcoin::{secp256k1, sighash};
28+
#[cfg(splicing)]
29+
use bitcoin::TxIn;
2930

3031
use crate::ln::types::ChannelId;
3132
use crate::types::payment::{PaymentPreimage, PaymentHash};
@@ -1182,6 +1183,34 @@ impl UnfundedChannelContext {
11821183
}
11831184
}
11841185

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+
11851214
/// Contains everything about the channel including state, and various flags.
11861215
pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
11871216
config: LegacyChannelConfig,
@@ -1217,6 +1246,10 @@ pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
12171246
secp_ctx: Secp256k1<secp256k1::All>,
12181247
channel_value_satoshis: u64,
12191248

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+
12201253
latest_monitor_update_id: u64,
12211254

12221255
holder_signer: ChannelSignerType<SP>,
@@ -2207,6 +2240,9 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
22072240
is_manual_broadcast: false,
22082241

22092242
next_funding_txid: None,
2243+
2244+
#[cfg(splicing)]
2245+
pending_splice_pre: None,
22102246
};
22112247

22122248
Ok(channel_context)
@@ -2440,6 +2476,9 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
24402476
local_initiated_shutdown: None,
24412477
is_manual_broadcast: false,
24422478
next_funding_txid: None,
2479+
2480+
#[cfg(splicing)]
2481+
pending_splice_pre: None,
24432482
})
24442483
}
24452484

@@ -4085,6 +4124,72 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
40854124
self.channel_transaction_parameters = channel_transaction_parameters;
40864125
self.get_initial_counterparty_commitment_signature(logger)
40874126
}
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+
}
40884193
}
40894194

40904195
// Internal utility functions for channels
@@ -7807,6 +7912,28 @@ impl<SP: Deref> Channel<SP> where
78077912
}
78087913
}
78097914

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+
}
78107937

78117938
// Send stuff to our remote peers:
78127939

@@ -10123,6 +10250,9 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
1012310250
// during a signing session, but have not received `tx_signatures` we MUST set `next_funding_txid`
1012410251
// to the txid of that interactive transaction, else we MUST NOT set it.
1012510252
next_funding_txid,
10253+
10254+
#[cfg(splicing)]
10255+
pending_splice_pre: None,
1012610256
},
1012710257
interactive_tx_signing_session: None,
1012810258
})
@@ -11907,4 +12037,69 @@ mod tests {
1190712037
assert_eq!(node_a_chan.context.channel_state, ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::THEIR_CHANNEL_READY));
1190812038
assert!(node_a_chan.check_get_channel_ready(0, &&logger).is_some());
1190912039
}
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+
}
1191012105
}

0 commit comments

Comments
 (0)