Skip to content

Commit 7683c1d

Browse files
committed
Partly handle splice_init, splice_ack messages, with tests
1 parent 4322b19 commit 7683c1d

File tree

5 files changed

+609
-11
lines changed

5 files changed

+609
-11
lines changed

lightning/src/ln/channel.rs

+197-2
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};
1313
use bitcoin::transaction::Transaction;
14-
use bitcoin::sighash;
1514
use bitcoin::sighash::EcdsaSighashType;
1615
use bitcoin::consensus::encode;
1716

@@ -23,7 +22,9 @@ use bitcoin::hash_types::{Txid, BlockHash};
2322
use bitcoin::secp256k1::constants::PUBLIC_KEY_SIZE;
2423
use bitcoin::secp256k1::{PublicKey,SecretKey};
2524
use bitcoin::secp256k1::{Secp256k1,ecdsa::Signature};
26-
use bitcoin::secp256k1;
25+
use bitcoin::{secp256k1, sighash};
26+
#[cfg(splicing)]
27+
use bitcoin::TxIn;
2728

2829
use crate::ln::types::ChannelId;
2930
use crate::types::payment::{PaymentPreimage, PaymentHash};
@@ -1179,6 +1180,34 @@ impl UnfundedChannelContext {
11791180
}
11801181
}
11811182

1183+
/// Info about a pending splice, used in the pre-splice channel
1184+
#[cfg(splicing)]
1185+
#[derive(Clone)]
1186+
pub(crate) struct PendingSpliceInfoPre {
1187+
pub our_funding_contribution: i64,
1188+
pub funding_feerate_perkw: u32,
1189+
pub locktime: u32,
1190+
/// The funding inputs we will be contributing to the splice.
1191+
/// TODO(splice): will be changed to TransactionU16LenLimited
1192+
pub our_funding_inputs: Vec<(TxIn, Transaction)>,
1193+
}
1194+
1195+
#[cfg(splicing)]
1196+
impl PendingSpliceInfoPre {
1197+
fn add_checked(base: u64, delta: i64) -> u64 {
1198+
if delta >= 0 {
1199+
base.saturating_add(delta as u64)
1200+
} else {
1201+
base.saturating_sub(delta.abs() as u64)
1202+
}
1203+
}
1204+
1205+
/// Compute the post-splice channel value from the pre-splice values and the peer contributions
1206+
pub fn compute_post_value(pre_channel_value: u64, our_funding_contribution: i64, their_funding_contribution: i64) -> u64 {
1207+
Self::add_checked(pre_channel_value, our_funding_contribution.saturating_add(their_funding_contribution))
1208+
}
1209+
}
1210+
11821211
/// Contains everything about the channel including state, and various flags.
11831212
pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
11841213
config: LegacyChannelConfig,
@@ -1214,6 +1243,10 @@ pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
12141243
secp_ctx: Secp256k1<secp256k1::All>,
12151244
channel_value_satoshis: u64,
12161245

1246+
/// Info about an in-progress, pending splice (if any), on the pre-splice channel
1247+
#[cfg(splicing)]
1248+
pub(crate) pending_splice_pre: Option<PendingSpliceInfoPre>,
1249+
12171250
latest_monitor_update_id: u64,
12181251

12191252
holder_signer: ChannelSignerType<SP>,
@@ -1980,6 +2013,9 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
19802013
blocked_monitor_updates: Vec::new(),
19812014

19822015
is_manual_broadcast: false,
2016+
2017+
#[cfg(splicing)]
2018+
pending_splice_pre: None,
19832019
};
19842020

19852021
Ok(channel_context)
@@ -2211,6 +2247,9 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
22112247
blocked_monitor_updates: Vec::new(),
22122248
local_initiated_shutdown: None,
22132249
is_manual_broadcast: false,
2250+
2251+
#[cfg(splicing)]
2252+
pending_splice_pre: None,
22142253
})
22152254
}
22162255

@@ -3771,6 +3810,72 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
37713810
self.channel_transaction_parameters.channel_type_features = self.channel_type.clone();
37723811
Ok(())
37733812
}
3813+
3814+
// /// Splice process starting; update state; update capacity, state, reset funding tx
3815+
// #[cfg(splicing)]
3816+
// pub(crate) fn splice_start<L: Deref>(&mut self, is_outgoing: bool, logger: &L) where L::Target: Logger {
3817+
// // Set state, by this point handshake is complete
3818+
// self.channel_state = ChannelState::NegotiatingFunding(NegotiatingFundingFlags::OUR_INIT_SENT | NegotiatingFundingFlags::THEIR_INIT_SENT);
3819+
3820+
// log_info!(logger,
3821+
// "Splicing process started, new channel value {}, outgoing {}, channel_id {}",
3822+
// self.channel_value_satoshis, is_outgoing, self.channel_id,
3823+
// );
3824+
// }
3825+
3826+
/// Get the splice message that can be sent during splice initiation.
3827+
#[cfg(splicing)]
3828+
pub fn get_splice_init(&self, our_funding_contribution_satoshis: i64, signer_provider: &SP,
3829+
funding_feerate_perkw: u32, locktime: u32,
3830+
) -> msgs::SpliceInit {
3831+
if !self.is_outbound() {
3832+
panic!("Tried to initiate a splice on an inbound channel!");
3833+
}
3834+
3835+
// At this point we are not committed to the new channel value yet, but the funding pubkey
3836+
// depends on the channel value, so we create here a new funding pubkey with the new
3837+
// channel value.
3838+
// Note that channel_keys_id is supposed NOT to change
3839+
let funding_pubkey = {
3840+
// TODO: Funding pubkey generation requires the post channel value, but that is not known yet,
3841+
// the acceptor contribution is missing. There is a need for a way to generate a new funding pubkey,
3842+
// not based on the channel value
3843+
let pre_channel_value = self.channel_value_satoshis;
3844+
let placeholder_counterparty_contribution = 0;
3845+
let incomplete_post_splice_channel_value = PendingSpliceInfoPre::compute_post_value(pre_channel_value,
3846+
our_funding_contribution_satoshis, placeholder_counterparty_contribution);
3847+
let holder_signer = signer_provider.derive_channel_signer(incomplete_post_splice_channel_value, self.channel_keys_id);
3848+
holder_signer.pubkeys().funding_pubkey
3849+
};
3850+
3851+
msgs::SpliceInit {
3852+
channel_id: self.channel_id,
3853+
funding_contribution_satoshis: our_funding_contribution_satoshis,
3854+
funding_feerate_perkw,
3855+
locktime,
3856+
funding_pubkey,
3857+
require_confirmed_inputs: None,
3858+
}
3859+
}
3860+
3861+
/// Get the splice_ack message that can be sent in response to splice initiation.
3862+
#[cfg(splicing)]
3863+
pub fn get_splice_ack(&mut self, our_funding_contribution_satoshis: i64) -> Result<msgs::SpliceAck, ChannelError> {
3864+
if self.is_outbound() {
3865+
panic!("Tried to accept a splice on an outound channel!");
3866+
}
3867+
3868+
// TODO(splicing): checks
3869+
3870+
// Note: at this point keys are already updated
3871+
let funding_pubkey = self.get_holder_pubkeys().funding_pubkey;
3872+
Ok(msgs::SpliceAck {
3873+
channel_id: self.channel_id,
3874+
funding_contribution_satoshis: our_funding_contribution_satoshis,
3875+
funding_pubkey,
3876+
require_confirmed_inputs: None,
3877+
})
3878+
}
37743879
}
37753880

37763881
// Internal utility functions for channels
@@ -7350,6 +7455,28 @@ impl<SP: Deref> Channel<SP> where
73507455
}
73517456
}
73527457

7458+
#[cfg(splicing)]
7459+
pub fn splice_init<ES: Deref, L: Deref>(
7460+
&mut self, our_funding_contribution_satoshis: i64,
7461+
_signer_provider: &SP, _entropy_source: &ES, _holder_node_id: PublicKey, logger: &L
7462+
)
7463+
-> Result<msgs::SpliceAck, ChannelError>
7464+
where ES::Target: EntropySource, L::Target: Logger
7465+
{
7466+
if !self.context.is_outbound() {
7467+
// TODO(splicing): Enable starting in the line below
7468+
// Apply start of splice change in the state
7469+
// self.context.splice_start(false, logger);
7470+
7471+
let splice_ack_msg = self.context.get_splice_ack(our_funding_contribution_satoshis)?;
7472+
// TODO(splicing): start interactive funding negotiation
7473+
// let _msg = post_chan.begin_interactive_funding_tx_construction(signer_provider, entropy_source, holder_node_id)
7474+
// .map_err(|err| ChannelError::Warn(format!("Failed to start interactive transaction construction, {:?}", err)))?;
7475+
Ok(splice_ack_msg)
7476+
} else {
7477+
Err(ChannelError::Warn("Internal consistency error: splice_init on inbound channel".into()))
7478+
}
7479+
}
73537480

73547481
// Send stuff to our remote peers:
73557482

@@ -9618,6 +9745,9 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
96189745

96199746
blocked_monitor_updates: blocked_monitor_updates.unwrap(),
96209747
is_manual_broadcast: is_manual_broadcast.unwrap_or(false),
9748+
9749+
#[cfg(splicing)]
9750+
pending_splice_pre: None,
96219751
},
96229752
#[cfg(any(dual_funding, splicing))]
96239753
dual_funding_channel_context: None,
@@ -11403,4 +11533,69 @@ mod tests {
1140311533
assert_eq!(node_a_chan.context.channel_state, ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::THEIR_CHANNEL_READY));
1140411534
assert!(node_a_chan.check_get_channel_ready(0, &&logger).is_some());
1140511535
}
11536+
11537+
#[cfg(all(test, splicing))]
11538+
fn get_pre_and_post(pre_channel_value: u64, our_funding_contribution: i64, their_funding_contribution: i64) -> (u64, u64) {
11539+
use crate::ln::channel::PendingSpliceInfoPre;
11540+
11541+
let post_channel_value = PendingSpliceInfoPre::compute_post_value(pre_channel_value, our_funding_contribution, their_funding_contribution);
11542+
(pre_channel_value, post_channel_value)
11543+
}
11544+
11545+
#[cfg(all(test, splicing))]
11546+
#[test]
11547+
fn test_splice_compute_post_value() {
11548+
{
11549+
// increase, small amounts
11550+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 6_000, 0);
11551+
assert_eq!(pre_channel_value, 9_000);
11552+
assert_eq!(post_channel_value, 15_000);
11553+
}
11554+
{
11555+
// increase, small amounts
11556+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 4_000, 2_000);
11557+
assert_eq!(pre_channel_value, 9_000);
11558+
assert_eq!(post_channel_value, 15_000);
11559+
}
11560+
{
11561+
// increase, small amounts
11562+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 0, 6_000);
11563+
assert_eq!(pre_channel_value, 9_000);
11564+
assert_eq!(post_channel_value, 15_000);
11565+
}
11566+
{
11567+
// decrease, small amounts
11568+
let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, -6_000, 0);
11569+
assert_eq!(pre_channel_value, 15_000);
11570+
assert_eq!(post_channel_value, 9_000);
11571+
}
11572+
{
11573+
// decrease, small amounts
11574+
let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, -4_000, -2_000);
11575+
assert_eq!(pre_channel_value, 15_000);
11576+
assert_eq!(post_channel_value, 9_000);
11577+
}
11578+
{
11579+
// increase and decrease
11580+
let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, 4_000, -2_000);
11581+
assert_eq!(pre_channel_value, 15_000);
11582+
assert_eq!(post_channel_value, 17_000);
11583+
}
11584+
let base2: u64 = 2;
11585+
let huge63i3 = (base2.pow(63) - 3) as i64;
11586+
assert_eq!(huge63i3, 9223372036854775805);
11587+
assert_eq!(-huge63i3, -9223372036854775805);
11588+
{
11589+
// increase, large amount
11590+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, huge63i3, 3);
11591+
assert_eq!(pre_channel_value, 9_000);
11592+
assert_eq!(post_channel_value, 9223372036854784807);
11593+
}
11594+
{
11595+
// increase, large amounts
11596+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, huge63i3, huge63i3);
11597+
assert_eq!(pre_channel_value, 9_000);
11598+
assert_eq!(post_channel_value, 9223372036854784807);
11599+
}
11600+
}
1140611601
}

0 commit comments

Comments
 (0)