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);
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);
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);
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);
*/
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);
}
}
}
+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,
}
}
}
+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,
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 {
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>;
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 })
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) {}
#[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 {
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
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
})
}
- 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 {
}
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())));
}
}
}
+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;
}
}
- 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;
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(),
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) {
StaticRemoteKey,
// Byte 2
,
+ // Byte 3
+ ,
],
optional_features: [
// Byte 0
VariableLengthOnion | PaymentSecret,
// Byte 2
BasicMPP,
+ // Byte 3
+ ShutdownAnySegwit,
],
});
define_context!(NodeContext {
StaticRemoteKey,
// Byte 2
,
+ // Byte 3
+ ,
],
optional_features: [
// Byte 0
VariableLengthOnion | PaymentSecret,
// Byte 2
BasicMPP,
+ // Byte 3
+ ShutdownAnySegwit,
],
});
define_context!(ChannelContext {
"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 {
}
}
+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);
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();
// - 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:
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);
})
};
- 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());
use ln::functional_test_utils::*;
use ln::chan_utils::CommitmentTransaction;
+use ln::msgs::OptionalField::Present;
#[test]
fn test_insane_channel_opens() {
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);
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());
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());
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);
}
}
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());
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);
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);
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] {
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] {
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] {
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] {
}
}
+#[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
}
/// 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],
}
/// 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,
}
/// 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.
}
/// 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,
}
/// 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],
}
/// 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],
}
/// 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],
}
/// 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],
}
/// 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],
}
/// 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],
}
/// 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],
}
/// 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],
}
/// 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],
}
/// 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],
}
/// 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],
}
/// 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],
}
/// 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],
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
}
/// 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],
}
/// 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],
}
/// 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 {
}
/// The unsigned part of a node_announcement
-#[derive(PartialEq, Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
pub struct UnsignedNodeAnnouncement {
/// The advertised features
pub features: NodeFeatures,
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
}
/// 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,
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,
}
/// 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,
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,
/// 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,
/// 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,
/// 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,
/// 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,
/// 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,
}
/// 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 {
}
/// 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,
/// 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>,
/// 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 {
/// 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),
// 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);
}
}
-#[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...
}
}
-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 {
},
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);
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>,
}
}
-#[derive(Clone, PartialEq, Debug)]
+#[derive(Clone, Debug, PartialEq)]
/// Details about one direction of a channel. Received
/// within a channel update.
pub struct DirectionalChannelInfo {
last_update_message
});
-#[derive(PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
/// Details about a channel (both directions).
/// Received within a channel announcement.
pub struct ChannelInfo {
}
}
-#[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
}
}
-#[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
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) {}