diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index b1b8dfebbf5..279dc92610a 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -915,15 +915,15 @@ pub fn do_test(data: &[u8], underlying_out: Out) { }, 0x0e => { if chan_a_disconnected { - nodes[0].peer_connected(&nodes[1].get_our_node_id(), &Init { features: InitFeatures::known() }); - nodes[1].peer_connected(&nodes[0].get_our_node_id(), &Init { features: InitFeatures::known() }); + nodes[0].peer_connected(&nodes[1].get_our_node_id(), &Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }); + nodes[1].peer_connected(&nodes[0].get_our_node_id(), &Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }); chan_a_disconnected = false; } }, 0x0f => { if chan_b_disconnected { - nodes[1].peer_connected(&nodes[2].get_our_node_id(), &Init { features: InitFeatures::known() }); - nodes[2].peer_connected(&nodes[1].get_our_node_id(), &Init { features: InitFeatures::known() }); + nodes[1].peer_connected(&nodes[2].get_our_node_id(), &Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }); + nodes[2].peer_connected(&nodes[1].get_our_node_id(), &Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }); chan_b_disconnected = false; } }, @@ -1118,13 +1118,13 @@ pub fn do_test(data: &[u8], underlying_out: Out) { // Next, make sure peers are all connected to each other if chan_a_disconnected { - nodes[0].peer_connected(&nodes[1].get_our_node_id(), &Init { features: InitFeatures::known() }); - nodes[1].peer_connected(&nodes[0].get_our_node_id(), &Init { features: InitFeatures::known() }); + nodes[0].peer_connected(&nodes[1].get_our_node_id(), &Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }); + nodes[1].peer_connected(&nodes[0].get_our_node_id(), &Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }); chan_a_disconnected = false; } if chan_b_disconnected { - nodes[1].peer_connected(&nodes[2].get_our_node_id(), &Init { features: InitFeatures::known() }); - nodes[2].peer_connected(&nodes[1].get_our_node_id(), &Init { features: InitFeatures::known() }); + nodes[1].peer_connected(&nodes[2].get_our_node_id(), &Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }); + nodes[2].peer_connected(&nodes[1].get_our_node_id(), &Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }); chan_b_disconnected = false; } diff --git a/lightning-background-processor/src/lib.rs b/lightning-background-processor/src/lib.rs index 39ecc316a5a..03576ed962b 100644 --- a/lightning-background-processor/src/lib.rs +++ b/lightning-background-processor/src/lib.rs @@ -397,8 +397,8 @@ mod tests { for i in 0..num_nodes { for j in (i+1)..num_nodes { - nodes[i].node.peer_connected(&nodes[j].node.get_our_node_id(), &Init { features: InitFeatures::known() }); - nodes[j].node.peer_connected(&nodes[i].node.get_our_node_id(), &Init { features: InitFeatures::known() }); + nodes[i].node.peer_connected(&nodes[j].node.get_our_node_id(), &Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }); + nodes[j].node.peer_connected(&nodes[i].node.get_our_node_id(), &Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }); } } diff --git a/lightning/src/ln/chanmon_update_fail_tests.rs b/lightning/src/ln/chanmon_update_fail_tests.rs index cb39b64a448..aea171c1c51 100644 --- a/lightning/src/ln/chanmon_update_fail_tests.rs +++ b/lightning/src/ln/chanmon_update_fail_tests.rs @@ -337,10 +337,10 @@ fn do_test_monitor_temporary_update_fail(disconnect_count: usize) { nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false); nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false); - nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]); assert_eq!(reestablish_1.len(), 1); - nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]); assert_eq!(reestablish_2.len(), 1); @@ -359,10 +359,10 @@ fn do_test_monitor_temporary_update_fail(disconnect_count: usize) { assert!(nodes[0].node.get_and_clear_pending_events().is_empty()); assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty()); - nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]); assert_eq!(reestablish_1.len(), 1); - nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]); assert_eq!(reestablish_2.len(), 1); @@ -1111,8 +1111,8 @@ fn test_monitor_update_fail_reestablish() { commitment_signed_dance!(nodes[1], nodes[2], updates.commitment_signed, false); chanmon_cfgs[1].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure)); - nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); - nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); + nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let as_reestablish = get_event_msg!(nodes[0], MessageSendEvent::SendChannelReestablish, nodes[1].node.get_our_node_id()); let bs_reestablish = get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[0].node.get_our_node_id()); @@ -1130,8 +1130,8 @@ fn test_monitor_update_fail_reestablish() { nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false); nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false); - nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); - nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); + nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); assert!(as_reestablish == get_event_msg!(nodes[0], MessageSendEvent::SendChannelReestablish, nodes[1].node.get_our_node_id())); assert!(bs_reestablish == get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[0].node.get_our_node_id())); @@ -1303,8 +1303,8 @@ fn claim_while_disconnected_monitor_update_fail() { assert!(nodes[1].node.claim_funds(payment_preimage_1)); check_added_monitors!(nodes[1], 1); - nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); - nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); + nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let as_reconnect = get_event_msg!(nodes[0], MessageSendEvent::SendChannelReestablish, nodes[1].node.get_our_node_id()); let bs_reconnect = get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[0].node.get_our_node_id()); @@ -1430,8 +1430,8 @@ fn monitor_failed_no_reestablish_response() { nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false); nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false); - nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); - nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); + nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let as_reconnect = get_event_msg!(nodes[0], MessageSendEvent::SendChannelReestablish, nodes[1].node.get_our_node_id()); let bs_reconnect = get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[0].node.get_our_node_id()); @@ -1995,9 +1995,9 @@ fn test_pending_update_fee_ack_on_reconnect() { nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false); nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false); - nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known() }); + nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }); let as_connect_msg = get_event_msg!(nodes[0], MessageSendEvent::SendChannelReestablish, nodes[1].node.get_our_node_id()); - nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known() }); + nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }); let bs_connect_msg = get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[0].node.get_our_node_id()); nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &as_connect_msg); @@ -2077,9 +2077,9 @@ fn do_update_fee_resend_test(deliver_update: bool, parallel_updates: bool) { nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false); nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false); - nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known() }); + nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }); let as_connect_msg = get_event_msg!(nodes[0], MessageSendEvent::SendChannelReestablish, nodes[1].node.get_our_node_id()); - nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known() }); + nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }); let bs_connect_msg = get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[0].node.get_our_node_id()); nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &as_connect_msg); @@ -2241,10 +2241,10 @@ fn do_channel_holding_cell_serialize(disconnect: bool, reload_a: bool) { nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false); // Now reconnect the two - nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]); assert_eq!(reestablish_1.len(), 1); - nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]); assert_eq!(reestablish_2.len(), 1); diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 0eaf244d0e4..d13bcac71f5 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -6494,8 +6494,8 @@ mod tests { let payer_pubkey = nodes[0].node.get_our_node_id(); let payee_pubkey = nodes[1].node.get_our_node_id(); - nodes[0].node.peer_connected(&payee_pubkey, &msgs::Init { features: InitFeatures::known() }); - nodes[1].node.peer_connected(&payer_pubkey, &msgs::Init { features: InitFeatures::known() }); + nodes[0].node.peer_connected(&payee_pubkey, &msgs::Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }); + nodes[1].node.peer_connected(&payer_pubkey, &msgs::Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }); let _chan = create_chan_between_nodes(&nodes[0], &nodes[1], InitFeatures::known(), InitFeatures::known()); let params = RouteParameters { @@ -6537,8 +6537,8 @@ mod tests { let payer_pubkey = nodes[0].node.get_our_node_id(); let payee_pubkey = nodes[1].node.get_our_node_id(); - nodes[0].node.peer_connected(&payee_pubkey, &msgs::Init { features: InitFeatures::known() }); - nodes[1].node.peer_connected(&payer_pubkey, &msgs::Init { features: InitFeatures::known() }); + nodes[0].node.peer_connected(&payee_pubkey, &msgs::Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }); + nodes[1].node.peer_connected(&payer_pubkey, &msgs::Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }); let _chan = create_chan_between_nodes(&nodes[0], &nodes[1], InitFeatures::known(), InitFeatures::known()); let params = RouteParameters { diff --git a/lightning/src/ln/features.rs b/lightning/src/ln/features.rs index 32ba9de7586..5b12d79f01e 100644 --- a/lightning/src/ln/features.rs +++ b/lightning/src/ln/features.rs @@ -126,6 +126,8 @@ mod sealed { , // Byte 3 , + // Byte 4 + , ], optional_features: [ // Byte 0 @@ -136,6 +138,8 @@ mod sealed { BasicMPP, // Byte 3 ShutdownAnySegwit, + // Byte 4 + CompressionAdvertisement, ], }); define_context!(NodeContext { @@ -165,7 +169,7 @@ mod sealed { // Byte 3 ShutdownAnySegwit, // Byte 4 - , + CompressionAdvertisement, // Byte 5 , // Byte 6 @@ -223,7 +227,7 @@ mod sealed { /// useful for manipulating feature flags. macro_rules! define_feature { ($odd_bit: expr, $feature: ident, [$($context: ty),+], $doc: expr, $optional_setter: ident, - $required_setter: ident) => { + $required_setter: ident, $supported_getter: ident) => { #[doc = $doc] /// /// See [BOLT #9] for details. @@ -320,6 +324,11 @@ mod sealed { ::set_required_bit(&mut self.flags); self } + + /// Checks if this feature is supported. + pub fn $supported_getter(&self) -> bool { + ::supports_feature(&self.flags) + } } $( @@ -331,41 +340,61 @@ mod sealed { const ASSERT_ODD_BIT_PARITY: usize = (::ODD_BIT % 2) - 1; } )* - + }; + ($odd_bit: expr, $feature: ident, [$($context: ty),+], $doc: expr, $optional_setter: ident, + $required_setter: ident, $supported_getter: ident, $required_getter: ident) => { + define_feature!($odd_bit, $feature, [$($context),+], $doc, $optional_setter, $required_setter, $supported_getter); + impl Features { + /// Checks if this feature is required. + pub fn $required_getter(&self) -> bool { + ::requires_feature(&self.flags) + } + } } } define_feature!(1, DataLossProtect, [InitContext, NodeContext], "Feature flags for `option_data_loss_protect`.", set_data_loss_protect_optional, - set_data_loss_protect_required); + set_data_loss_protect_required, supports_data_loss_protect, requires_data_loss_protect); // NOTE: Per Bolt #9, initial_routing_sync has no even bit. define_feature!(3, InitialRoutingSync, [InitContext], "Feature flags for `initial_routing_sync`.", - set_initial_routing_sync_optional, set_initial_routing_sync_required); + set_initial_routing_sync_optional, set_initial_routing_sync_required, + initial_routing_sync); define_feature!(5, UpfrontShutdownScript, [InitContext, NodeContext], "Feature flags for `option_upfront_shutdown_script`.", set_upfront_shutdown_script_optional, - set_upfront_shutdown_script_required); + set_upfront_shutdown_script_required, supports_upfront_shutdown_script, + requires_upfront_shutdown_script); define_feature!(7, GossipQueries, [InitContext, NodeContext], - "Feature flags for `gossip_queries`.", set_gossip_queries_optional, set_gossip_queries_required); + "Feature flags for `gossip_queries`.", set_gossip_queries_optional, set_gossip_queries_required, + supports_gossip_queries, requires_gossip_queries); define_feature!(9, VariableLengthOnion, [InitContext, NodeContext, InvoiceContext], "Feature flags for `var_onion_optin`.", set_variable_length_onion_optional, - set_variable_length_onion_required); + set_variable_length_onion_required, supports_variable_length_onion, + requires_variable_length_onion); define_feature!(13, StaticRemoteKey, [InitContext, NodeContext, ChannelTypeContext], "Feature flags for `option_static_remotekey`.", set_static_remote_key_optional, - set_static_remote_key_required); + set_static_remote_key_required, supports_static_remote_key, requires_static_remote_key); define_feature!(15, PaymentSecret, [InitContext, NodeContext, InvoiceContext], - "Feature flags for `payment_secret`.", set_payment_secret_optional, set_payment_secret_required); + "Feature flags for `payment_secret`.", set_payment_secret_optional, set_payment_secret_required, + supports_payment_secret, requires_payment_secret); define_feature!(17, BasicMPP, [InitContext, NodeContext, InvoiceContext], - "Feature flags for `basic_mpp`.", set_basic_mpp_optional, set_basic_mpp_required); + "Feature flags for `basic_mpp`.", set_basic_mpp_optional, set_basic_mpp_required, + supports_basic_mpp, requires_basic_mpp); + define_feature!(33, CompressionAdvertisement, [InitContext, NodeContext], + "Feature flags for `option_compression`.", set_compression_advertisement_optional, + set_compression_advertisement_required, supports_compression_advertisement, + requires_compression_advertisement); define_feature!(27, ShutdownAnySegwit, [InitContext, NodeContext], "Feature flags for `opt_shutdown_anysegwit`.", set_shutdown_any_segwit_optional, - set_shutdown_any_segwit_required); + set_shutdown_any_segwit_required, supports_shutdown_anysegwit, requires_shutdown_anysegwit); define_feature!(55, Keysend, [NodeContext], - "Feature flags for keysend payments.", set_keysend_optional, set_keysend_required); + "Feature flags for keysend payments.", set_keysend_optional, set_keysend_required, + supports_keysend, requires_keysend); #[cfg(test)] define_feature!(123456789, UnknownFeature, [NodeContext, ChannelContext, InvoiceContext], "Feature flags for an unknown feature used in testing.", set_unknown_feature_optional, - set_unknown_feature_required); + set_unknown_feature_required, supports_unknown_test_feature, requires_unknown_test_feature); } /// Tracks the set of features which a node implements, templated by the context in which it @@ -662,25 +691,7 @@ impl Features { } } -impl Features { - #[cfg(test)] - pub(crate) fn requires_data_loss_protect(&self) -> bool { - ::requires_feature(&self.flags) - } - #[cfg(test)] - pub(crate) fn supports_data_loss_protect(&self) -> bool { - ::supports_feature(&self.flags) - } -} - impl Features { - #[cfg(test)] - pub(crate) fn requires_upfront_shutdown_script(&self) -> bool { - ::requires_feature(&self.flags) - } - pub(crate) fn supports_upfront_shutdown_script(&self) -> bool { - ::supports_feature(&self.flags) - } #[cfg(test)] pub(crate) fn clear_upfront_shutdown_script(mut self) -> Self { ::clear_bits(&mut self.flags); @@ -690,13 +701,6 @@ impl Features { impl Features { - #[cfg(test)] - pub(crate) fn requires_gossip_queries(&self) -> bool { - ::requires_feature(&self.flags) - } - pub(crate) fn supports_gossip_queries(&self) -> bool { - ::supports_feature(&self.flags) - } #[cfg(test)] pub(crate) fn clear_gossip_queries(mut self) -> Self { ::clear_bits(&mut self.flags); @@ -704,30 +708,7 @@ impl Features { } } -impl Features { - #[cfg(test)] - pub(crate) fn requires_variable_length_onion(&self) -> bool { - ::requires_feature(&self.flags) - } - pub(crate) fn supports_variable_length_onion(&self) -> bool { - ::supports_feature(&self.flags) - } -} - -impl Features { - pub(crate) fn supports_static_remote_key(&self) -> bool { - ::supports_feature(&self.flags) - } - #[cfg(test)] - pub(crate) fn requires_static_remote_key(&self) -> bool { - ::requires_feature(&self.flags) - } -} - impl Features { - pub(crate) fn initial_routing_sync(&self) -> bool { - ::supports_feature(&self.flags) - } // We are no longer setting initial_routing_sync now that gossip_queries // is enabled. This feature is ignored by a peer when gossip_queries has // been negotiated. @@ -737,32 +718,7 @@ impl Features { } } -impl Features { - #[cfg(test)] - pub(crate) fn requires_payment_secret(&self) -> bool { - ::requires_feature(&self.flags) - } - /// Returns whether the `payment_secret` feature is supported. - pub fn supports_payment_secret(&self) -> bool { - ::supports_feature(&self.flags) - } -} - -impl Features { - #[cfg(test)] - pub(crate) fn requires_basic_mpp(&self) -> bool { - ::requires_feature(&self.flags) - } - // We currently never test for this since we don't actually *generate* multipath routes. - pub(crate) fn supports_basic_mpp(&self) -> bool { - ::supports_feature(&self.flags) - } -} - impl Features { - pub(crate) fn supports_shutdown_anysegwit(&self) -> bool { - ::supports_feature(&self.flags) - } #[cfg(test)] pub(crate) fn clear_shutdown_anysegwit(mut self) -> Self { ::clear_bits(&mut self.flags); @@ -862,6 +818,11 @@ mod tests { assert!(InitFeatures::known().supports_shutdown_anysegwit()); assert!(NodeFeatures::known().supports_shutdown_anysegwit()); + assert!(InitFeatures::known().supports_compression_advertisement()); + assert!(NodeFeatures::known().supports_compression_advertisement()); + assert!(!InitFeatures::known().requires_compression_advertisement()); + assert!(!NodeFeatures::known().requires_compression_advertisement()); + let mut init_features = InitFeatures::known(); assert!(init_features.initial_routing_sync()); init_features.clear_initial_routing_sync(); @@ -897,11 +858,13 @@ mod tests { // - var_onion_optin (req) | static_remote_key (req) | payment_secret(req) // - basic_mpp // - opt_shutdown_anysegwit - assert_eq!(node_features.flags.len(), 4); + // - opt_compression_advertisement + assert_eq!(node_features.flags.len(), 5); assert_eq!(node_features.flags[0], 0b00000010); assert_eq!(node_features.flags[1], 0b01010001); assert_eq!(node_features.flags[2], 0b00000010); assert_eq!(node_features.flags[3], 0b00001000); + assert_eq!(node_features.flags[4], 0b00000010); } // Check that cleared flags are kept blank when converting back: diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 01f9db53439..e710438e6bc 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -1638,8 +1638,8 @@ pub fn create_network<'a, 'b: 'a, 'c: 'b>(node_count: usize, cfgs: &'b Vec(node_a: &Node<'a, 'b, 'c>, node_b: &Node<'a, 'b, 'c>, send_funding_locked: (bool, bool), pending_htlc_adds: (i64, i64), pending_htlc_claims: (usize, usize), pending_htlc_fails: (usize, usize), pending_cell_htlc_claims: (usize, usize), pending_cell_htlc_fails: (usize, usize), pending_raa: (bool, bool)) { - node_a.node.peer_connected(&node_b.node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + node_a.node.peer_connected(&node_b.node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let reestablish_1 = get_chan_reestablish_msgs!(node_a, node_b); - node_b.node.peer_connected(&node_a.node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + node_b.node.peer_connected(&node_a.node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let reestablish_2 = get_chan_reestablish_msgs!(node_b, node_a); if send_funding_locked.0 { diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index 48d56b43b38..bc00ee0211c 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -3977,10 +3977,10 @@ fn test_drop_messages_peer_disconnect_dual_htlc() { nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false); nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false); - nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]); assert_eq!(reestablish_1.len(), 1); - nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]); assert_eq!(reestablish_2.len(), 1); @@ -4249,9 +4249,9 @@ fn test_no_txn_manager_serialize_deserialize() { assert_eq!(nodes[0].node.list_channels().len(), 1); check_added_monitors!(nodes[0], 1); - nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]); - nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]); nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &reestablish_1[0]); @@ -4369,9 +4369,9 @@ fn test_manager_serialize_deserialize_events() { assert_eq!(nodes[0].node.list_channels().len(), 1); check_added_monitors!(nodes[0], 1); - nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]); - nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]); nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &reestablish_1[0]); @@ -4564,9 +4564,9 @@ fn test_manager_serialize_deserialize_inconsistent_monitor() { //... and we can even still claim the payment! claim_payment(&nodes[2], &[&nodes[0], &nodes[1]], our_payment_preimage); - nodes[3].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[3].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let reestablish = get_event_msg!(nodes[3], MessageSendEvent::SendChannelReestablish, nodes[0].node.get_our_node_id()); - nodes[0].node.peer_connected(&nodes[3].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[0].node.peer_connected(&nodes[3].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); nodes[0].node.handle_channel_reestablish(&nodes[3].node.get_our_node_id(), &reestablish); let msg_events = nodes[0].node.get_and_clear_pending_msg_events(); assert_eq!(msg_events.len(), 1); @@ -6611,10 +6611,10 @@ fn test_update_add_htlc_bolt2_receiver_check_repeated_id_ignore() { //Disconnect and Reconnect nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false); nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false); - nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]); assert_eq!(reestablish_1.len(), 1); - nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]); assert_eq!(reestablish_2.len(), 1); nodes[0].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &reestablish_2[0]); @@ -7250,8 +7250,8 @@ fn test_data_loss_protect() { check_added_monitors!(nodes[0], 1); - nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); - nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); + nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let reestablish_0 = get_chan_reestablish_msgs!(nodes[1], nodes[0]); @@ -7398,10 +7398,10 @@ fn test_announce_disable_channels() { } } // Reconnect peers - nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let reestablish_1 = get_chan_reestablish_msgs!(nodes[0], nodes[1]); assert_eq!(reestablish_1.len(), 3); - nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let reestablish_2 = get_chan_reestablish_msgs!(nodes[1], nodes[0]); assert_eq!(reestablish_2.len(), 3); @@ -7573,8 +7573,8 @@ fn test_priv_forwarding_rejection() { check_added_monitors!(nodes[1], 2); nodes[1].node = &nodes_1_deserialized; - nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known() }); - nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }); + nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let as_reestablish = get_event_msg!(nodes[0], MessageSendEvent::SendChannelReestablish, nodes[1].node.get_our_node_id()); let bs_reestablish = get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[0].node.get_our_node_id()); nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &as_reestablish); @@ -7582,8 +7582,8 @@ fn test_priv_forwarding_rejection() { get_event_msg!(nodes[0], MessageSendEvent::SendChannelUpdate, nodes[1].node.get_our_node_id()); get_event_msg!(nodes[1], MessageSendEvent::SendChannelUpdate, nodes[0].node.get_our_node_id()); - nodes[1].node.peer_connected(&nodes[2].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known() }); - nodes[2].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[1].node.peer_connected(&nodes[2].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }); + nodes[2].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let bs_reestablish = get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[2].node.get_our_node_id()); let cs_reestablish = get_event_msg!(nodes[2], MessageSendEvent::SendChannelReestablish, nodes[1].node.get_our_node_id()); nodes[2].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &bs_reestablish); @@ -9273,8 +9273,8 @@ fn test_keysend_payments_to_private_node() { let payer_pubkey = nodes[0].node.get_our_node_id(); let payee_pubkey = nodes[1].node.get_our_node_id(); - nodes[0].node.peer_connected(&payee_pubkey, &msgs::Init { features: InitFeatures::known() }); - nodes[1].node.peer_connected(&payer_pubkey, &msgs::Init { features: InitFeatures::known() }); + nodes[0].node.peer_connected(&payee_pubkey, &msgs::Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }); + nodes[1].node.peer_connected(&payer_pubkey, &msgs::Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }); let _chan = create_chan_between_nodes(&nodes[0], &nodes[1], InitFeatures::known(), InitFeatures::known()); let params = RouteParameters { diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index 87944ccae63..4eb6c5074f1 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -40,7 +40,7 @@ use io_extras::read_to_end; use util::events::MessageSendEventsProvider; use util::logger; -use util::ser::{Readable, Writeable, Writer, FixedLengthReader, HighZeroBytesDroppedVarInt}; +use util::ser::{Readable, Writeable, Writer, FixedLengthReader, HighZeroBytesDroppedVarInt, IterWriteWrapper}; use ln::{PaymentPreimage, PaymentHash, PaymentSecret}; @@ -75,6 +75,9 @@ pub enum DecodeError { pub struct Init { /// The relevant features which the sender supports pub features: InitFeatures, + /// The set of encoding types which our peer supports for gossip messages, excluding those we + /// do not understand. + pub gossip_compression_encodings: Vec, } /// An error message to be sent or received from a peer @@ -696,10 +699,22 @@ pub struct GossipTimestampFilter { } /// Encoding type for data compression of collections in gossip queries. -/// We do not support encoding_type=1 zlib serialization defined in BOLT #7. -enum EncodingType { +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum GossipEncodingType { + // Note that the enum variants here are defined to the values as used in message encodings. + // Because they currently match the bit indexes for the gossip encodings field in Init they are + // re-used there. If future encodings have different bit positions from encoding fields, code + // in Init (de-)serialization will need to adapt. + /// Uncompressed gossip query messages sent as-is on the wire Uncompressed = 0x00, + /// Gossip messages compressed with the zlib compression algorithm. + /// For security reasons, we do not implement this or recommend anyone implement this. + Zlib = 0x01, } +const KNOWN_ENCODINGS: [GossipEncodingType; 2] = [GossipEncodingType::Uncompressed, GossipEncodingType::Zlib]; +/// The gossip encodings which we support here. Note that due to security concerns we do not +/// support reading zlib-compressed gossip messages. +pub const SUPPORTED_GOSSIP_ENCODINGS: [GossipEncodingType; 1] = [GossipEncodingType::Uncompressed]; /// Used to put an error message in a LightningError #[derive(Clone, Debug)] @@ -1132,7 +1147,22 @@ impl Writeable for Init { // global_features gets the bottom 13 bits of our features, and local_features gets all of // our relevant feature bits. This keeps us compatible with old nodes. self.features.write_up_to_13(w)?; - self.features.write(w) + self.features.write(w)?; + let mut highest_gossip_encoding = 0; + for enc in self.gossip_compression_encodings.iter() { + highest_gossip_encoding = cmp::max(1 << (*enc as u8), highest_gossip_encoding); + } + let mut gossip_compression_bits = Vec::new(); + gossip_compression_bits.resize(((highest_gossip_encoding + 7) / 8) as usize, 0); + for enc in self.gossip_compression_encodings.iter() { + let val = 1u32 << (*enc as u8); + gossip_compression_bits[(val / 8) as usize] |= (val % 8) as u8; + } + encode_tlv_stream!(w, { + // 1 - networks field to list genesis block hashes + (3, IterWriteWrapper(gossip_compression_bits.iter()), required) + }); + Ok(()) } } @@ -1140,8 +1170,23 @@ impl Readable for Init { fn read(r: &mut R) -> Result { let global_features: InitFeatures = Readable::read(r)?; let features: InitFeatures = Readable::read(r)?; + let mut gossip_compression_bits = Some(Vec::::new()); + decode_tlv_stream!(r, { + // 1 - networks field to list genesis block hashes + (3, gossip_compression_bits, vec_type), + }); + let gossip_compression_bits = gossip_compression_bits.unwrap(); + let mut gossip_compression_encodings = Vec::new(); + for encoding in &KNOWN_ENCODINGS { + let enc_val = 1u32 << (*encoding as u8); + if gossip_compression_bits.len() <= (enc_val / 8) as usize { continue; } + if gossip_compression_bits[(enc_val / 8) as usize] & (enc_val % 8) as u8 != 0 { + gossip_compression_encodings.push(*encoding); + } + } Ok(Init { features: features.or(global_features), + gossip_compression_encodings, }) } } @@ -1617,7 +1662,7 @@ impl Readable for QueryShortChannelIds { // Must be encoding_type=0 uncompressed serialization. We do not // support encoding_type=1 zlib serialization. - if encoding_type != EncodingType::Uncompressed as u8 { + if encoding_type != GossipEncodingType::Uncompressed as u8 { return Err(DecodeError::UnsupportedCompression); } @@ -1651,7 +1696,7 @@ impl Writeable for QueryShortChannelIds { encoding_len.write(w)?; // We only support type=0 uncompressed serialization - (EncodingType::Uncompressed as u8).write(w)?; + (GossipEncodingType::Uncompressed as u8).write(w)?; for scid in self.short_channel_ids.iter() { scid.write(w)?; @@ -1697,7 +1742,7 @@ impl Readable for ReplyChannelRange { // Must be encoding_type=0 uncompressed serialization. We do not // support encoding_type=1 zlib serialization. - if encoding_type != EncodingType::Uncompressed as u8 { + if encoding_type != GossipEncodingType::Uncompressed as u8 { return Err(DecodeError::UnsupportedCompression); } @@ -1734,7 +1779,7 @@ impl Writeable for ReplyChannelRange { self.sync_complete.write(w)?; encoding_len.write(w)?; - (EncodingType::Uncompressed as u8).write(w)?; + (GossipEncodingType::Uncompressed as u8).write(w)?; for scid in self.short_channel_ids.iter() { scid.write(w)?; } @@ -1755,7 +1800,7 @@ mod tests { use ln::{PaymentPreimage, PaymentHash, PaymentSecret}; use ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures}; use ln::msgs; - use ln::msgs::{FinalOnionHopData, OptionalField, OnionErrorPacket, OnionHopDataFormat}; + use ln::msgs::{FinalOnionHopData, OptionalField, OnionErrorPacket, OnionHopDataFormat, GossipEncodingType}; use util::ser::{Writeable, Readable}; use bitcoin::hashes::hex::FromHex; @@ -2390,13 +2435,24 @@ mod tests { fn encoding_init() { assert_eq!(msgs::Init { features: InitFeatures::from_le_bytes(vec![0xFF, 0xFF, 0xFF]), - }.encode(), hex::decode("00023fff0003ffffff").unwrap()); + gossip_compression_encodings: Vec::new(), + }.encode(), hex::decode("00023fff0003ffffff0300").unwrap()); assert_eq!(msgs::Init { features: InitFeatures::from_le_bytes(vec![0xFF]), - }.encode(), hex::decode("0001ff0001ff").unwrap()); + gossip_compression_encodings: Vec::new(), + }.encode(), hex::decode("0001ff0001ff0300").unwrap()); + assert_eq!(msgs::Init { + features: InitFeatures::from_le_bytes(vec![]), + gossip_compression_encodings: Vec::new(), + }.encode(), hex::decode("000000000300").unwrap()); + assert_eq!(msgs::Init { + features: InitFeatures::from_le_bytes(vec![]), + gossip_compression_encodings: vec![GossipEncodingType::Uncompressed], + }.encode(), hex::decode("00000000030101").unwrap()); assert_eq!(msgs::Init { features: InitFeatures::from_le_bytes(vec![]), - }.encode(), hex::decode("00000000").unwrap()); + gossip_compression_encodings: vec![GossipEncodingType::Uncompressed, GossipEncodingType::Zlib], + }.encode(), hex::decode("00000000030103").unwrap()); } #[test] diff --git a/lightning/src/ln/payment_tests.rs b/lightning/src/ln/payment_tests.rs index 7c9ff3199d1..b6f908ff895 100644 --- a/lightning/src/ln/payment_tests.rs +++ b/lightning/src/ln/payment_tests.rs @@ -377,12 +377,12 @@ fn do_retry_with_no_persist(confirm_before_reload: bool) { assert_eq!(as_broadcasted_txn[0], as_commitment_tx); nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false); - nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known()}); + nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }); assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty()); // Now nodes[1] should send a channel reestablish, which nodes[0] will respond to with an // error, as the channel has hit the chain. - nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known()}); + nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }); let bs_reestablish = get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[0].node.get_our_node_id()); nodes[0].node.handle_channel_reestablish(&nodes[1].node.get_our_node_id(), &bs_reestablish); let as_err = nodes[0].node.get_and_clear_pending_msg_events(); diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index 89f3e9ff5ff..d43059d1c30 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -19,7 +19,7 @@ use bitcoin::secp256k1::key::{SecretKey,PublicKey}; use ln::features::InitFeatures; use ln::msgs; -use ln::msgs::{ChannelMessageHandler, LightningError, RoutingMessageHandler}; +use ln::msgs::{ChannelMessageHandler, LightningError, RoutingMessageHandler, SUPPORTED_GOSSIP_ENCODINGS}; use ln::channelmanager::{SimpleArcChannelManager, SimpleRefChannelManager}; use util::ser::{VecWriter, Writeable, Writer}; use ln::peer_channel_encryptor::{PeerChannelEncryptor,NextNoiseStep}; @@ -858,7 +858,7 @@ impl P peer.their_node_id = Some(their_node_id); insert_node_id!(); let features = InitFeatures::known(); - let resp = msgs::Init { features }; + let resp = msgs::Init { features, gossip_compression_encodings: SUPPORTED_GOSSIP_ENCODINGS.iter().map(|e| *e).collect() }; self.enqueue_message(peer, &resp); peer.awaiting_pong_timer_tick_intervals = 0; }, @@ -869,7 +869,7 @@ impl P peer.their_node_id = Some(their_node_id); insert_node_id!(); let features = InitFeatures::known(); - let resp = msgs::Init { features }; + let resp = msgs::Init { features, gossip_compression_encodings: SUPPORTED_GOSSIP_ENCODINGS.iter().map(|e| *e).collect() }; self.enqueue_message(peer, &resp); peer.awaiting_pong_timer_tick_intervals = 0; }, diff --git a/lightning/src/ln/shutdown_tests.rs b/lightning/src/ln/shutdown_tests.rs index db76a2c760c..0f8b5a5caef 100644 --- a/lightning/src/ln/shutdown_tests.rs +++ b/lightning/src/ln/shutdown_tests.rs @@ -247,9 +247,9 @@ fn do_test_shutdown_rebroadcast(recv_count: u8) { nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false); nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false); - nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let node_0_reestablish = get_event_msg!(nodes[0], MessageSendEvent::SendChannelReestablish, nodes[1].node.get_our_node_id()); - nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let node_1_reestablish = get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[0].node.get_our_node_id()); nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &node_0_reestablish); @@ -307,9 +307,9 @@ fn do_test_shutdown_rebroadcast(recv_count: u8) { nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false); nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false); - nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); let node_1_2nd_reestablish = get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[0].node.get_our_node_id()); - nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty() }); + nodes[0].node.peer_connected(&nodes[1].node.get_our_node_id(), &msgs::Init { features: InitFeatures::empty(), gossip_compression_encodings: Vec::new() }); if recv_count == 0 { // If all closing_signeds weren't delivered we can just resume where we left off... let node_0_2nd_reestablish = get_event_msg!(nodes[0], MessageSendEvent::SendChannelReestablish, nodes[1].node.get_our_node_id()); diff --git a/lightning/src/ln/wire.rs b/lightning/src/ln/wire.rs index d3cc257f5a6..83369ed95b3 100644 --- a/lightning/src/ln/wire.rs +++ b/lightning/src/ln/wire.rs @@ -491,7 +491,8 @@ mod tests { let mut reader = io::Cursor::new(buffer); let decoded_msg = read(&mut reader, &IgnoringMessageHandler{}).unwrap(); match decoded_msg { - Message::Init(msgs::Init { features }) => { + Message::Init(msgs::Init { features, gossip_compression_encodings }) => { + assert!(gossip_compression_encodings.is_empty()); assert!(features.supports_variable_length_onion()); assert!(features.supports_upfront_shutdown_script()); assert!(features.supports_gossip_queries()); diff --git a/lightning/src/routing/network_graph.rs b/lightning/src/routing/network_graph.rs index 4d33bbdee92..0195b05157a 100644 --- a/lightning/src/routing/network_graph.rs +++ b/lightning/src/routing/network_graph.rs @@ -25,7 +25,7 @@ use chain; use chain::Access; use ln::features::{ChannelFeatures, NodeFeatures}; use ln::msgs::{DecodeError, ErrorAction, Init, LightningError, RoutingMessageHandler, NetAddress, MAX_VALUE_MSAT}; -use ln::msgs::{ChannelAnnouncement, ChannelUpdate, NodeAnnouncement, OptionalField}; +use ln::msgs::{ChannelAnnouncement, ChannelUpdate, NodeAnnouncement, OptionalField, SUPPORTED_GOSSIP_ENCODINGS}; use ln::msgs::{QueryChannelRange, ReplyChannelRange, QueryShortChannelIds, ReplyShortChannelIdsEnd}; use ln::msgs; use util::ser::{Writeable, Readable, Writer}; @@ -370,12 +370,18 @@ where C::Target: chain::Access, L::Target: Logger /// when the final reply_scids_end message is received, though we are not /// tracking this directly. fn sync_routing_table(&self, their_node_id: &PublicKey, init_msg: &Init) { - // We will only perform a sync with peers that support gossip_queries. if !init_msg.features.supports_gossip_queries() { return (); } + // We will only perform a sync with peers that support our encodings (if they specify their + // encodings) + if !init_msg.gossip_compression_encodings.is_empty() && + !init_msg.gossip_compression_encodings.iter().any(|e| SUPPORTED_GOSSIP_ENCODINGS.contains(e)) { + return (); + } + // Check if we need to perform a full synchronization with this peer if !self.should_request_full_sync(&their_node_id) { return (); @@ -1230,7 +1236,8 @@ mod tests { use routing::network_graph::{NetGraphMsgHandler, NetworkGraph, NetworkUpdate, MAX_EXCESS_BYTES_FOR_RELAY}; use ln::msgs::{Init, OptionalField, RoutingMessageHandler, UnsignedNodeAnnouncement, NodeAnnouncement, UnsignedChannelAnnouncement, ChannelAnnouncement, UnsignedChannelUpdate, ChannelUpdate, - ReplyChannelRange, ReplyShortChannelIdsEnd, QueryChannelRange, QueryShortChannelIds, MAX_VALUE_MSAT}; + ReplyChannelRange, ReplyShortChannelIdsEnd, QueryChannelRange, QueryShortChannelIds, MAX_VALUE_MSAT, + SUPPORTED_GOSSIP_ENCODINGS, GossipEncodingType}; use util::test_utils; use util::logger::Logger; use util::ser::{Readable, Writeable}; @@ -2215,7 +2222,15 @@ mod tests { // It should ignore if gossip_queries feature is not enabled { - let init_msg = Init { features: InitFeatures::known().clear_gossip_queries() }; + let init_msg = Init { features: InitFeatures::known().clear_gossip_queries(), gossip_compression_encodings: SUPPORTED_GOSSIP_ENCODINGS.iter().map(|e| *e).collect() }; + net_graph_msg_handler.sync_routing_table(&node_id_1, &init_msg); + let events = net_graph_msg_handler.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 0); + } + + // It should ignore if available encodings do not match ours + { + let init_msg = Init { features: InitFeatures::known().clear_gossip_queries(), gossip_compression_encodings: vec![GossipEncodingType::Zlib] }; net_graph_msg_handler.sync_routing_table(&node_id_1, &init_msg); let events = net_graph_msg_handler.get_and_clear_pending_msg_events(); assert_eq!(events.len(), 0); @@ -2223,7 +2238,25 @@ mod tests { // It should send a query_channel_message with the correct information { - let init_msg = Init { features: InitFeatures::known() }; + let init_msg = Init { features: InitFeatures::known(), gossip_compression_encodings: SUPPORTED_GOSSIP_ENCODINGS.iter().map(|e| *e).collect() }; + net_graph_msg_handler.sync_routing_table(&node_id_1, &init_msg); + let events = net_graph_msg_handler.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 1); + match &events[0] { + MessageSendEvent::SendChannelRangeQuery{ node_id, msg } => { + assert_eq!(node_id, &node_id_1); + assert_eq!(msg.chain_hash, chain_hash); + assert_eq!(msg.first_blocknum, first_blocknum); + assert_eq!(msg.number_of_blocks, number_of_blocks); + }, + _ => panic!("Expected MessageSendEvent::SendChannelRangeQuery") + }; + } + + // It should send a query_channel_message with the correct information if the peer was old + // and didn't send its supported encodings + { + let init_msg = Init { features: InitFeatures::known(), gossip_compression_encodings: Vec::new() }; net_graph_msg_handler.sync_routing_table(&node_id_1, &init_msg); let events = net_graph_msg_handler.get_and_clear_pending_msg_events(); assert_eq!(events.len(), 1); @@ -2244,7 +2277,7 @@ mod tests { { let network_graph = create_network_graph(); let (secp_ctx, net_graph_msg_handler) = create_net_graph_msg_handler(&network_graph); - let init_msg = Init { features: InitFeatures::known() }; + let init_msg = Init { features: InitFeatures::known(), gossip_compression_encodings: SUPPORTED_GOSSIP_ENCODINGS.iter().map(|e| *e).collect() }; for n in 1..7 { let node_privkey = &SecretKey::from_slice(&[n; 32]).unwrap(); let node_id = PublicKey::from_secret_key(&secp_ctx, node_privkey); diff --git a/lightning/src/util/events.rs b/lightning/src/util/events.rs index e90f443b0c2..f26b7058974 100644 --- a/lightning/src/util/events.rs +++ b/lightning/src/util/events.rs @@ -21,7 +21,7 @@ use ln::msgs; use ln::msgs::DecodeError; use ln::{PaymentPreimage, PaymentHash, PaymentSecret}; use routing::network_graph::NetworkUpdate; -use util::ser::{BigSize, FixedLengthReader, Writeable, Writer, MaybeReadable, Readable, VecReadWrapper, VecWriteWrapper}; +use util::ser::{BigSize, FixedLengthReader, Writeable, Writer, MaybeReadable, Readable, VecReadWrapper, IterWriteWrapper}; use routing::router::{RouteHop, RouteParameters}; use bitcoin::Transaction; @@ -424,7 +424,7 @@ impl Writeable for Event { &Event::SpendableOutputs { ref outputs } => { 5u8.write(writer)?; write_tlv_fields!(writer, { - (0, VecWriteWrapper(outputs), required), + (0, IterWriteWrapper(outputs.iter()), required), }); }, &Event::PaymentForwarded { fee_earned_msat, claim_from_onchain_tx } => { diff --git a/lightning/src/util/ser.rs b/lightning/src/util/ser.rs index 8fb72a8f9fe..cb883d8b2e8 100644 --- a/lightning/src/util/ser.rs +++ b/lightning/src/util/ser.rs @@ -244,12 +244,12 @@ impl Readable for OptionDeserWrapper { } } -/// Wrapper to write each element of a Vec with no length prefix -pub(crate) struct VecWriteWrapper<'a, T: Writeable>(pub &'a Vec); -impl<'a, T: Writeable> Writeable for VecWriteWrapper<'a, T> { +/// Wrapper to write each element of an iterator with no length prefix +pub(crate) struct IterWriteWrapper(pub I) where I::Item: Writeable; +impl Writeable for IterWriteWrapper where I::Item: Writeable { #[inline] fn write(&self, writer: &mut W) -> Result<(), io::Error> { - for ref v in self.0.iter() { + for v in self.0.clone() { v.write(writer)?; } Ok(()) diff --git a/lightning/src/util/ser_macros.rs b/lightning/src/util/ser_macros.rs index 165d1f1edba..43bbe3d68c4 100644 --- a/lightning/src/util/ser_macros.rs +++ b/lightning/src/util/ser_macros.rs @@ -17,7 +17,7 @@ macro_rules! encode_tlv { $field.write($stream)?; }; ($stream: expr, $type: expr, $field: expr, vec_type) => { - encode_tlv!($stream, $type, ::util::ser::VecWriteWrapper(&$field), required); + encode_tlv!($stream, $type, ::util::ser::IterWriteWrapper($field.iter()), required); }; ($stream: expr, $optional_type: expr, $optional_field: expr, option) => { if let Some(ref field) = $optional_field { @@ -66,7 +66,7 @@ macro_rules! get_varint_length_prefixed_tlv_length { $len.0 += field_len; }; ($len: expr, $type: expr, $field: expr, vec_type) => { - get_varint_length_prefixed_tlv_length!($len, $type, ::util::ser::VecWriteWrapper(&$field), required); + get_varint_length_prefixed_tlv_length!($len, $type, ::util::ser::IterWriteWrapper($field.iter()), required); }; ($len: expr, $optional_type: expr, $optional_field: expr, option) => { if let Some(ref field) = $optional_field {