Update splice messages according to new spec draft
authoroptout <13562139+optout21@users.noreply.github.com>
Mon, 24 Jun 2024 11:05:45 +0000 (13:05 +0200)
committeroptout <13562139+optout21@users.noreply.github.com>
Mon, 24 Jun 2024 11:05:45 +0000 (13:05 +0200)
19 files changed:
fuzz/src/bin/gen_target.sh
fuzz/src/bin/msg_splice_init_target.rs [new file with mode: 0644]
fuzz/src/bin/msg_splice_target.rs [deleted file]
fuzz/src/msg_targets/gen_target.sh
fuzz/src/msg_targets/mod.rs
fuzz/src/msg_targets/msg_splice.rs [deleted file]
fuzz/src/msg_targets/msg_splice_init.rs [new file with mode: 0644]
fuzz/targets.h
lightning-net-tokio/src/lib.rs
lightning/src/events/mod.rs
lightning/src/ln/channel.rs
lightning/src/ln/channelmanager.rs
lightning/src/ln/functional_test_utils.rs
lightning/src/ln/functional_tests.rs
lightning/src/ln/interactivetxs.rs
lightning/src/ln/msgs.rs
lightning/src/ln/peer_handler.rs
lightning/src/ln/wire.rs
lightning/src/util/test_utils.rs

index f124c1e0ef03bd710417cbebf0b770f81df8094e..717248aa5758165ad016d980c72cd1fd4edb3844 100755 (executable)
@@ -74,6 +74,6 @@ GEN_TEST msg_tx_abort msg_targets::
 
 GEN_TEST msg_stfu msg_targets::
 
-GEN_TEST msg_splice msg_targets::
+GEN_TEST msg_splice_init msg_targets::
 GEN_TEST msg_splice_ack msg_targets::
 GEN_TEST msg_splice_locked msg_targets::
diff --git a/fuzz/src/bin/msg_splice_init_target.rs b/fuzz/src/bin/msg_splice_init_target.rs
new file mode 100644 (file)
index 0000000..83df645
--- /dev/null
@@ -0,0 +1,120 @@
+// This file is Copyright its original authors, visible in version control
+// history.
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+// This file is auto-generated by gen_target.sh based on target_template.txt
+// To modify it, modify target_template.txt and run gen_target.sh instead.
+
+#![cfg_attr(feature = "libfuzzer_fuzz", no_main)]
+#![cfg_attr(rustfmt, rustfmt_skip)]
+
+#[cfg(not(fuzzing))]
+compile_error!("Fuzz targets need cfg=fuzzing");
+
+#[cfg(not(hashes_fuzz))]
+compile_error!("Fuzz targets need cfg=hashes_fuzz");
+
+#[cfg(not(secp256k1_fuzz))]
+compile_error!("Fuzz targets need cfg=secp256k1_fuzz");
+
+extern crate lightning_fuzz;
+use lightning_fuzz::msg_targets::msg_splice_init::*;
+
+#[cfg(feature = "afl")]
+#[macro_use] extern crate afl;
+#[cfg(feature = "afl")]
+fn main() {
+       fuzz!(|data| {
+               msg_splice_init_run(data.as_ptr(), data.len());
+       });
+}
+
+#[cfg(feature = "honggfuzz")]
+#[macro_use] extern crate honggfuzz;
+#[cfg(feature = "honggfuzz")]
+fn main() {
+       loop {
+               fuzz!(|data| {
+                       msg_splice_init_run(data.as_ptr(), data.len());
+               });
+       }
+}
+
+#[cfg(feature = "libfuzzer_fuzz")]
+#[macro_use] extern crate libfuzzer_sys;
+#[cfg(feature = "libfuzzer_fuzz")]
+fuzz_target!(|data: &[u8]| {
+       msg_splice_init_run(data.as_ptr(), data.len());
+});
+
+#[cfg(feature = "stdin_fuzz")]
+fn main() {
+       use std::io::Read;
+
+       let mut data = Vec::with_capacity(8192);
+       std::io::stdin().read_to_end(&mut data).unwrap();
+       msg_splice_init_run(data.as_ptr(), data.len());
+}
+
+#[test]
+fn run_test_cases() {
+       use std::fs;
+       use std::io::Read;
+       use lightning_fuzz::utils::test_logger::StringBuffer;
+
+       use std::sync::{atomic, Arc};
+       {
+               let data: Vec<u8> = vec![0];
+               msg_splice_init_run(data.as_ptr(), data.len());
+       }
+       let mut threads = Vec::new();
+       let threads_running = Arc::new(atomic::AtomicUsize::new(0));
+       if let Ok(tests) = fs::read_dir("test_cases/msg_splice_init") {
+               for test in tests {
+                       let mut data: Vec<u8> = Vec::new();
+                       let path = test.unwrap().path();
+                       fs::File::open(&path).unwrap().read_to_end(&mut data).unwrap();
+                       threads_running.fetch_add(1, atomic::Ordering::AcqRel);
+
+                       let thread_count_ref = Arc::clone(&threads_running);
+                       let main_thread_ref = std::thread::current();
+                       threads.push((path.file_name().unwrap().to_str().unwrap().to_string(),
+                               std::thread::spawn(move || {
+                                       let string_logger = StringBuffer::new();
+
+                                       let panic_logger = string_logger.clone();
+                                       let res = if ::std::panic::catch_unwind(move || {
+                                               msg_splice_init_test(&data, panic_logger);
+                                       }).is_err() {
+                                               Some(string_logger.into_string())
+                                       } else { None };
+                                       thread_count_ref.fetch_sub(1, atomic::Ordering::AcqRel);
+                                       main_thread_ref.unpark();
+                                       res
+                               })
+                       ));
+                       while threads_running.load(atomic::Ordering::Acquire) > 32 {
+                               std::thread::park();
+                       }
+               }
+       }
+       let mut failed_outputs = Vec::new();
+       for (test, thread) in threads.drain(..) {
+               if let Some(output) = thread.join().unwrap() {
+                       println!("\nOutput of {}:\n{}\n", test, output);
+                       failed_outputs.push(test);
+               }
+       }
+       if !failed_outputs.is_empty() {
+               println!("Test cases which failed: ");
+               for case in failed_outputs {
+                       println!("{}", case);
+               }
+               panic!();
+       }
+}
diff --git a/fuzz/src/bin/msg_splice_target.rs b/fuzz/src/bin/msg_splice_target.rs
deleted file mode 100644 (file)
index a88b189..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-// This file is Copyright its original authors, visible in version control
-// history.
-//
-// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
-// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
-// You may not use this file except in accordance with one or both of these
-// licenses.
-
-// This file is auto-generated by gen_target.sh based on target_template.txt
-// To modify it, modify target_template.txt and run gen_target.sh instead.
-
-#![cfg_attr(feature = "libfuzzer_fuzz", no_main)]
-#![cfg_attr(rustfmt, rustfmt_skip)]
-
-#[cfg(not(fuzzing))]
-compile_error!("Fuzz targets need cfg=fuzzing");
-
-#[cfg(not(hashes_fuzz))]
-compile_error!("Fuzz targets need cfg=hashes_fuzz");
-
-#[cfg(not(secp256k1_fuzz))]
-compile_error!("Fuzz targets need cfg=secp256k1_fuzz");
-
-extern crate lightning_fuzz;
-use lightning_fuzz::msg_targets::msg_splice::*;
-
-#[cfg(feature = "afl")]
-#[macro_use] extern crate afl;
-#[cfg(feature = "afl")]
-fn main() {
-       fuzz!(|data| {
-               msg_splice_run(data.as_ptr(), data.len());
-       });
-}
-
-#[cfg(feature = "honggfuzz")]
-#[macro_use] extern crate honggfuzz;
-#[cfg(feature = "honggfuzz")]
-fn main() {
-       loop {
-               fuzz!(|data| {
-                       msg_splice_run(data.as_ptr(), data.len());
-               });
-       }
-}
-
-#[cfg(feature = "libfuzzer_fuzz")]
-#[macro_use] extern crate libfuzzer_sys;
-#[cfg(feature = "libfuzzer_fuzz")]
-fuzz_target!(|data: &[u8]| {
-       msg_splice_run(data.as_ptr(), data.len());
-});
-
-#[cfg(feature = "stdin_fuzz")]
-fn main() {
-       use std::io::Read;
-
-       let mut data = Vec::with_capacity(8192);
-       std::io::stdin().read_to_end(&mut data).unwrap();
-       msg_splice_run(data.as_ptr(), data.len());
-}
-
-#[test]
-fn run_test_cases() {
-       use std::fs;
-       use std::io::Read;
-       use lightning_fuzz::utils::test_logger::StringBuffer;
-
-       use std::sync::{atomic, Arc};
-       {
-               let data: Vec<u8> = vec![0];
-               msg_splice_run(data.as_ptr(), data.len());
-       }
-       let mut threads = Vec::new();
-       let threads_running = Arc::new(atomic::AtomicUsize::new(0));
-       if let Ok(tests) = fs::read_dir("test_cases/msg_splice") {
-               for test in tests {
-                       let mut data: Vec<u8> = Vec::new();
-                       let path = test.unwrap().path();
-                       fs::File::open(&path).unwrap().read_to_end(&mut data).unwrap();
-                       threads_running.fetch_add(1, atomic::Ordering::AcqRel);
-
-                       let thread_count_ref = Arc::clone(&threads_running);
-                       let main_thread_ref = std::thread::current();
-                       threads.push((path.file_name().unwrap().to_str().unwrap().to_string(),
-                               std::thread::spawn(move || {
-                                       let string_logger = StringBuffer::new();
-
-                                       let panic_logger = string_logger.clone();
-                                       let res = if ::std::panic::catch_unwind(move || {
-                                               msg_splice_test(&data, panic_logger);
-                                       }).is_err() {
-                                               Some(string_logger.into_string())
-                                       } else { None };
-                                       thread_count_ref.fetch_sub(1, atomic::Ordering::AcqRel);
-                                       main_thread_ref.unpark();
-                                       res
-                               })
-                       ));
-                       while threads_running.load(atomic::Ordering::Acquire) > 32 {
-                               std::thread::park();
-                       }
-               }
-       }
-       let mut failed_outputs = Vec::new();
-       for (test, thread) in threads.drain(..) {
-               if let Some(output) = thread.join().unwrap() {
-                       println!("\nOutput of {}:\n{}\n", test, output);
-                       failed_outputs.push(test);
-               }
-       }
-       if !failed_outputs.is_empty() {
-               println!("Test cases which failed: ");
-               for case in failed_outputs {
-                       println!("{}", case);
-               }
-               panic!();
-       }
-}
index 05997c07573f8c4fcc57a6f7f38e32c4f87eb10c..62b1130ae9effc9194979cd89a95e754bd87bb03 100755 (executable)
@@ -64,6 +64,6 @@ GEN_TEST lightning::ln::msgs::TxAbort test_msg_simple ""
 
 GEN_TEST lightning::ln::msgs::Stfu test_msg_simple ""
 
-GEN_TEST lightning::ln::msgs::Splice test_msg_simple ""
+GEN_TEST lightning::ln::msgs::SpliceInit test_msg_simple ""
 GEN_TEST lightning::ln::msgs::SpliceAck test_msg_simple ""
 GEN_TEST lightning::ln::msgs::SpliceLocked test_msg_simple ""
index 15750a9a5b140a3402f5a8ee7b1c412be5c51428..527cb530d000a14fb16ccf8a6882c52a57dcf158 100644 (file)
@@ -43,6 +43,6 @@ pub mod msg_tx_init_rbf;
 pub mod msg_tx_ack_rbf;
 pub mod msg_tx_abort;
 pub mod msg_stfu;
-pub mod msg_splice;
+pub mod msg_splice_init;
 pub mod msg_splice_ack;
 pub mod msg_splice_locked;
diff --git a/fuzz/src/msg_targets/msg_splice.rs b/fuzz/src/msg_targets/msg_splice.rs
deleted file mode 100644 (file)
index f203da0..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-// This file is Copyright its original authors, visible in version control
-// history.
-//
-// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
-// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
-// You may not use this file except in accordance with one or both of these
-// licenses.
-
-// This file is auto-generated by gen_target.sh based on msg_target_template.txt
-// To modify it, modify msg_target_template.txt and run gen_target.sh instead.
-
-#![cfg_attr(rustfmt, rustfmt_skip)]
-
-use crate::msg_targets::utils::VecWriter;
-use crate::utils::test_logger;
-
-#[inline]
-pub fn msg_splice_test<Out: test_logger::Output>(data: &[u8], _out: Out) {
-       test_msg_simple!(lightning::ln::msgs::Splice, data);
-}
-
-#[no_mangle]
-pub extern "C" fn msg_splice_run(data: *const u8, datalen: usize) {
-       let data = unsafe { std::slice::from_raw_parts(data, datalen) };
-       test_msg_simple!(lightning::ln::msgs::Splice, data);
-}
diff --git a/fuzz/src/msg_targets/msg_splice_init.rs b/fuzz/src/msg_targets/msg_splice_init.rs
new file mode 100644 (file)
index 0000000..d2e3829
--- /dev/null
@@ -0,0 +1,27 @@
+// This file is Copyright its original authors, visible in version control
+// history.
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+// This file is auto-generated by gen_target.sh based on msg_target_template.txt
+// To modify it, modify msg_target_template.txt and run gen_target.sh instead.
+
+#![cfg_attr(rustfmt, rustfmt_skip)]
+
+use crate::msg_targets::utils::VecWriter;
+use crate::utils::test_logger;
+
+#[inline]
+pub fn msg_splice_init_test<Out: test_logger::Output>(data: &[u8], _out: Out) {
+       test_msg_simple!(lightning::ln::msgs::SpliceInit, data);
+}
+
+#[no_mangle]
+pub extern "C" fn msg_splice_init_run(data: *const u8, datalen: usize) {
+       let data = unsafe { std::slice::from_raw_parts(data, datalen) };
+       test_msg_simple!(lightning::ln::msgs::SpliceInit, data);
+}
index d8b755c1a7e5a3a7fa9cdb5732b852fd3452404c..b362477a12e0fe0bb9f04bba704f41e7d8c164a3 100644 (file)
@@ -59,6 +59,6 @@ void msg_tx_init_rbf_run(const unsigned char* data, size_t data_len);
 void msg_tx_ack_rbf_run(const unsigned char* data, size_t data_len);
 void msg_tx_abort_run(const unsigned char* data, size_t data_len);
 void msg_stfu_run(const unsigned char* data, size_t data_len);
-void msg_splice_run(const unsigned char* data, size_t data_len);
+void msg_splice_init_run(const unsigned char* data, size_t data_len);
 void msg_splice_ack_run(const unsigned char* data, size_t data_len);
 void msg_splice_locked_run(const unsigned char* data, size_t data_len);
index 6d001ca67fd5e1ec44d0307a198509d83cf2538a..5e926ae95f56e67340a3740a29052da4e6525936 100644 (file)
@@ -625,7 +625,7 @@ mod tests {
                fn handle_accept_channel_v2(&self, _their_node_id: &PublicKey, _msg: &AcceptChannelV2) {}
                fn handle_stfu(&self, _their_node_id: &PublicKey, _msg: &Stfu) {}
                #[cfg(splicing)]
-               fn handle_splice(&self, _their_node_id: &PublicKey, _msg: &Splice) {}
+               fn handle_splice_init(&self, _their_node_id: &PublicKey, _msg: &SpliceInit) {}
                #[cfg(splicing)]
                fn handle_splice_ack(&self, _their_node_id: &PublicKey, _msg: &SpliceAck) {}
                #[cfg(splicing)]
index a1d1b3aa572470bda0bf984a7f07380648ad8e1a..d717b7ff0c9296e732bbe6ba256db09701f8aa14 100644 (file)
@@ -2057,12 +2057,12 @@ pub enum MessageSendEvent {
                /// The message which should be sent.
                msg: msgs::Stfu,
        },
-       /// Used to indicate that a splice message should be sent to the peer with the given node id.
-       SendSplice {
+       /// Used to indicate that a splice_init message should be sent to the peer with the given node id.
+       SendSpliceInit {
                /// The node_id of the node which should receive this message
                node_id: PublicKey,
                /// The message which should be sent.
-               msg: msgs::Splice,
+               msg: msgs::SpliceInit,
        },
        /// Used to indicate that a splice_ack message should be sent to the peer with the given node id.
        SendSpliceAck {
index 57fbe51626bec580a111f62335dfdc63d70771d5..a9f8ff005ab1f0888daf3502ee8948dfa6e6302f 100644 (file)
@@ -7135,6 +7135,7 @@ impl<SP: Deref> Channel<SP> where
                                        channel_id: self.context.channel_id,
                                        signature,
                                        htlc_signatures,
+                                       batch: None,
                                        #[cfg(taproot)]
                                        partial_signature_with_nonce: None,
                                }, (counterparty_commitment_txid, commitment_stats.htlcs_included)))
index 274edf6d7b4238495eb87390bb8453ad76ca3a8b..ea5150cba0e5f62d113b8c25a31fd55c6fc019b1 100644 (file)
@@ -9652,7 +9652,7 @@ where
        }
 
        #[cfg(splicing)]
-       fn handle_splice(&self, counterparty_node_id: &PublicKey, msg: &msgs::Splice) {
+       fn handle_splice_init(&self, counterparty_node_id: &PublicKey, msg: &msgs::SpliceInit) {
                let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close(
                        "Splicing not supported".to_owned(),
                         msg.channel_id.clone())), *counterparty_node_id);
@@ -9859,7 +9859,7 @@ where
                                                // Quiescence
                                                &events::MessageSendEvent::SendStfu { .. } => false,
                                                // Splicing
-                                               &events::MessageSendEvent::SendSplice { .. } => false,
+                                               &events::MessageSendEvent::SendSpliceInit { .. } => false,
                                                &events::MessageSendEvent::SendSpliceAck { .. } => false,
                                                &events::MessageSendEvent::SendSpliceLocked { .. } => false,
                                                // Interactive Transaction Construction
index 7e57f20595a5b05630ace9de66b6a854043c7f56..cfec6fb18c4c99cf0f3b2203961dc4c9146f61c7 100644 (file)
@@ -884,7 +884,7 @@ pub fn remove_first_msg_event_to_node(msg_node_id: &PublicKey, msg_events: &mut
                MessageSendEvent::SendStfu { node_id, .. } => {
                        node_id == msg_node_id
                },
-               MessageSendEvent::SendSplice { node_id, .. } => {
+               MessageSendEvent::SendSpliceInit { node_id, .. } => {
                        node_id == msg_node_id
                },
                MessageSendEvent::SendSpliceAck { node_id, .. } => {
index 38be3d8b17b02db6e80b60b88ed5e060ce189b00..72415a6bae0ef2332e470cbb18cd4b433d7c988f 100644 (file)
@@ -783,6 +783,7 @@ fn test_update_fee_that_funder_cannot_afford() {
                channel_id: chan.2,
                signature: res.0,
                htlc_signatures: res.1,
+               batch: None,
                #[cfg(taproot)]
                partial_signature_with_nonce: None,
        };
@@ -1532,6 +1533,7 @@ fn test_fee_spike_violation_fails_htlc() {
                channel_id: chan.2,
                signature: res.0,
                htlc_signatures: res.1,
+               batch: None,
                #[cfg(taproot)]
                partial_signature_with_nonce: None,
        };
index 17c6990508610c196574913171300e13003acb86..653abdbc6594eb5020eb166c0f08c1e627e15b29 100644 (file)
@@ -942,6 +942,7 @@ impl InteractiveTxConstructor {
                                prevtx,
                                prevtx_out: input.previous_output.vout,
                                sequence: input.sequence.to_consensus_u32(),
+                               shared_input_txid: None,
                        };
                        do_state_transition!(self, sent_tx_add_input, &msg)?;
                        Ok(InteractiveTxMessageSend::TxAddInput(msg))
index 3e0627aac233036361bda62971f704d6ea2718d6..aa69abb712b3a0c744ff7cd7c79ad6fe0b976180 100644 (file)
@@ -410,8 +410,9 @@ pub struct ChannelReady {
 /// construction.
 pub type SerialId = u64;
 
-/// An stfu (quiescence) message to be sent by or received from the stfu initiator.
-// TODO(splicing): Add spec link for `stfu`; still in draft, using from https://github.com/lightning/bolts/pull/863
+/// An `stfu` (quiescence) message to be sent by or received from the stfu initiator.
+///
+// TODO(splicing): Add spec link for `stfu`; still in draft, using from https://github.com/lightning/bolts/pull/1160
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct Stfu {
        /// The channel ID where quiescence is intended
@@ -420,48 +421,51 @@ pub struct Stfu {
        pub initiator: u8,
 }
 
-/// A splice message to be sent by or received from the stfu initiator (splice initiator).
-// TODO(splicing): Add spec link for `splice`; still in draft, using from https://github.com/lightning/bolts/pull/863
+/// A `splice_init` message to be sent by or received from the stfu initiator (splice initiator).
+///
+// TODO(splicing): Add spec link for `splice_init`; still in draft, using from https://github.com/lightning/bolts/pull/1160
 #[derive(Clone, Debug, PartialEq, Eq)]
-pub struct Splice {
+pub struct SpliceInit {
        /// The channel ID where splicing is intended
        pub channel_id: ChannelId,
-       /// The genesis hash of the blockchain where the channel is intended to be spliced
-       pub chain_hash: ChainHash,
-       /// The intended change in channel capacity: the amount to be added (positive value)
-       /// or removed (negative value) by the sender (splice initiator) by splicing into/from the channel.
-       pub relative_satoshis: i64,
+       /// The amount the splice initiator is intending to add to its channel balance (splice-in)
+       /// or remove from its channel balance (splice-out).
+       pub funding_contribution_satoshis: i64,
        /// The feerate for the new funding transaction, set by the splice initiator
        pub funding_feerate_perkw: u32,
        /// The locktime for the new funding transaction
        pub locktime: u32,
        /// The key of the sender (splice initiator) controlling the new funding transaction
        pub funding_pubkey: PublicKey,
+       /// If set, only confirmed inputs added (by the splice acceptor) will be accepted
+       pub require_confirmed_inputs: Option<()>,
 }
 
-/// A splice_ack message to be received by or sent to the splice initiator.
+/// A `splice_ack` message to be received by or sent to the splice initiator.
 ///
-// TODO(splicing): Add spec link for `splice_ack`; still in draft, using from https://github.com/lightning/bolts/pull/863
+// TODO(splicing): Add spec link for `splice_ack`; still in draft, using from https://github.com/lightning/bolts/pull/1160
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct SpliceAck {
        /// The channel ID where splicing is intended
        pub channel_id: ChannelId,
-       /// The genesis hash of the blockchain where the channel is intended to be spliced
-       pub chain_hash: ChainHash,
-       /// The intended change in channel capacity: the amount to be added (positive value)
-       /// or removed (negative value) by the sender (splice acceptor) by splicing into/from the channel.
-       pub relative_satoshis: i64,
+       /// The amount the splice acceptor is intending to add to its channel balance (splice-in)
+       /// or remove from its channel balance (splice-out).
+       pub funding_contribution_satoshis: i64,
        /// The key of the sender (splice acceptor) controlling the new funding transaction
        pub funding_pubkey: PublicKey,
+       /// If set, only confirmed inputs added (by the splice initiator) will be accepted
+       pub require_confirmed_inputs: Option<()>,
 }
 
-/// A splice_locked message to be sent to or received from a peer.
+/// A `splice_locked` message to be sent to or received from a peer.
 ///
-// TODO(splicing): Add spec link for `splice_locked`; still in draft, using from https://github.com/lightning/bolts/pull/863
+// TODO(splicing): Add spec link for `splice_locked`; still in draft, using from https://github.com/lightning/bolts/pull/1160
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct SpliceLocked {
        /// The channel ID
        pub channel_id: ChannelId,
+       /// The ID of the new funding transaction that has been locked
+       pub splice_txid: Txid,
 }
 
 /// A tx_add_input message for adding an input during interactive transaction construction
@@ -481,6 +485,8 @@ pub struct TxAddInput {
        pub prevtx_out: u32,
        /// The sequence number of this input
        pub sequence: u32,
+       /// The ID of the previous funding transaction, when it is being added as an input during splicing
+       pub shared_input_txid: Option<Txid>,
 }
 
 /// A tx_add_output message for adding an output during interactive transaction construction.
@@ -544,7 +550,7 @@ pub struct TxSignatures {
        /// The list of witnesses
        pub witnesses: Vec<Witness>,
        /// Optional signature for the shared input -- the previous funding outpoint -- signed by both peers
-       pub funding_outpoint_sig: Option<Signature>,
+       pub shared_input_signature: Option<Signature>,
 }
 
 /// A tx_init_rbf message which initiates a replacement of the transaction after it's been
@@ -708,6 +714,15 @@ pub struct UpdateFailMalformedHTLC {
        pub failure_code: u16,
 }
 
+/// Optional batch parameters for `commitment_signed` message.
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+pub struct CommitmentSignedBatch {
+       /// Batch size N: all N `commitment_signed` messages must be received before being processed
+       pub batch_size: u16,
+       /// The funding transaction, to discriminate among multiple pending funding transactions (e.g. in case of splicing)
+       pub funding_txid: Txid,
+}
+
 /// A [`commitment_signed`] message to be sent to or received from a peer.
 ///
 /// [`commitment_signed`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#committing-updates-so-far-commitment_signed
@@ -719,6 +734,8 @@ pub struct CommitmentSigned {
        pub signature: Signature,
        /// Signatures on the HTLC transactions
        pub htlc_signatures: Vec<Signature>,
+       /// Optional batch size and other parameters
+       pub batch: Option<CommitmentSignedBatch>,
        #[cfg(taproot)]
        /// The partial Taproot signature on the commitment transaction
        pub partial_signature_with_nonce: Option<PartialSignatureWithNonce>,
@@ -1461,9 +1478,9 @@ pub trait ChannelMessageHandler : MessageSendEventsProvider {
        fn handle_stfu(&self, their_node_id: &PublicKey, msg: &Stfu);
 
        // Splicing
-       /// Handle an incoming `splice` message from the given peer.
+       /// Handle an incoming `splice_init` message from the given peer.
        #[cfg(splicing)]
-       fn handle_splice(&self, their_node_id: &PublicKey, msg: &Splice);
+       fn handle_splice_init(&self, their_node_id: &PublicKey, msg: &SpliceInit);
        /// Handle an incoming `splice_ack` message from the given peer.
        #[cfg(splicing)]
        fn handle_splice_ack(&self, their_node_id: &PublicKey, msg: &SpliceAck);
@@ -2088,24 +2105,27 @@ impl_writeable_msg!(Stfu, {
        initiator,
 }, {});
 
-impl_writeable_msg!(Splice, {
+impl_writeable_msg!(SpliceInit, {
        channel_id,
-       chain_hash,
-       relative_satoshis,
+       funding_contribution_satoshis,
        funding_feerate_perkw,
        locktime,
        funding_pubkey,
-}, {});
+}, {
+       (2, require_confirmed_inputs, option), // `splice_init_tlvs`
+});
 
 impl_writeable_msg!(SpliceAck, {
        channel_id,
-       chain_hash,
-       relative_satoshis,
+       funding_contribution_satoshis,
        funding_pubkey,
-}, {});
+}, {
+       (2, require_confirmed_inputs, option), // `splice_ack_tlvs`
+});
 
 impl_writeable_msg!(SpliceLocked, {
        channel_id,
+       splice_txid,
 }, {});
 
 impl_writeable_msg!(TxAddInput, {
@@ -2114,7 +2134,9 @@ impl_writeable_msg!(TxAddInput, {
        prevtx,
        prevtx_out,
        sequence,
-}, {});
+}, {
+       (0, shared_input_txid, option), // `funding_txid`
+});
 
 impl_writeable_msg!(TxAddOutput, {
        channel_id,
@@ -2142,7 +2164,7 @@ impl_writeable_msg!(TxSignatures, {
        tx_hash,
        witnesses,
 }, {
-       (0, funding_outpoint_sig, option),
+       (0, shared_input_signature, option), // `signature`
 });
 
 impl_writeable_msg!(TxInitRbf, {
@@ -2191,12 +2213,19 @@ impl_writeable!(ClosingSignedFeeRange, {
        max_fee_satoshis
 });
 
+impl_writeable_msg!(CommitmentSignedBatch, {
+       batch_size,
+       funding_txid,
+}, {});
+
 #[cfg(not(taproot))]
 impl_writeable_msg!(CommitmentSigned, {
        channel_id,
        signature,
        htlc_signatures
-}, {});
+}, {
+       (0, batch, option),
+});
 
 #[cfg(taproot)]
 impl_writeable_msg!(CommitmentSigned, {
@@ -2204,7 +2233,8 @@ impl_writeable_msg!(CommitmentSigned, {
        signature,
        htlc_signatures
 }, {
-       (2, partial_signature_with_nonce, option)
+       (0, batch, option),
+       (2, partial_signature_with_nonce, option),
 });
 
 impl_writeable!(DecodedOnionErrorPacket, {
@@ -3851,19 +3881,19 @@ mod tests {
        }
 
        #[test]
-       fn encoding_splice() {
+       fn encoding_splice_init() {
                let secp_ctx = Secp256k1::new();
                let (_, pubkey_1,) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
-               let splice = msgs::Splice {
-                       chain_hash: ChainHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(),
+               let splice_init = msgs::SpliceInit {
                        channel_id: ChannelId::from_bytes([2; 32]),
-                       relative_satoshis: 123456,
+                       funding_contribution_satoshis: -123456,
                        funding_feerate_perkw: 2000,
                        locktime: 0,
                        funding_pubkey: pubkey_1,
+                       require_confirmed_inputs: Some(()),
                };
-               let encoded_value = splice.encode();
-               assert_eq!(encoded_value.as_hex().to_string(), "02020202020202020202020202020202020202020202020202020202020202026fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000000000000001e240000007d000000000031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f");
+               let encoded_value = splice_init.encode();
+               assert_eq!(encoded_value.as_hex().to_string(), "0202020202020202020202020202020202020202020202020202020202020202fffffffffffe1dc0000007d000000000031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f0200");
        }
 
        #[test]
@@ -3880,23 +3910,24 @@ mod tests {
        fn encoding_splice_ack() {
                let secp_ctx = Secp256k1::new();
                let (_, pubkey_1,) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
-               let splice = msgs::SpliceAck {
-                       chain_hash: ChainHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(),
+               let splice_ack = msgs::SpliceAck {
                        channel_id: ChannelId::from_bytes([2; 32]),
-                       relative_satoshis: 123456,
+                       funding_contribution_satoshis: -123456,
                        funding_pubkey: pubkey_1,
+                       require_confirmed_inputs: Some(()),
                };
-               let encoded_value = splice.encode();
-               assert_eq!(encoded_value.as_hex().to_string(), "02020202020202020202020202020202020202020202020202020202020202026fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000000000000001e240031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f");
+               let encoded_value = splice_ack.encode();
+               assert_eq!(encoded_value.as_hex().to_string(), "0202020202020202020202020202020202020202020202020202020202020202fffffffffffe1dc0031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f0200");
        }
 
        #[test]
        fn encoding_splice_locked() {
-               let splice = msgs::SpliceLocked {
+               let splice_locked = msgs::SpliceLocked {
                        channel_id: ChannelId::from_bytes([2; 32]),
+                       splice_txid: Txid::from_str("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(),
                };
-               let encoded_value = splice.encode();
-               assert_eq!(encoded_value.as_hex().to_string(), "0202020202020202020202020202020202020202020202020202020202020202");
+               let encoded_value = splice_locked.encode();
+               assert_eq!(encoded_value.as_hex().to_string(), "02020202020202020202020202020202020202020202020202020202020202026e96fe9f8b0ddcd729ba03cfafa5a27b050b39d354dd980814268dfa9a44d4c2");
        }
 
        #[test]
@@ -3928,10 +3959,11 @@ mod tests {
                        }).unwrap(),
                        prevtx_out: 305419896,
                        sequence: 305419896,
+                       shared_input_txid: Some(Txid::from_str("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap()),
                };
                let encoded_value = tx_add_input.encode();
-               let target_value = <Vec<u8>>::from_hex("0202020202020202020202020202020202020202020202020202020202020202000000012345678900de02000000000101779ced6c148293f86b60cb222108553d22c89207326bb7b6b897e23e64ab5b300200000000fdffffff0236dbc1000000000016001417d29e4dd454bac3b1cde50d1926da80cfc5287b9cbd03000000000016001436ec78d514df462da95e6a00c24daa8915362d420247304402206af85b7dd67450ad12c979302fac49dfacbc6a8620f49c5da2b5721cf9565ca502207002b32fed9ce1bf095f57aeb10c36928ac60b12e723d97d2964a54640ceefa701210301ab7dc16488303549bfcdd80f6ae5ee4c20bf97ab5410bbd6b1bfa85dcd6944000000001234567812345678").unwrap();
-               assert_eq!(encoded_value, target_value);
+               let target_value = "0202020202020202020202020202020202020202020202020202020202020202000000012345678900de02000000000101779ced6c148293f86b60cb222108553d22c89207326bb7b6b897e23e64ab5b300200000000fdffffff0236dbc1000000000016001417d29e4dd454bac3b1cde50d1926da80cfc5287b9cbd03000000000016001436ec78d514df462da95e6a00c24daa8915362d420247304402206af85b7dd67450ad12c979302fac49dfacbc6a8620f49c5da2b5721cf9565ca502207002b32fed9ce1bf095f57aeb10c36928ac60b12e723d97d2964a54640ceefa701210301ab7dc16488303549bfcdd80f6ae5ee4c20bf97ab5410bbd6b1bfa85dcd694400000000123456781234567800206e96fe9f8b0ddcd729ba03cfafa5a27b050b39d354dd980814268dfa9a44d4c2";
+               assert_eq!(encoded_value.as_hex().to_string(), target_value);
        }
 
        #[test]
@@ -3996,7 +4028,7 @@ mod tests {
                                        <Vec<u8>>::from_hex("3045022100ee00dbf4a862463e837d7c08509de814d620e4d9830fa84818713e0fa358f145022021c3c7060c4d53fe84fd165d60208451108a778c13b92ca4c6bad439236126cc01").unwrap(),
                                        <Vec<u8>>::from_hex("028fbbf0b16f5ba5bcb5dd37cd4047ce6f726a21c06682f9ec2f52b057de1dbdb5").unwrap()]),
                        ],
-                       funding_outpoint_sig: Some(sig_1),
+                       shared_input_signature: Some(sig_1),
                };
                let encoded_value = tx_signatures.encode();
                let mut target_value = <Vec<u8>>::from_hex("0202020202020202020202020202020202020202020202020202020202020202").unwrap(); // channel_id
@@ -4225,17 +4257,19 @@ mod tests {
                        channel_id: ChannelId::from_bytes([2; 32]),
                        signature: sig_1,
                        htlc_signatures: if htlcs { vec![sig_2, sig_3, sig_4] } else { Vec::new() },
+                       batch: Some(msgs::CommitmentSignedBatch { batch_size: 3, funding_txid: Txid::from_str("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap() }),
                        #[cfg(taproot)]
                        partial_signature_with_nonce: None,
                };
                let encoded_value = commitment_signed.encode();
-               let mut target_value = <Vec<u8>>::from_hex("0202020202020202020202020202020202020202020202020202020202020202d977cb9b53d93a6ff64bb5f1e158b4094b66e798fb12911168a3ccdf80a83096340a6a95da0ae8d9f776528eecdbb747eb6b545495a4319ed5378e35b21e073a").unwrap();
+               let mut target_value = "0202020202020202020202020202020202020202020202020202020202020202d977cb9b53d93a6ff64bb5f1e158b4094b66e798fb12911168a3ccdf80a83096340a6a95da0ae8d9f776528eecdbb747eb6b545495a4319ed5378e35b21e073a".to_string();
                if htlcs {
-                       target_value.append(&mut <Vec<u8>>::from_hex("00031735b6a427e80d5fe7cd90a2f4ee08dc9c27cda7c35a4172e5d85b12c49d4232537e98f9b1f3c5e6989a8b9644e90e8918127680dbd0d4043510840fc0f1e11a216c280b5395a2546e7e4b2663e04f811622f15a4f91e83aa2e92ba2a573c139142c54ae63072a1ec1ee7dc0c04bde5c847806172aa05c92c22ae8e308d1d2692b12cc195ce0a2d1bda6a88befa19fa07f51caa75ce83837f28965600b8aacab0855ffb0e741ec5f7c41421e9829a9d48611c8c831f71be5ea73e66594977ffd").unwrap());
+                       target_value += "00031735b6a427e80d5fe7cd90a2f4ee08dc9c27cda7c35a4172e5d85b12c49d4232537e98f9b1f3c5e6989a8b9644e90e8918127680dbd0d4043510840fc0f1e11a216c280b5395a2546e7e4b2663e04f811622f15a4f91e83aa2e92ba2a573c139142c54ae63072a1ec1ee7dc0c04bde5c847806172aa05c92c22ae8e308d1d2692b12cc195ce0a2d1bda6a88befa19fa07f51caa75ce83837f28965600b8aacab0855ffb0e741ec5f7c41421e9829a9d48611c8c831f71be5ea73e66594977ffd";
                } else {
-                       target_value.append(&mut <Vec<u8>>::from_hex("0000").unwrap());
+                       target_value += "0000";
                }
-               assert_eq!(encoded_value, target_value);
+               target_value += "002200036e96fe9f8b0ddcd729ba03cfafa5a27b050b39d354dd980814268dfa9a44d4c2"; // batch
+               assert_eq!(encoded_value.as_hex().to_string(), target_value);
        }
 
        #[test]
index 448dd213dad553ba8143e15b9d32cbea2fb1464c..4911fb24f6500a50e8168390b41a0c9f53f1db15 100644 (file)
@@ -265,7 +265,7 @@ impl ChannelMessageHandler for ErroringMessageHandler {
                ErroringMessageHandler::push_error(&self, their_node_id, msg.channel_id);
        }
        #[cfg(splicing)]
-       fn handle_splice(&self, their_node_id: &PublicKey, msg: &msgs::Splice) {
+       fn handle_splice_init(&self, their_node_id: &PublicKey, msg: &msgs::SpliceInit) {
                ErroringMessageHandler::push_error(&self, their_node_id, msg.channel_id);
        }
        #[cfg(splicing)]
@@ -1806,8 +1806,8 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
 
                        #[cfg(splicing)]
                        // Splicing messages:
-                       wire::Message::Splice(msg) => {
-                               self.message_handler.chan_handler.handle_splice(&their_node_id, &msg);
+                       wire::Message::SpliceInit(msg) => {
+                               self.message_handler.chan_handler.handle_splice_init(&their_node_id, &msg);
                        }
                        #[cfg(splicing)]
                        wire::Message::SpliceAck(msg) => {
@@ -2145,9 +2145,9 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
                                                                        &msg.channel_id);
                                                        self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
                                                }
-                                               MessageSendEvent::SendSplice { ref node_id, ref msg} => {
+                                               MessageSendEvent::SendSpliceInit { ref node_id, ref msg} => {
                                                        let logger = WithContext::from(&self.logger, Some(*node_id), Some(msg.channel_id), None);
-                                                       log_debug!(logger, "Handling SendSplice event in peer_handler for node {} for channel {}",
+                                                       log_debug!(logger, "Handling SendSpliceInit event in peer_handler for node {} for channel {}",
                                                                        log_pubkey!(node_id),
                                                                        &msg.channel_id);
                                                        self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
index 55e31399ae10074d2e72f1b04a4c1c71ed1808df..4cf5e21c17367d4b4620b7edcfd488d3820d1975 100644 (file)
@@ -61,7 +61,7 @@ pub(crate) enum Message<T> where T: core::fmt::Debug + Type + TestEq {
        FundingSigned(msgs::FundingSigned),
        Stfu(msgs::Stfu),
        #[cfg(splicing)]
-       Splice(msgs::Splice),
+       SpliceInit(msgs::SpliceInit),
        #[cfg(splicing)]
        SpliceAck(msgs::SpliceAck),
        #[cfg(splicing)]
@@ -119,7 +119,7 @@ impl<T> Writeable for Message<T> where T: core::fmt::Debug + Type + TestEq {
                        &Message::FundingSigned(ref msg) => msg.write(writer),
                        &Message::Stfu(ref msg) => msg.write(writer),
                        #[cfg(splicing)]
-                       &Message::Splice(ref msg) => msg.write(writer),
+                       &Message::SpliceInit(ref msg) => msg.write(writer),
                        #[cfg(splicing)]
                        &Message::SpliceAck(ref msg) => msg.write(writer),
                        #[cfg(splicing)]
@@ -177,7 +177,7 @@ impl<T> Type for Message<T> where T: core::fmt::Debug + Type + TestEq {
                        &Message::FundingSigned(ref msg) => msg.type_id(),
                        &Message::Stfu(ref msg) => msg.type_id(),
                        #[cfg(splicing)]
-                       &Message::Splice(ref msg) => msg.type_id(),
+                       &Message::SpliceInit(ref msg) => msg.type_id(),
                        #[cfg(splicing)]
                        &Message::SpliceAck(ref msg) => msg.type_id(),
                        #[cfg(splicing)]
@@ -280,8 +280,8 @@ fn do_read<R: io::Read, T, H: core::ops::Deref>(buffer: &mut R, message_type: u1
                        Ok(Message::FundingSigned(Readable::read(buffer)?))
                },
                #[cfg(splicing)]
-               msgs::Splice::TYPE => {
-                       Ok(Message::Splice(Readable::read(buffer)?))
+               msgs::SpliceInit::TYPE => {
+                       Ok(Message::SpliceInit(Readable::read(buffer)?))
                },
                msgs::Stfu::TYPE => {
                        Ok(Message::Stfu(Readable::read(buffer)?))
@@ -504,13 +504,13 @@ impl Encode for msgs::AcceptChannelV2 {
        const TYPE: u16 = 65;
 }
 
-impl Encode for msgs::Splice {
-       // TODO(splicing) Double check with finalized spec; draft spec contains 74, which is probably wrong as it is used by tx_Abort; CLN uses 75
-       const TYPE: u16 = 75;
+impl Encode for msgs::SpliceInit {
+       // TODO(splicing) Double check with finalized spec; draft spec contains 80; previously it was 74 (conflict with tx_abort); CLN used 75
+       const TYPE: u16 = 80;
 }
 
 impl Encode for msgs::SpliceAck {
-       const TYPE: u16 = 76;
+       const TYPE: u16 = 81;
 }
 
 impl Encode for msgs::SpliceLocked {
index f6616a8e5d2449391c2beb68d08e93c295127cee..2fea61090f0bb5ea9a680e019aa3f6917598d779 100644 (file)
@@ -800,8 +800,8 @@ impl msgs::ChannelMessageHandler for TestChannelMessageHandler {
                self.received_msg(wire::Message::Stfu(msg.clone()));
        }
        #[cfg(splicing)]
-       fn handle_splice(&self, _their_node_id: &PublicKey, msg: &msgs::Splice) {
-               self.received_msg(wire::Message::Splice(msg.clone()));
+       fn handle_splice_init(&self, _their_node_id: &PublicKey, msg: &msgs::SpliceInit) {
+               self.received_msg(wire::Message::SpliceInit(msg.clone()));
        }
        #[cfg(splicing)]
        fn handle_splice_ack(&self, _their_node_id: &PublicKey, msg: &msgs::SpliceAck) {