Merge pull request #791 from jkczyz/2021-01-spv-client
authorMatt Corallo <649246+TheBlueMatt@users.noreply.github.com>
Fri, 26 Feb 2021 15:54:01 +0000 (07:54 -0800)
committerGitHub <noreply@github.com>
Fri, 26 Feb 2021 15:54:01 +0000 (07:54 -0800)
SPV client utility for syncing a lightning node

14 files changed:
lightning-c-bindings/include/lightning.h
lightning-c-bindings/src/c_types/derived.rs
lightning-c-bindings/src/ln/msgs.rs
lightning-c-bindings/src/routing/network_graph.rs
lightning-net-tokio/src/lib.rs
lightning/src/ln/channel.rs
lightning/src/ln/channelmanager.rs
lightning/src/ln/features.rs
lightning/src/ln/functional_test_utils.rs
lightning/src/ln/functional_tests.rs
lightning/src/ln/msgs.rs
lightning/src/ln/peer_handler.rs
lightning/src/routing/network_graph.rs
lightning/src/util/test_utils.rs

index 01a252ee3969f959e0d8e2c5744c527b422e61fa..28e54f4f3a9d84c306693548e2b27c443af6120a 100644 (file)
@@ -4150,6 +4150,8 @@ struct LDKCResult_ChannelInfoDecodeErrorZ CResult_ChannelInfoDecodeErrorZ_err(st
 
 void CResult_ChannelInfoDecodeErrorZ_free(struct LDKCResult_ChannelInfoDecodeErrorZ _res);
 
+struct LDKCResult_ChannelInfoDecodeErrorZ CResult_ChannelInfoDecodeErrorZ_clone(const struct LDKCResult_ChannelInfoDecodeErrorZ *NONNULL_PTR orig);
+
 struct LDKCResult_RoutingFeesDecodeErrorZ CResult_RoutingFeesDecodeErrorZ_ok(struct LDKRoutingFees o);
 
 struct LDKCResult_RoutingFeesDecodeErrorZ CResult_RoutingFeesDecodeErrorZ_err(struct LDKDecodeError e);
@@ -4184,6 +4186,8 @@ struct LDKCResult_NetworkGraphDecodeErrorZ CResult_NetworkGraphDecodeErrorZ_err(
 
 void CResult_NetworkGraphDecodeErrorZ_free(struct LDKCResult_NetworkGraphDecodeErrorZ _res);
 
+struct LDKCResult_NetworkGraphDecodeErrorZ CResult_NetworkGraphDecodeErrorZ_clone(const struct LDKCResult_NetworkGraphDecodeErrorZ *NONNULL_PTR orig);
+
 struct LDKC2Tuple_usizeTransactionZ C2Tuple_usizeTransactionZ_new(uintptr_t a, struct LDKTransaction b);
 
 void C2Tuple_usizeTransactionZ_free(struct LDKC2Tuple_usizeTransactionZ _res);
@@ -6149,6 +6153,18 @@ struct LDKDecodeError DecodeError_clone(const struct LDKDecodeError *NONNULL_PTR
 
 void Init_free(struct LDKInit this_ptr);
 
+/**
+ * The relevant features which the sender supports
+ */
+struct LDKInitFeatures Init_get_features(const struct LDKInit *NONNULL_PTR this_ptr);
+
+/**
+ * The relevant features which the sender supports
+ */
+void Init_set_features(struct LDKInit *NONNULL_PTR this_ptr, struct LDKInitFeatures val);
+
+MUST_USE_RES struct LDKInit Init_new(struct LDKInitFeatures features_arg);
+
 struct LDKInit Init_clone(const struct LDKInit *NONNULL_PTR orig);
 
 void ErrorMessage_free(struct LDKErrorMessage this_ptr);
@@ -8772,6 +8788,8 @@ struct LDKCResult_RouteLightningErrorZ get_route(struct LDKPublicKey our_node_id
 
 void NetworkGraph_free(struct LDKNetworkGraph this_ptr);
 
+struct LDKNetworkGraph NetworkGraph_clone(const struct LDKNetworkGraph *NONNULL_PTR orig);
+
 void LockedNetworkGraph_free(struct LDKLockedNetworkGraph this_ptr);
 
 void NetGraphMsgHandler_free(struct LDKNetGraphMsgHandler this_ptr);
@@ -8952,6 +8970,8 @@ struct LDKChannelAnnouncement ChannelInfo_get_announcement_message(const struct
  */
 void ChannelInfo_set_announcement_message(struct LDKChannelInfo *NONNULL_PTR this_ptr, struct LDKChannelAnnouncement val);
 
+struct LDKChannelInfo ChannelInfo_clone(const struct LDKChannelInfo *NONNULL_PTR orig);
+
 struct LDKCVec_u8Z ChannelInfo_write(const struct LDKChannelInfo *NONNULL_PTR obj);
 
 struct LDKCResult_ChannelInfoDecodeErrorZ ChannelInfo_read(struct LDKu8slice ser);
index d58c56b45ca851d0109b08dd96555eb8fd32c55f..f2211f191ee94f8fbe97e5494bac4626bb5c6cdd 100644 (file)
@@ -1940,6 +1940,21 @@ impl From<crate::c_types::CResultTempl<crate::routing::network_graph::ChannelInf
                }
        }
 }
+impl Clone for CResult_ChannelInfoDecodeErrorZ {
+       fn clone(&self) -> Self {
+               if self.result_ok {
+                       Self { result_ok: true, contents: CResult_ChannelInfoDecodeErrorZPtr {
+                               result: Box::into_raw(Box::new(<crate::routing::network_graph::ChannelInfo>::clone(unsafe { &*self.contents.result })))
+                       } }
+               } else {
+                       Self { result_ok: false, contents: CResult_ChannelInfoDecodeErrorZPtr {
+                               err: Box::into_raw(Box::new(<crate::ln::msgs::DecodeError>::clone(unsafe { &*self.contents.err })))
+                       } }
+               }
+       }
+}
+#[no_mangle]
+pub extern "C" fn CResult_ChannelInfoDecodeErrorZ_clone(orig: &CResult_ChannelInfoDecodeErrorZ) -> CResult_ChannelInfoDecodeErrorZ { orig.clone() }
 #[repr(C)]
 pub union CResult_RoutingFeesDecodeErrorZPtr {
        pub result: *mut crate::routing::network_graph::RoutingFees,
@@ -2305,6 +2320,21 @@ impl From<crate::c_types::CResultTempl<crate::routing::network_graph::NetworkGra
                }
        }
 }
+impl Clone for CResult_NetworkGraphDecodeErrorZ {
+       fn clone(&self) -> Self {
+               if self.result_ok {
+                       Self { result_ok: true, contents: CResult_NetworkGraphDecodeErrorZPtr {
+                               result: Box::into_raw(Box::new(<crate::routing::network_graph::NetworkGraph>::clone(unsafe { &*self.contents.result })))
+                       } }
+               } else {
+                       Self { result_ok: false, contents: CResult_NetworkGraphDecodeErrorZPtr {
+                               err: Box::into_raw(Box::new(<crate::ln::msgs::DecodeError>::clone(unsafe { &*self.contents.err })))
+                       } }
+               }
+       }
+}
+#[no_mangle]
+pub extern "C" fn CResult_NetworkGraphDecodeErrorZ_clone(orig: &CResult_NetworkGraphDecodeErrorZ) -> CResult_NetworkGraphDecodeErrorZ { orig.clone() }
 #[repr(C)]
 pub struct C2Tuple_usizeTransactionZ {
        pub a: usize,
index 308730f53508a6af72c653557fe7b10470f1309c..dd60efa03c1a480d8cb41d00d6a7d28fb2529462 100644 (file)
@@ -113,6 +113,24 @@ impl Init {
                ret
        }
 }
+/// The relevant features which the sender supports
+#[no_mangle]
+pub extern "C" fn Init_get_features(this_ptr: &Init) -> crate::ln::features::InitFeatures {
+       let mut inner_val = &mut unsafe { &mut *this_ptr.inner }.features;
+       crate::ln::features::InitFeatures { inner: unsafe { ( (&((*inner_val)) as *const _) as *mut _) }, is_owned: false }
+}
+/// The relevant features which the sender supports
+#[no_mangle]
+pub extern "C" fn Init_set_features(this_ptr: &mut Init, mut val: crate::ln::features::InitFeatures) {
+       unsafe { &mut *this_ptr.inner }.features = *unsafe { Box::from_raw(val.take_inner()) };
+}
+#[must_use]
+#[no_mangle]
+pub extern "C" fn Init_new(mut features_arg: crate::ln::features::InitFeatures) -> Init {
+       Init { inner: Box::into_raw(Box::new(nativeInit {
+               features: *unsafe { Box::from_raw(features_arg.take_inner()) },
+       })), is_owned: true }
+}
 impl Clone for Init {
        fn clone(&self) -> Self {
                Self {
index ad4c0c3b331d52150f4eb1e9dd9edecd05f080af..157dbc4225e9ab0a559bdbe2f14c2b316252ceb0 100644 (file)
@@ -42,6 +42,24 @@ impl NetworkGraph {
                ret
        }
 }
+impl Clone for NetworkGraph {
+       fn clone(&self) -> Self {
+               Self {
+                       inner: if self.inner.is_null() { std::ptr::null_mut() } else {
+                               Box::into_raw(Box::new(unsafe { &*self.inner }.clone())) },
+                       is_owned: true,
+               }
+       }
+}
+#[allow(unused)]
+/// Used only if an object of this type is returned as a trait impl by a method
+pub(crate) extern "C" fn NetworkGraph_clone_void(this_ptr: *const c_void) -> *mut c_void {
+       Box::into_raw(Box::new(unsafe { (*(this_ptr as *mut nativeNetworkGraph)).clone() })) as *mut c_void
+}
+#[no_mangle]
+pub extern "C" fn NetworkGraph_clone(orig: &NetworkGraph) -> NetworkGraph {
+       orig.clone()
+}
 
 use lightning::routing::network_graph::LockedNetworkGraph as nativeLockedNetworkGraphImport;
 type nativeLockedNetworkGraph = nativeLockedNetworkGraphImport<'static>;
@@ -559,6 +577,24 @@ pub extern "C" fn ChannelInfo_set_announcement_message(this_ptr: &mut ChannelInf
        let mut local_val = if val.inner.is_null() { None } else { Some( { *unsafe { Box::from_raw(val.take_inner()) } }) };
        unsafe { &mut *this_ptr.inner }.announcement_message = local_val;
 }
+impl Clone for ChannelInfo {
+       fn clone(&self) -> Self {
+               Self {
+                       inner: if self.inner.is_null() { std::ptr::null_mut() } else {
+                               Box::into_raw(Box::new(unsafe { &*self.inner }.clone())) },
+                       is_owned: true,
+               }
+       }
+}
+#[allow(unused)]
+/// Used only if an object of this type is returned as a trait impl by a method
+pub(crate) extern "C" fn ChannelInfo_clone_void(this_ptr: *const c_void) -> *mut c_void {
+       Box::into_raw(Box::new(unsafe { (*(this_ptr as *mut nativeChannelInfo)).clone() })) as *mut c_void
+}
+#[no_mangle]
+pub extern "C" fn ChannelInfo_clone(orig: &ChannelInfo) -> ChannelInfo {
+       orig.clone()
+}
 #[no_mangle]
 pub extern "C" fn ChannelInfo_write(obj: &ChannelInfo) -> crate::c_types::derived::CVec_u8Z {
        crate::c_types::serialize_obj(unsafe { &*unsafe { &*obj }.inner })
index f15f271e42cbe07e3ff41f5c9f5a5bc76e0f806a..051341ee98cb230b16114ee743a87a80c749e5cd 100644 (file)
@@ -551,7 +551,7 @@ mod tests {
                fn handle_funding_created(&self, _their_node_id: &PublicKey, _msg: &FundingCreated) {}
                fn handle_funding_signed(&self, _their_node_id: &PublicKey, _msg: &FundingSigned) {}
                fn handle_funding_locked(&self, _their_node_id: &PublicKey, _msg: &FundingLocked) {}
-               fn handle_shutdown(&self, _their_node_id: &PublicKey, _msg: &Shutdown) {}
+               fn handle_shutdown(&self, _their_node_id: &PublicKey, _their_features: &InitFeatures, _msg: &Shutdown) {}
                fn handle_closing_signed(&self, _their_node_id: &PublicKey, _msg: &ClosingSigned) {}
                fn handle_update_add_htlc(&self, _their_node_id: &PublicKey, _msg: &UpdateAddHTLC) {}
                fn handle_update_fulfill_htlc(&self, _their_node_id: &PublicKey, _msg: &UpdateFulfillHTLC) {}
index 0040541cbc18dcbc286c8a59040bd855fc1689be..95dcde2c25c6ba1bd3210fd34a54af6a2e4cb1b6 100644 (file)
@@ -45,6 +45,7 @@ use std::ops::Deref;
 #[cfg(any(test, feature = "fuzztarget"))]
 use std::sync::Mutex;
 use bitcoin::hashes::hex::ToHex;
+use bitcoin::blockdata::opcodes::all::OP_PUSHBYTES_0;
 
 #[cfg(test)]
 pub struct ChannelValueStat {
@@ -737,15 +738,14 @@ impl<Signer: Sign> Channel<Signer> {
                let counterparty_shutdown_scriptpubkey = if their_features.supports_upfront_shutdown_script() {
                        match &msg.shutdown_scriptpubkey {
                                &OptionalField::Present(ref script) => {
-                                       // Peer is signaling upfront_shutdown and has provided a non-accepted scriptpubkey format. We enforce it while receiving shutdown msg
-                                       if script.is_p2pkh() || script.is_p2sh() || script.is_v0_p2wsh() || script.is_v0_p2wpkh() {
-                                               Some(script.clone())
                                        // Peer is signaling upfront_shutdown and has opt-out with a 0-length script. We don't enforce anything
-                                       } else if script.len() == 0 {
+                                       if script.len() == 0 {
                                                None
                                        // Peer is signaling upfront_shutdown and has provided a non-accepted scriptpubkey format. Fail the channel
-                                       } else {
+                                       } else if is_unsupported_shutdown_script(&their_features, script) {
                                                return Err(ChannelError::Close(format!("Peer is signaling upfront_shutdown but has provided a non-accepted scriptpubkey format. script: ({})", script.to_bytes().to_hex())));
+                                       } else {
+                                               Some(script.clone())
                                        }
                                },
                                // Peer is signaling upfront shutdown but don't opt-out with correct mechanism (a.k.a 0-length script). Peer looks buggy, we fail the channel
@@ -1439,15 +1439,14 @@ impl<Signer: Sign> Channel<Signer> {
                let counterparty_shutdown_scriptpubkey = if their_features.supports_upfront_shutdown_script() {
                        match &msg.shutdown_scriptpubkey {
                                &OptionalField::Present(ref script) => {
-                                       // Peer is signaling upfront_shutdown and has provided a non-accepted scriptpubkey format. We enforce it while receiving shutdown msg
-                                       if script.is_p2pkh() || script.is_p2sh() || script.is_v0_p2wsh() || script.is_v0_p2wpkh() {
-                                               Some(script.clone())
                                        // Peer is signaling upfront_shutdown and has opt-out with a 0-length script. We don't enforce anything
-                                       } else if script.len() == 0 {
+                                       if script.len() == 0 {
                                                None
                                        // Peer is signaling upfront_shutdown and has provided a non-accepted scriptpubkey format. Fail the channel
+                                       } else if is_unsupported_shutdown_script(&their_features, script) {
+                                               return Err(ChannelError::Close(format!("Peer is signaling upfront_shutdown but has provided a non-accepted scriptpubkey format. script: ({})", script.to_bytes().to_hex())));
                                        } else {
-                                               return Err(ChannelError::Close(format!("Peer is signaling upfront_shutdown but has provided a non-accepted scriptpubkey format. scriptpubkey: ({})", script.to_bytes().to_hex())));
+                                               Some(script.clone())
                                        }
                                },
                                // Peer is signaling upfront shutdown but don't opt-out with correct mechanism (a.k.a 0-length script). Peer looks buggy, we fail the channel
@@ -3066,7 +3065,7 @@ impl<Signer: Sign> Channel<Signer> {
                })
        }
 
-       pub fn shutdown<F: Deref>(&mut self, fee_estimator: &F, msg: &msgs::Shutdown) -> Result<(Option<msgs::Shutdown>, Option<msgs::ClosingSigned>, Vec<(HTLCSource, PaymentHash)>), ChannelError>
+       pub fn shutdown<F: Deref>(&mut self, fee_estimator: &F, their_features: &InitFeatures, msg: &msgs::Shutdown) -> Result<(Option<msgs::Shutdown>, Option<msgs::ClosingSigned>, Vec<(HTLCSource, PaymentHash)>), ChannelError>
                where F::Target: FeeEstimator
        {
                if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 {
@@ -3085,14 +3084,7 @@ impl<Signer: Sign> Channel<Signer> {
                }
                assert_eq!(self.channel_state & ChannelState::ShutdownComplete as u32, 0);
 
-               // BOLT 2 says we must only send a scriptpubkey of certain standard forms, which are up to
-               // 34 bytes in length, so don't let the remote peer feed us some super fee-heavy script.
-               if self.is_outbound() && msg.scriptpubkey.len() > 34 {
-                       return Err(ChannelError::Close(format!("Got counterparty shutdown_scriptpubkey ({}) of absurd length from remote peer", msg.scriptpubkey.to_bytes().to_hex())));
-               }
-
-               //Check counterparty_shutdown_scriptpubkey form as BOLT says we must
-               if !msg.scriptpubkey.is_p2pkh() && !msg.scriptpubkey.is_p2sh() && !msg.scriptpubkey.is_v0_p2wpkh() && !msg.scriptpubkey.is_v0_p2wsh() {
+               if is_unsupported_shutdown_script(&their_features, &msg.scriptpubkey) {
                        return Err(ChannelError::Close(format!("Got a nonstandard scriptpubkey ({}) from remote peer", msg.scriptpubkey.to_bytes().to_hex())));
                }
 
@@ -4217,6 +4209,24 @@ impl<Signer: Sign> Channel<Signer> {
        }
 }
 
+fn is_unsupported_shutdown_script(their_features: &InitFeatures, script: &Script) -> bool {
+       // We restrain shutdown scripts to standards forms to avoid transactions not propagating on the p2p tx-relay network
+
+       // BOLT 2 says we must only send a scriptpubkey of certain standard forms,
+       // which for a a BIP-141-compliant witness program is at max 42 bytes in length.
+       // So don't let the remote peer feed us some super fee-heavy script.
+       let is_script_too_long = script.len() > 42;
+       if is_script_too_long {
+               return true;
+       }
+
+       if their_features.supports_shutdown_anysegwit() && script.is_witness_program() && script.as_bytes()[0] != OP_PUSHBYTES_0.into_u8() {
+               return false;
+       }
+
+       return !script.is_p2pkh() && !script.is_p2sh() && !script.is_v0_p2wpkh() && !script.is_v0_p2wsh()
+}
+
 const SERIALIZATION_VERSION: u8 = 1;
 const MIN_SERIALIZATION_VERSION: u8 = 1;
 
index 8f7fbde5f9cb131312ea2ae0d8be6df4b634474a..8fd243ae7720276c6025d6a0ece52509edc9e8c0 100644 (file)
@@ -2507,7 +2507,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                }
        }
 
-       fn internal_shutdown(&self, counterparty_node_id: &PublicKey, msg: &msgs::Shutdown) -> Result<(), MsgHandleErrInternal> {
+       fn internal_shutdown(&self, counterparty_node_id: &PublicKey, their_features: &InitFeatures, msg: &msgs::Shutdown) -> Result<(), MsgHandleErrInternal> {
                let (mut dropped_htlcs, chan_option) = {
                        let mut channel_state_lock = self.channel_state.lock().unwrap();
                        let channel_state = &mut *channel_state_lock;
@@ -2517,7 +2517,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                        if chan_entry.get().get_counterparty_node_id() != *counterparty_node_id {
                                                return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.channel_id));
                                        }
-                                       let (shutdown, closing_signed, dropped_htlcs) = try_chan_entry!(self, chan_entry.get_mut().shutdown(&self.fee_estimator, &msg), channel_state, chan_entry);
+                                       let (shutdown, closing_signed, dropped_htlcs) = try_chan_entry!(self, chan_entry.get_mut().shutdown(&self.fee_estimator, &their_features, &msg), channel_state, chan_entry);
                                        if let Some(msg) = shutdown {
                                                channel_state.pending_msg_events.push(events::MessageSendEvent::SendShutdown {
                                                        node_id: counterparty_node_id.clone(),
@@ -3369,9 +3369,9 @@ impl<Signer: Sign, M: Deref + Sync + Send, T: Deref + Sync + Send, K: Deref + Sy
                let _ = handle_error!(self, self.internal_funding_locked(counterparty_node_id, msg), *counterparty_node_id);
        }
 
-       fn handle_shutdown(&self, counterparty_node_id: &PublicKey, msg: &msgs::Shutdown) {
+       fn handle_shutdown(&self, counterparty_node_id: &PublicKey, their_features: &InitFeatures, msg: &msgs::Shutdown) {
                let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
-               let _ = handle_error!(self, self.internal_shutdown(counterparty_node_id, msg), *counterparty_node_id);
+               let _ = handle_error!(self, self.internal_shutdown(counterparty_node_id, their_features, msg), *counterparty_node_id);
        }
 
        fn handle_closing_signed(&self, counterparty_node_id: &PublicKey, msg: &msgs::ClosingSigned) {
index c97e18100fc769fd906a201f4868f3e662d21852..35c9410bc0b2b70ce4f7b5bd342b74134e950040 100644 (file)
@@ -100,6 +100,8 @@ mod sealed {
                        StaticRemoteKey,
                        // Byte 2
                        ,
+                       // Byte 3
+                       ,
                ],
                optional_features: [
                        // Byte 0
@@ -108,6 +110,8 @@ mod sealed {
                        VariableLengthOnion | PaymentSecret,
                        // Byte 2
                        BasicMPP,
+                       // Byte 3
+                       ShutdownAnySegwit,
                ],
        });
        define_context!(NodeContext {
@@ -118,6 +122,8 @@ mod sealed {
                        StaticRemoteKey,
                        // Byte 2
                        ,
+                       // Byte 3
+                       ,
                ],
                optional_features: [
                        // Byte 0
@@ -126,6 +132,8 @@ mod sealed {
                        VariableLengthOnion | PaymentSecret,
                        // Byte 2
                        BasicMPP,
+                       // Byte 3
+                       ShutdownAnySegwit,
                ],
        });
        define_context!(ChannelContext {
@@ -252,6 +260,8 @@ mod sealed {
                "Feature flags for `payment_secret`.");
        define_feature!(17, BasicMPP, [InitContext, NodeContext],
                "Feature flags for `basic_mpp`.");
+       define_feature!(27, ShutdownAnySegwit, [InitContext, NodeContext],
+               "Feature flags for `opt_shutdown_anysegwit`.");
 
        #[cfg(test)]
        define_context!(TestingContext {
@@ -549,6 +559,17 @@ impl<T: sealed::BasicMPP> Features<T> {
        }
 }
 
+impl<T: sealed::ShutdownAnySegwit> Features<T> {
+       pub(crate) fn supports_shutdown_anysegwit(&self) -> bool {
+               <T as sealed::ShutdownAnySegwit>::supports_feature(&self.flags)
+       }
+       #[cfg(test)]
+       pub(crate) fn clear_shutdown_anysegwit(mut self) -> Self {
+               <T as sealed::ShutdownAnySegwit>::clear_bits(&mut self.flags);
+               self
+       }
+}
+
 impl<T: sealed::Context> Writeable for Features<T> {
        fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
                w.size_hint(self.flags.len() + 2);
@@ -619,6 +640,9 @@ mod tests {
                assert!(!InitFeatures::known().requires_basic_mpp());
                assert!(!NodeFeatures::known().requires_basic_mpp());
 
+               assert!(InitFeatures::known().supports_shutdown_anysegwit());
+               assert!(NodeFeatures::known().supports_shutdown_anysegwit());
+
                let mut init_features = InitFeatures::known();
                assert!(init_features.initial_routing_sync());
                init_features.clear_initial_routing_sync();
@@ -657,10 +681,12 @@ mod tests {
                        // - option_data_loss_protect
                        // - var_onion_optin | static_remote_key (req) | payment_secret
                        // - basic_mpp
-                       assert_eq!(node_features.flags.len(), 3);
+                       // - opt_shutdown_anysegwit
+                       assert_eq!(node_features.flags.len(), 4);
                        assert_eq!(node_features.flags[0], 0b00000010);
                        assert_eq!(node_features.flags[1], 0b10010010);
                        assert_eq!(node_features.flags[2], 0b00000010);
+                       assert_eq!(node_features.flags[3], 0b00001000);
                }
 
                // Check that cleared flags are kept blank when converting back:
index 19802e431c4a555f2a54b732187c4b363def5186..219417d562f2cbd6a503510f9725594487e90c3d 100644 (file)
@@ -604,7 +604,7 @@ pub fn close_channel<'a, 'b, 'c>(outbound_node: &Node<'a, 'b, 'c>, inbound_node:
        let (tx_a, tx_b);
 
        node_a.close_channel(channel_id).unwrap();
-       node_b.handle_shutdown(&node_a.get_our_node_id(), &get_event_msg!(struct_a, MessageSendEvent::SendShutdown, node_b.get_our_node_id()));
+       node_b.handle_shutdown(&node_a.get_our_node_id(), &InitFeatures::known(), &get_event_msg!(struct_a, MessageSendEvent::SendShutdown, node_b.get_our_node_id()));
 
        let events_1 = node_b.get_and_clear_pending_msg_events();
        assert!(events_1.len() >= 1);
@@ -629,7 +629,7 @@ pub fn close_channel<'a, 'b, 'c>(outbound_node: &Node<'a, 'b, 'c>, inbound_node:
                })
        };
 
-       node_a.handle_shutdown(&node_b.get_our_node_id(), &shutdown_b);
+       node_a.handle_shutdown(&node_b.get_our_node_id(), &InitFeatures::known(), &shutdown_b);
        let (as_update, bs_update) = if close_inbound_first {
                assert!(node_a.get_and_clear_pending_msg_events().is_empty());
                node_a.handle_closing_signed(&node_b.get_our_node_id(), &closing_signed_b.unwrap());
index d60c611fa3611e26c2eb30eeed1d6684980acfbb..ea33bb561444bf3048141844e619b14f2959ea70 100644 (file)
@@ -55,6 +55,7 @@ use std::mem;
 
 use ln::functional_test_utils::*;
 use ln::chan_utils::CommitmentTransaction;
+use ln::msgs::OptionalField::Present;
 
 #[test]
 fn test_insane_channel_opens() {
@@ -832,9 +833,9 @@ fn pre_funding_lock_shutdown_test() {
 
        nodes[0].node.close_channel(&OutPoint { txid: tx.txid(), index: 0 }.to_channel_id()).unwrap();
        let node_0_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id());
-       nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &node_0_shutdown);
+       nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
        let node_1_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
-       nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &node_1_shutdown);
+       nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_1_shutdown);
 
        let node_0_closing_signed = get_event_msg!(nodes[0], MessageSendEvent::SendClosingSigned, nodes[1].node.get_our_node_id());
        nodes[1].node.handle_closing_signed(&nodes[0].node.get_our_node_id(), &node_0_closing_signed);
@@ -862,9 +863,9 @@ fn updates_shutdown_wait() {
 
        nodes[0].node.close_channel(&chan_1.2).unwrap();
        let node_0_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id());
-       nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &node_0_shutdown);
+       nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
        let node_1_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
-       nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &node_1_shutdown);
+       nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_1_shutdown);
 
        assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
        assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
@@ -949,13 +950,13 @@ fn htlc_fail_async_shutdown() {
 
        nodes[1].node.close_channel(&chan_1.2).unwrap();
        let node_1_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
-       nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &node_1_shutdown);
+       nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_1_shutdown);
        let node_0_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id());
 
        nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &updates.update_add_htlcs[0]);
        nodes[1].node.handle_commitment_signed(&nodes[0].node.get_our_node_id(), &updates.commitment_signed);
        check_added_monitors!(nodes[1], 1);
-       nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &node_0_shutdown);
+       nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
        commitment_signed_dance!(nodes[1], nodes[0], (), false, true, false);
 
        let updates_2 = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
@@ -1017,10 +1018,10 @@ fn do_test_shutdown_rebroadcast(recv_count: u8) {
        nodes[1].node.close_channel(&chan_1.2).unwrap();
        let node_1_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
        if recv_count > 0 {
-               nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &node_1_shutdown);
+               nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_1_shutdown);
                let node_0_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id());
                if recv_count > 1 {
-                       nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &node_0_shutdown);
+                       nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
                }
        }
 
@@ -1039,14 +1040,14 @@ fn do_test_shutdown_rebroadcast(recv_count: u8) {
        nodes[0].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &node_1_reestablish);
        let node_0_2nd_shutdown = if recv_count > 0 {
                let node_0_2nd_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id());
-               nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &node_1_2nd_shutdown);
+               nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_1_2nd_shutdown);
                node_0_2nd_shutdown
        } else {
                assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
-               nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &node_1_2nd_shutdown);
+               nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_1_2nd_shutdown);
                get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id())
        };
-       nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &node_0_2nd_shutdown);
+       nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &node_0_2nd_shutdown);
 
        assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
        assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
@@ -1106,10 +1107,10 @@ fn do_test_shutdown_rebroadcast(recv_count: u8) {
                let node_1_3rd_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
                assert!(node_1_3rd_shutdown == node_1_2nd_shutdown);
 
-               nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &node_0_3rd_shutdown);
+               nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &node_0_3rd_shutdown);
                assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
 
-               nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &node_1_3rd_shutdown);
+               nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_1_3rd_shutdown);
                let node_0_2nd_closing_signed = get_event_msg!(nodes[0], MessageSendEvent::SendClosingSigned, nodes[1].node.get_our_node_id());
                assert!(node_0_closing_signed == node_0_2nd_closing_signed);
 
@@ -7195,7 +7196,7 @@ fn test_upfront_shutdown_script() {
        let mut node_0_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[2].node.get_our_node_id());
        node_0_shutdown.scriptpubkey = Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script().to_p2sh();
        // Test we enforce upfront_scriptpbukey if by providing a diffrent one at closing that  we disconnect peer
-       nodes[2].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &node_0_shutdown);
+       nodes[2].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
     assert!(regex::Regex::new(r"Got shutdown request with a scriptpubkey \([A-Fa-f0-9]+\) which did not match their previous scriptpubkey.").unwrap().is_match(check_closed_broadcast!(nodes[2], true).unwrap().data.as_str()));
        check_added_monitors!(nodes[2], 1);
 
@@ -7204,7 +7205,7 @@ fn test_upfront_shutdown_script() {
        nodes[0].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id()).unwrap();
        let node_0_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[2].node.get_our_node_id());
        // We test that in case of peer committing upfront to a script, if it oesn't change at closing, we sign
-       nodes[2].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &node_0_shutdown);
+       nodes[2].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
        let events = nodes[2].node.get_and_clear_pending_msg_events();
        assert_eq!(events.len(), 1);
        match events[0] {
@@ -7218,7 +7219,7 @@ fn test_upfront_shutdown_script() {
        nodes[0].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id()).unwrap();
        let mut node_1_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id());
        node_1_shutdown.scriptpubkey = Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script().to_p2sh();
-       nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &node_1_shutdown);
+       nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &node_1_shutdown);
        let events = nodes[1].node.get_and_clear_pending_msg_events();
        assert_eq!(events.len(), 1);
        match events[0] {
@@ -7232,7 +7233,7 @@ fn test_upfront_shutdown_script() {
        nodes[1].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id()).unwrap();
        let mut node_0_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
        node_0_shutdown.scriptpubkey = Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script().to_p2sh();
-       nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &node_0_shutdown);
+       nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
        let events = nodes[0].node.get_and_clear_pending_msg_events();
        assert_eq!(events.len(), 1);
        match events[0] {
@@ -7246,7 +7247,7 @@ fn test_upfront_shutdown_script() {
        nodes[1].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id()).unwrap();
        let mut node_0_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
        node_0_shutdown.scriptpubkey = Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script().to_p2sh();
-       nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &node_0_shutdown);
+       nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
        let events = nodes[0].node.get_and_clear_pending_msg_events();
        assert_eq!(events.len(), 2);
        match events[0] {
@@ -7259,6 +7260,136 @@ fn test_upfront_shutdown_script() {
        }
 }
 
+#[test]
+fn test_upfront_shutdown_script_unsupport_segwit() {
+       // We test that channel is closed early
+       // if a segwit program is passed as upfront shutdown script,
+       // but the peer does not support segwit.
+       let chanmon_cfgs = create_chanmon_cfgs(2);
+       let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
+       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
+       let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+
+       nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None).unwrap();
+
+       let mut open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
+       open_channel.shutdown_scriptpubkey = Present(Builder::new().push_int(16)
+               .push_slice(&[0, 0])
+               .into_script());
+
+       let features = InitFeatures::known().clear_shutdown_anysegwit();
+       nodes[0].node.handle_open_channel(&nodes[0].node.get_our_node_id(), features, &open_channel);
+
+       let events = nodes[0].node.get_and_clear_pending_msg_events();
+       assert_eq!(events.len(), 1);
+       match events[0] {
+               MessageSendEvent::HandleError { action: ErrorAction::SendErrorMessage { ref msg }, node_id } => {
+                       assert_eq!(node_id, nodes[0].node.get_our_node_id());
+                       assert!(regex::Regex::new(r"Peer is signaling upfront_shutdown but has provided a non-accepted scriptpubkey format. script: (\([A-Fa-f0-9]+\))").unwrap().is_match(&*msg.data));
+               },
+               _ => panic!("Unexpected event"),
+       }
+}
+
+#[test]
+fn test_shutdown_script_any_segwit_allowed() {
+       let mut config = UserConfig::default();
+       config.channel_options.announced_channel = true;
+       config.peer_channel_config_limits.force_announced_channel_preference = false;
+       config.channel_options.commit_upfront_shutdown_pubkey = false;
+       let user_cfgs = [None, Some(config), None];
+       let chanmon_cfgs = create_chanmon_cfgs(3);
+       let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
+       let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &user_cfgs);
+       let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
+
+       //// We test if the remote peer accepts opt_shutdown_anysegwit, a witness program can be used on shutdown
+       let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 1000000, InitFeatures::known(), InitFeatures::known());
+       nodes[1].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id()).unwrap();
+       let mut node_0_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
+       node_0_shutdown.scriptpubkey = Builder::new().push_int(16)
+               .push_slice(&[0, 0])
+               .into_script();
+       nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
+       let events = nodes[0].node.get_and_clear_pending_msg_events();
+       assert_eq!(events.len(), 2);
+       match events[0] {
+               MessageSendEvent::SendShutdown { node_id, .. } => { assert_eq!(node_id, nodes[1].node.get_our_node_id()) }
+               _ => panic!("Unexpected event"),
+       }
+       match events[1] {
+               MessageSendEvent::SendClosingSigned { node_id, .. } => { assert_eq!(node_id, nodes[1].node.get_our_node_id()) }
+               _ => panic!("Unexpected event"),
+       }
+}
+
+#[test]
+fn test_shutdown_script_any_segwit_not_allowed() {
+       let mut config = UserConfig::default();
+       config.channel_options.announced_channel = true;
+       config.peer_channel_config_limits.force_announced_channel_preference = false;
+       config.channel_options.commit_upfront_shutdown_pubkey = false;
+       let user_cfgs = [None, Some(config), None];
+       let chanmon_cfgs = create_chanmon_cfgs(3);
+       let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
+       let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &user_cfgs);
+       let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
+
+       //// We test that if the remote peer does not accept opt_shutdown_anysegwit, the witness program cannot be used on shutdown
+       let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 1000000, InitFeatures::known(), InitFeatures::known());
+       nodes[1].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id()).unwrap();
+       let mut node_0_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
+       // Make an any segwit version script
+       node_0_shutdown.scriptpubkey = Builder::new().push_int(16)
+               .push_slice(&[0, 0])
+               .into_script();
+       let flags_no = InitFeatures::known().clear_shutdown_anysegwit();
+       nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &flags_no, &node_0_shutdown);
+       let events = nodes[0].node.get_and_clear_pending_msg_events();
+       assert_eq!(events.len(), 2);
+       match events[1] {
+               MessageSendEvent::HandleError { action: ErrorAction::SendErrorMessage { ref msg }, node_id } => {
+                       assert_eq!(node_id, nodes[1].node.get_our_node_id());
+                       assert_eq!(msg.data, "Got a nonstandard scriptpubkey (60020000) from remote peer".to_owned())
+               },
+               _ => panic!("Unexpected event"),
+       }
+       check_added_monitors!(nodes[0], 1);
+}
+
+#[test]
+fn test_shutdown_script_segwit_but_not_anysegwit() {
+       let mut config = UserConfig::default();
+       config.channel_options.announced_channel = true;
+       config.peer_channel_config_limits.force_announced_channel_preference = false;
+       config.channel_options.commit_upfront_shutdown_pubkey = false;
+       let user_cfgs = [None, Some(config), None];
+       let chanmon_cfgs = create_chanmon_cfgs(3);
+       let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
+       let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &user_cfgs);
+       let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
+
+       //// We test that if shutdown any segwit is supported and we send a witness script with 0 version, this is not accepted
+       let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 1000000, InitFeatures::known(), InitFeatures::known());
+       nodes[1].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id()).unwrap();
+       let mut node_0_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
+       // Make a segwit script that is not a valid as any segwit
+       node_0_shutdown.scriptpubkey = Builder::new().push_int(0)
+               .push_slice(&[0, 0])
+               .into_script();
+       nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
+       let events = nodes[0].node.get_and_clear_pending_msg_events();
+       assert_eq!(events.len(), 2);
+       match events[1] {
+               MessageSendEvent::HandleError { action: ErrorAction::SendErrorMessage { ref msg }, node_id } => {
+                       assert_eq!(node_id, nodes[1].node.get_our_node_id());
+                       assert_eq!(msg.data, "Got a nonstandard scriptpubkey (00020000) from remote peer".to_owned())
+               },
+               _ => panic!("Unexpected event"),
+       }
+       check_added_monitors!(nodes[0], 1);
+}
+
 #[test]
 fn test_user_configurable_csv_delay() {
        // We test our channel constructors yield errors when we pass them absurd csv delay
index 2c3e7df717bb09d744abbdf9da86893ed4159a28..3042b4d32e0a344e185ef9756654aefa759606aa 100644 (file)
@@ -66,16 +66,14 @@ pub enum DecodeError {
 }
 
 /// An init message to be sent or received from a peer
-#[derive(Clone)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct Init {
-       #[cfg(not(feature = "fuzztarget"))]
-       pub(crate) features: InitFeatures,
-       #[cfg(feature = "fuzztarget")]
+       /// The relevant features which the sender supports
        pub features: InitFeatures,
 }
 
 /// An error message to be sent or received from a peer
-#[derive(Clone)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct ErrorMessage {
        /// The channel ID involved in the error
        pub channel_id: [u8; 32],
@@ -87,7 +85,7 @@ pub struct ErrorMessage {
 }
 
 /// A ping message to be sent or received from a peer
-#[derive(Clone)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct Ping {
        /// The desired response length
        pub ponglen: u16,
@@ -97,7 +95,7 @@ pub struct Ping {
 }
 
 /// A pong message to be sent or received from a peer
-#[derive(Clone)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct Pong {
        /// The pong packet size.
        /// This field is not sent on the wire. byteslen zeros are sent.
@@ -105,7 +103,7 @@ pub struct Pong {
 }
 
 /// An open_channel message to be sent or received from a peer
-#[derive(Clone)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct OpenChannel {
        /// The genesis hash of the blockchain where the channel is to be opened
        pub chain_hash: BlockHash,
@@ -148,7 +146,7 @@ pub struct OpenChannel {
 }
 
 /// An accept_channel message to be sent or received from a peer
-#[derive(Clone)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct AcceptChannel {
        /// A temporary channel ID, until the funding outpoint is announced
        pub temporary_channel_id: [u8; 32],
@@ -183,7 +181,7 @@ pub struct AcceptChannel {
 }
 
 /// A funding_created message to be sent or received from a peer
-#[derive(Clone)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct FundingCreated {
        /// A temporary channel ID, until the funding is established
        pub temporary_channel_id: [u8; 32],
@@ -196,7 +194,7 @@ pub struct FundingCreated {
 }
 
 /// A funding_signed message to be sent or received from a peer
-#[derive(Clone)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct FundingSigned {
        /// The channel ID
        pub channel_id: [u8; 32],
@@ -205,7 +203,7 @@ pub struct FundingSigned {
 }
 
 /// A funding_locked message to be sent or received from a peer
-#[derive(Clone, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct FundingLocked {
        /// The channel ID
        pub channel_id: [u8; 32],
@@ -214,7 +212,7 @@ pub struct FundingLocked {
 }
 
 /// A shutdown message to be sent or received from a peer
-#[derive(Clone, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct Shutdown {
        /// The channel ID
        pub channel_id: [u8; 32],
@@ -224,7 +222,7 @@ pub struct Shutdown {
 }
 
 /// A closing_signed message to be sent or received from a peer
-#[derive(Clone, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct ClosingSigned {
        /// The channel ID
        pub channel_id: [u8; 32],
@@ -235,7 +233,7 @@ pub struct ClosingSigned {
 }
 
 /// An update_add_htlc message to be sent or received from a peer
-#[derive(Clone, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct UpdateAddHTLC {
        /// The channel ID
        pub channel_id: [u8; 32],
@@ -251,7 +249,7 @@ pub struct UpdateAddHTLC {
 }
 
 /// An update_fulfill_htlc message to be sent or received from a peer
-#[derive(Clone, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct UpdateFulfillHTLC {
        /// The channel ID
        pub channel_id: [u8; 32],
@@ -262,7 +260,7 @@ pub struct UpdateFulfillHTLC {
 }
 
 /// An update_fail_htlc message to be sent or received from a peer
-#[derive(Clone, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct UpdateFailHTLC {
        /// The channel ID
        pub channel_id: [u8; 32],
@@ -272,7 +270,7 @@ pub struct UpdateFailHTLC {
 }
 
 /// An update_fail_malformed_htlc message to be sent or received from a peer
-#[derive(Clone, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct UpdateFailMalformedHTLC {
        /// The channel ID
        pub channel_id: [u8; 32],
@@ -284,7 +282,7 @@ pub struct UpdateFailMalformedHTLC {
 }
 
 /// A commitment_signed message to be sent or received from a peer
-#[derive(Clone, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct CommitmentSigned {
        /// The channel ID
        pub channel_id: [u8; 32],
@@ -295,7 +293,7 @@ pub struct CommitmentSigned {
 }
 
 /// A revoke_and_ack message to be sent or received from a peer
-#[derive(Clone, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct RevokeAndACK {
        /// The channel ID
        pub channel_id: [u8; 32],
@@ -306,7 +304,7 @@ pub struct RevokeAndACK {
 }
 
 /// An update_fee message to be sent or received from a peer
-#[derive(PartialEq, Clone)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct UpdateFee {
        /// The channel ID
        pub channel_id: [u8; 32],
@@ -314,7 +312,7 @@ pub struct UpdateFee {
        pub feerate_per_kw: u32,
 }
 
-#[derive(PartialEq, Clone)]
+#[derive(Clone, Debug, PartialEq)]
 /// Proof that the sender knows the per-commitment secret of the previous commitment transaction.
 /// This is used to convince the recipient that the channel is at a certain commitment
 /// number even if they lost that data due to a local failure.  Of course, the peer may lie
@@ -328,7 +326,7 @@ pub struct DataLossProtect {
 }
 
 /// A channel_reestablish message to be sent or received from a peer
-#[derive(PartialEq, Clone)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct ChannelReestablish {
        /// The channel ID
        pub channel_id: [u8; 32],
@@ -341,7 +339,7 @@ pub struct ChannelReestablish {
 }
 
 /// An announcement_signatures message to be sent or received from a peer
-#[derive(PartialEq, Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct AnnouncementSignatures {
        /// The channel ID
        pub channel_id: [u8; 32],
@@ -354,7 +352,7 @@ pub struct AnnouncementSignatures {
 }
 
 /// An address which can be used to connect to a remote peer
-#[derive(Clone, PartialEq, Debug)]
+#[derive(Clone, Debug, PartialEq)]
 pub enum NetAddress {
        /// An IPv4 address/port on which the peer is listening.
        IPv4 {
@@ -472,7 +470,7 @@ impl Readable for Result<NetAddress, u8> {
 }
 
 /// The unsigned part of a node_announcement
-#[derive(PartialEq, Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct UnsignedNodeAnnouncement {
        /// The advertised features
        pub features: NodeFeatures,
@@ -491,7 +489,7 @@ pub struct UnsignedNodeAnnouncement {
        pub(crate) excess_address_data: Vec<u8>,
        pub(crate) excess_data: Vec<u8>,
 }
-#[derive(PartialEq, Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
 /// A node_announcement message to be sent or received from a peer
 pub struct NodeAnnouncement {
        /// The signature by the node key
@@ -501,7 +499,7 @@ pub struct NodeAnnouncement {
 }
 
 /// The unsigned part of a channel_announcement
-#[derive(PartialEq, Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct UnsignedChannelAnnouncement {
        /// The advertised channel features
        pub features: ChannelFeatures,
@@ -520,7 +518,7 @@ pub struct UnsignedChannelAnnouncement {
        pub(crate) excess_data: Vec<u8>,
 }
 /// A channel_announcement message to be sent or received from a peer
-#[derive(PartialEq, Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct ChannelAnnouncement {
        /// Authentication of the announcement by the first public node
        pub node_signature_1: Signature,
@@ -535,7 +533,7 @@ pub struct ChannelAnnouncement {
 }
 
 /// The unsigned part of a channel_update
-#[derive(PartialEq, Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct UnsignedChannelUpdate {
        /// The genesis hash of the blockchain where the channel is to be opened
        pub chain_hash: BlockHash,
@@ -558,7 +556,7 @@ pub struct UnsignedChannelUpdate {
        pub(crate) excess_data: Vec<u8>,
 }
 /// A channel_update message to be sent or received from a peer
-#[derive(PartialEq, Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct ChannelUpdate {
        /// A signature of the channel update
        pub signature: Signature,
@@ -570,7 +568,7 @@ pub struct ChannelUpdate {
 /// UTXOs in a range of blocks. The recipient of a query makes a best
 /// effort to reply to the query using one or more reply_channel_range
 /// messages.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct QueryChannelRange {
        /// The genesis hash of the blockchain being queried
        pub chain_hash: BlockHash,
@@ -587,7 +585,7 @@ pub struct QueryChannelRange {
 /// not be a perfect view of the network. The short_channel_ids in the
 /// reply are encoded. We only support encoding_type=0 uncompressed
 /// serialization and do not support encoding_type=1 zlib serialization.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct ReplyChannelRange {
        /// The genesis hash of the blockchain being queried
        pub chain_hash: BlockHash,
@@ -609,7 +607,7 @@ pub struct ReplyChannelRange {
 /// reply_short_channel_ids_end message. The short_channel_ids sent in
 /// this query are encoded. We only support encoding_type=0 uncompressed
 /// serialization and do not support encoding_type=1 zlib serialization.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct QueryShortChannelIds {
        /// The genesis hash of the blockchain being queried
        pub chain_hash: BlockHash,
@@ -621,7 +619,7 @@ pub struct QueryShortChannelIds {
 /// query_short_channel_ids message. The query recipient makes a best
 /// effort to respond based on their local network view which may not be
 /// a perfect view of the network.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct ReplyShortChannelIdsEnd {
        /// The genesis hash of the blockchain that was queried
        pub chain_hash: BlockHash,
@@ -633,7 +631,7 @@ pub struct ReplyShortChannelIdsEnd {
 /// A gossip_timestamp_filter message is used by a node to request
 /// gossip relay for messages in the requested time range when the
 /// gossip_queries feature has been negotiated.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct GossipTimestampFilter {
        /// The genesis hash of the blockchain for channel and node information
        pub chain_hash: BlockHash,
@@ -650,7 +648,7 @@ enum EncodingType {
 }
 
 /// Used to put an error message in a LightningError
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub enum ErrorAction {
        /// The peer took some action which made us think they were useless. Disconnect them.
        DisconnectPeer {
@@ -667,7 +665,7 @@ pub enum ErrorAction {
 }
 
 /// An Err type for failure to process messages.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub struct LightningError {
        /// A human-readable message describing the error
        pub err: String,
@@ -677,7 +675,7 @@ pub struct LightningError {
 
 /// Struct used to return values from revoke_and_ack messages, containing a bunch of commitment
 /// transaction updates if they were pending.
-#[derive(PartialEq, Clone)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct CommitmentUpdate {
        /// update_add_htlc messages which should be sent
        pub update_add_htlcs: Vec<UpdateAddHTLC>,
@@ -696,7 +694,7 @@ pub struct CommitmentUpdate {
 /// The information we received from a peer along the route of a payment we originated. This is
 /// returned by ChannelMessageHandler::handle_update_fail_htlc to be passed into
 /// RoutingMessageHandler::handle_htlc_fail_channel_update to update our network map.
-#[derive(Clone)]
+#[derive(Clone, Debug, PartialEq)]
 pub enum HTLCFailChannelUpdate {
        /// We received an error which included a full ChannelUpdate message.
        ChannelUpdateMessage {
@@ -727,7 +725,7 @@ pub enum HTLCFailChannelUpdate {
 /// OptionalFeild simply gets Present if there are enough bytes to read into it), we have a
 /// separate enum type for them.
 /// (C-not exported) due to a free generic in T
-#[derive(Clone, PartialEq, Debug)]
+#[derive(Clone, Debug, PartialEq)]
 pub enum OptionalField<T> {
        /// Optional field is included in message
        Present(T),
@@ -754,7 +752,7 @@ pub trait ChannelMessageHandler : MessageSendEventsProvider + Send + Sync {
 
        // Channl close:
        /// Handle an incoming shutdown message from the given peer.
-       fn handle_shutdown(&self, their_node_id: &PublicKey, msg: &Shutdown);
+       fn handle_shutdown(&self, their_node_id: &PublicKey, their_features: &InitFeatures, msg: &Shutdown);
        /// Handle an incoming closing_signed message from the given peer.
        fn handle_closing_signed(&self, their_node_id: &PublicKey, msg: &ClosingSigned);
 
@@ -912,7 +910,13 @@ impl PartialEq for OnionPacket {
        }
 }
 
-#[derive(Clone, PartialEq)]
+impl fmt::Debug for OnionPacket {
+       fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+               f.write_fmt(format_args!("OnionPacket version {} with hmac {:?}", self.version, &self.hmac[..]))
+       }
+}
+
+#[derive(Clone, Debug, PartialEq)]
 pub(crate) struct OnionErrorPacket {
        // This really should be a constant size slice, but the spec lets these things be up to 128KB?
        // (TODO) We limit it in decode to much lower...
@@ -932,12 +936,6 @@ impl fmt::Display for DecodeError {
        }
 }
 
-impl fmt::Debug for LightningError {
-       fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-               f.write_str(self.err.as_str())
-       }
-}
-
 impl From<::std::io::Error> for DecodeError {
        fn from(e: ::std::io::Error) -> Self {
                if e.kind() == ::std::io::ErrorKind::UnexpectedEof {
index 0e9facb8ac888aee43711439a1453085533eb536..dbd54b3b66458fc025ad974205cdf23a03c89b0e 100644 (file)
@@ -763,7 +763,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, L: Deref> PeerManager<D
                        },
 
                        wire::Message::Shutdown(msg) => {
-                               self.message_handler.chan_handler.handle_shutdown(&peer.their_node_id.unwrap(), &msg);
+                               self.message_handler.chan_handler.handle_shutdown(&peer.their_node_id.unwrap(), peer.their_features.as_ref().unwrap(), &msg);
                        },
                        wire::Message::ClosingSigned(msg) => {
                                self.message_handler.chan_handler.handle_closing_signed(&peer.their_node_id.unwrap(), &msg);
index 4c5e718fed162d66fca028f98392e0f51d23b4d7..d9a1d8279dea23fa21acbe8d91956d5a962c52fe 100644 (file)
@@ -45,7 +45,7 @@ use bitcoin::hashes::hex::ToHex;
 const MAX_EXCESS_BYTES_FOR_RELAY: usize = 1024;
 
 /// Represents the network as nodes and channels between them
-#[derive(PartialEq)]
+#[derive(Clone, PartialEq)]
 pub struct NetworkGraph {
        genesis_hash: BlockHash,
        channels: BTreeMap<u64, ChannelInfo>,
@@ -335,7 +335,7 @@ where
        }
 }
 
-#[derive(Clone, PartialEq, Debug)]
+#[derive(Clone, Debug, PartialEq)]
 /// Details about one direction of a channel. Received
 /// within a channel update.
 pub struct DirectionalChannelInfo {
@@ -376,7 +376,7 @@ impl_writeable!(DirectionalChannelInfo, 0, {
        last_update_message
 });
 
-#[derive(PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
 /// Details about a channel (both directions).
 /// Received within a channel announcement.
 pub struct ChannelInfo {
@@ -447,7 +447,7 @@ impl Writeable for RoutingFees {
        }
 }
 
-#[derive(Clone, PartialEq, Debug)]
+#[derive(Clone, Debug, PartialEq)]
 /// Information received in the latest node_announcement from this node.
 pub struct NodeAnnouncementInfo {
        /// Protocol features the node announced support for
@@ -513,7 +513,7 @@ impl Readable for NodeAnnouncementInfo {
        }
 }
 
-#[derive(Clone, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
 /// Details about a node in the network, known from the network announcement.
 pub struct NodeInfo {
        /// All valid channels a node has announced
index f0743c1f061f3ead55453e556a0f6c9759b3cd27..afc6e598e76edccffdfe022c04d693a6f78ad0d6 100644 (file)
@@ -209,7 +209,7 @@ impl msgs::ChannelMessageHandler for TestChannelMessageHandler {
        fn handle_funding_created(&self, _their_node_id: &PublicKey, _msg: &msgs::FundingCreated) {}
        fn handle_funding_signed(&self, _their_node_id: &PublicKey, _msg: &msgs::FundingSigned) {}
        fn handle_funding_locked(&self, _their_node_id: &PublicKey, _msg: &msgs::FundingLocked) {}
-       fn handle_shutdown(&self, _their_node_id: &PublicKey, _msg: &msgs::Shutdown) {}
+       fn handle_shutdown(&self, _their_node_id: &PublicKey, _their_features: &InitFeatures, _msg: &msgs::Shutdown) {}
        fn handle_closing_signed(&self, _their_node_id: &PublicKey, _msg: &msgs::ClosingSigned) {}
        fn handle_update_add_htlc(&self, _their_node_id: &PublicKey, _msg: &msgs::UpdateAddHTLC) {}
        fn handle_update_fulfill_htlc(&self, _their_node_id: &PublicKey, _msg: &msgs::UpdateFulfillHTLC) {}