Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Onion messages: flip feature bit 🎉 #1688

Merged
1 change: 1 addition & 0 deletions lightning-net-tokio/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,7 @@ mod tests {
fn handle_reply_short_channel_ids_end(&self, _their_node_id: &PublicKey, _msg: ReplyShortChannelIdsEnd) -> Result<(), LightningError> { Ok(()) }
fn handle_query_channel_range(&self, _their_node_id: &PublicKey, _msg: QueryChannelRange) -> Result<(), LightningError> { Ok(()) }
fn handle_query_short_channel_ids(&self, _their_node_id: &PublicKey, _msg: QueryShortChannelIds) -> Result<(), LightningError> { Ok(()) }
fn provided_node_features(&self) -> NodeFeatures { NodeFeatures::known() }
fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures { InitFeatures::known() }
}
impl ChannelMessageHandler for MsgHandler {
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6122,7 +6122,7 @@ impl<Signer: Sign, M: Deref , T: Deref , K: Deref , F: Deref , L: Deref >
}

fn provided_node_features(&self) -> NodeFeatures {
NodeFeatures::known()
NodeFeatures::known_channel_features()
}

fn provided_init_features(&self, _their_init_features: &PublicKey) -> InitFeatures {
Expand Down
61 changes: 44 additions & 17 deletions lightning/src/ln/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,13 @@
//! (see [BOLT-4](https://github.com/lightning/bolts/blob/master/04-onion-routing.md) for more information).
//! - `BasicMPP` - requires/supports that a node can receive basic multi-part payments
//! (see [BOLT-4](https://github.com/lightning/bolts/blob/master/04-onion-routing.md#basic-multi-part-payments) for more information).
//! - `Wumbo` - requires/supports that a node create large channels. Called `option_support_large_channel` in the spec.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could say "large channels (superior to MAX_FUNDING_SATOSHIS_NO_WUMBO)"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that const isn't public

//! (see [BOLT-2](https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#the-open_channel-message) for more information).
//! - `ShutdownAnySegwit` - requires/supports that future segwit versions are allowed in `shutdown`
//! (see [BOLT-2](https://github.com/lightning/bolts/blob/master/02-peer-protocol.md) for more information).
//! - `OnionMessages` - requires/supports forwarding onion messages
//! (see [BOLT-7](https://github.com/lightning/bolts/pull/759/files) for more information).
//! TODO: update link
//! - `ChannelType` - node supports the channel_type field in open/accept
//! (see [BOLT-2](https://github.com/lightning/bolts/blob/master/02-peer-protocol.md) for more information).
//! - `SCIDPrivacy` - supply channel aliases for routing
Expand Down Expand Up @@ -164,7 +169,8 @@ mod sealed {
],
optional_features: [
// Note that if new "non-channel-related" flags are added here they should be
// explicitly cleared in InitFeatures::known_channel_features.
// explicitly cleared in InitFeatures::known_channel_features and
// NodeFeatures::known_channel_features.
// Byte 0
DataLossProtect | InitialRoutingSync | UpfrontShutdownScript | GossipQueries,
// Byte 1
Expand All @@ -174,7 +180,7 @@ mod sealed {
// Byte 3
ShutdownAnySegwit,
// Byte 4
,
OnionMessages,
// Byte 5
ChannelType | SCIDPrivacy,
// Byte 6
Expand Down Expand Up @@ -208,7 +214,7 @@ mod sealed {
// Byte 3
ShutdownAnySegwit,
// Byte 4
,
OnionMessages,
// Byte 5
ChannelType | SCIDPrivacy,
// Byte 6
Expand Down Expand Up @@ -435,8 +441,6 @@ mod sealed {
define_feature!(27, ShutdownAnySegwit, [InitContext, NodeContext],
"Feature flags for `opt_shutdown_anysegwit`.", set_shutdown_any_segwit_optional,
set_shutdown_any_segwit_required, supports_shutdown_anysegwit, requires_shutdown_anysegwit);
// We do not yet advertise the onion messages feature bit, but we need to detect when peers
// support it.
define_feature!(39, OnionMessages, [InitContext, NodeContext],
"Feature flags for `option_onion_messages`.", set_onion_messages_optional,
set_onion_messages_required, supports_onion_messages, requires_onion_messages);
Expand Down Expand Up @@ -470,6 +474,17 @@ pub struct Features<T: sealed::Context> {
mark: PhantomData<T>,
}

impl <T: sealed::Context> Features<T> {
pub(crate) fn or(mut self, o: Self) -> Self {
let total_feature_len = cmp::max(self.flags.len(), o.flags.len());
self.flags.resize(total_feature_len, 0u8);
for (byte, o_byte) in self.flags.iter_mut().zip(o.flags.iter()) {
*byte |= *o_byte;
}
self
}
}

impl<T: sealed::Context> Clone for Features<T> {
fn clone(&self) -> Self {
Self {
Expand Down Expand Up @@ -532,16 +547,6 @@ impl InitFeatures {
Ok(())
}

/// or's another InitFeatures into this one.
pub(crate) fn or(mut self, o: InitFeatures) -> InitFeatures {
let total_feature_len = cmp::max(self.flags.len(), o.flags.len());
self.flags.resize(total_feature_len, 0u8);
for (byte, o_byte) in self.flags.iter_mut().zip(o.flags.iter()) {
*byte |= *o_byte;
}
self
}

/// Converts `InitFeatures` to `Features<C>`. Only known `InitFeatures` relevant to context `C`
/// are included in the result.
pub(crate) fn to_context<C: sealed::Context>(&self) -> Features<C> {
Expand All @@ -554,6 +559,16 @@ impl InitFeatures {
Self::known()
.clear_initial_routing_sync()
.clear_gossip_queries()
.clear_onion_messages()
}
}

impl NodeFeatures {
/// Returns the set of known node features that are related to channels.
pub fn known_channel_features() -> NodeFeatures {
Self::known()
.clear_gossip_queries()
.clear_onion_messages()
}
}

Expand Down Expand Up @@ -787,6 +802,13 @@ impl<T: sealed::InitialRoutingSync> Features<T> {
}
}

impl<T: sealed::OnionMessages> Features<T> {
pub(crate) fn clear_onion_messages(mut self) -> Self {
<T as sealed::OnionMessages>::clear_bits(&mut self.flags);
self
}
}

impl<T: sealed::ShutdownAnySegwit> Features<T> {
#[cfg(test)]
pub(crate) fn clear_shutdown_anysegwit(mut self) -> Self {
Expand Down Expand Up @@ -913,6 +935,11 @@ mod tests {
assert!(!InitFeatures::known().requires_wumbo());
assert!(!NodeFeatures::known().requires_wumbo());

assert!(InitFeatures::known().supports_onion_messages());
assert!(NodeFeatures::known().supports_onion_messages());
assert!(!InitFeatures::known().requires_onion_messages());
assert!(!NodeFeatures::known().requires_onion_messages());

assert!(InitFeatures::known().supports_zero_conf());
assert!(!InitFeatures::known().requires_zero_conf());
assert!(NodeFeatures::known().supports_zero_conf());
Expand Down Expand Up @@ -957,15 +984,15 @@ mod tests {
// - var_onion_optin (req) | static_remote_key (req) | payment_secret(req)
// - basic_mpp | wumbo
// - opt_shutdown_anysegwit
// -
// - onion_messages
// - option_channel_type | option_scid_alias
// - option_zeroconf
assert_eq!(node_features.flags.len(), 7);
assert_eq!(node_features.flags[0], 0b00000010);
assert_eq!(node_features.flags[1], 0b01010001);
assert_eq!(node_features.flags[2], 0b00001010);
assert_eq!(node_features.flags[3], 0b00001000);
assert_eq!(node_features.flags[4], 0b00000000);
assert_eq!(node_features.flags[4], 0b10000000);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I gotta spend some time figuring out how we handle feature bits internally lol

assert_eq!(node_features.flags[5], 0b10100000);
assert_eq!(node_features.flags[6], 0b00001000);
}
Expand Down
19 changes: 18 additions & 1 deletion lightning/src/ln/msgs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -900,7 +900,7 @@ pub trait ChannelMessageHandler : MessageSendEventsProvider {
// Handler information:
/// Gets the node feature flags which this handler itself supports. All available handlers are
/// queried similarly and their feature flags are OR'd together to form the [`NodeFeatures`]
/// which are broadcasted in our node_announcement message.
/// which are broadcasted in our [`NodeAnnouncement`] message.
fn provided_node_features(&self) -> NodeFeatures;

/// Gets the init feature flags which should be sent to the given peer. All available handlers
Expand Down Expand Up @@ -958,6 +958,10 @@ pub trait RoutingMessageHandler : MessageSendEventsProvider {
fn handle_query_short_channel_ids(&self, their_node_id: &PublicKey, msg: QueryShortChannelIds) -> Result<(), LightningError>;

// Handler information:
/// Gets the node feature flags which this handler itself supports. All available handlers are
/// queried similarly and their feature flags are OR'd together to form the [`NodeFeatures`]
/// which are broadcasted in our [`NodeAnnouncement`] message.
fn provided_node_features(&self) -> NodeFeatures;
/// Gets the init feature flags which should be sent to the given peer. All available handlers
/// are queried similarly and their feature flags are OR'd together to form the [`InitFeatures`]
/// which are sent in our [`Init`] message.
Expand All @@ -976,6 +980,19 @@ pub trait OnionMessageHandler : OnionMessageProvider {
/// Indicates a connection to the peer failed/an existing connection was lost. Allows handlers to
/// drop and refuse to forward onion messages to this peer.
fn peer_disconnected(&self, their_node_id: &PublicKey, no_connection_possible: bool);

// Handler information:
/// Gets the node feature flags which this handler itself supports. All available handlers are
/// queried similarly and their feature flags are OR'd together to form the [`NodeFeatures`]
/// which are broadcasted in our [`NodeAnnouncement`] message.
fn provided_node_features(&self) -> NodeFeatures;

/// Gets the init feature flags which should be sent to the given peer. All available handlers
/// are queried similarly and their feature flags are OR'd together to form the [`InitFeatures`]
/// which are sent in our [`Init`] message.
///
/// Note that this method is called before [`Self::peer_connected`].
fn provided_init_features(&self, their_node_id: &PublicKey) -> InitFeatures;
}

mod fuzzy_internal_msgs {
Expand Down
16 changes: 13 additions & 3 deletions lightning/src/ln/peer_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ impl RoutingMessageHandler for IgnoringMessageHandler {
fn handle_reply_short_channel_ids_end(&self, _their_node_id: &PublicKey, _msg: msgs::ReplyShortChannelIdsEnd) -> Result<(), LightningError> { Ok(()) }
fn handle_query_channel_range(&self, _their_node_id: &PublicKey, _msg: msgs::QueryChannelRange) -> Result<(), LightningError> { Ok(()) }
fn handle_query_short_channel_ids(&self, _their_node_id: &PublicKey, _msg: msgs::QueryShortChannelIds) -> Result<(), LightningError> { Ok(()) }
fn provided_node_features(&self) -> NodeFeatures { NodeFeatures::empty() }
fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures {
InitFeatures::empty()
}
Expand All @@ -88,6 +89,10 @@ impl OnionMessageHandler for IgnoringMessageHandler {
fn handle_onion_message(&self, _their_node_id: &PublicKey, _msg: &msgs::OnionMessage) {}
fn peer_connected(&self, _their_node_id: &PublicKey, _init: &msgs::Init) {}
fn peer_disconnected(&self, _their_node_id: &PublicKey, _no_connection_possible: bool) {}
fn provided_node_features(&self) -> NodeFeatures { NodeFeatures::empty() }
fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures {
InitFeatures::empty()
}
}
impl Deref for IgnoringMessageHandler {
type Target = IgnoringMessageHandler;
Expand Down Expand Up @@ -1061,7 +1066,8 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
peer.their_node_id = Some(their_node_id);
insert_node_id!();
let features = self.message_handler.chan_handler.provided_init_features(&their_node_id)
.or(self.message_handler.route_handler.provided_init_features(&their_node_id));
.or(self.message_handler.route_handler.provided_init_features(&their_node_id))
.or(self.message_handler.onion_message_handler.provided_init_features(&their_node_id));
let resp = msgs::Init { features, remote_network_address: filter_addresses(peer.their_net_address.clone()) };
self.enqueue_message(peer, &resp);
peer.awaiting_pong_timer_tick_intervals = 0;
Expand All @@ -1074,7 +1080,8 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
peer.their_node_id = Some(their_node_id);
insert_node_id!();
let features = self.message_handler.chan_handler.provided_init_features(&their_node_id)
.or(self.message_handler.route_handler.provided_init_features(&their_node_id));
.or(self.message_handler.route_handler.provided_init_features(&their_node_id))
.or(self.message_handler.onion_message_handler.provided_init_features(&their_node_id));
let resp = msgs::Init { features, remote_network_address: filter_addresses(peer.their_net_address.clone()) };
self.enqueue_message(peer, &resp);
peer.awaiting_pong_timer_tick_intervals = 0;
Expand Down Expand Up @@ -1969,8 +1976,11 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
// addresses be sorted for future compatibility.
addresses.sort_by_key(|addr| addr.get_id());

let features = self.message_handler.chan_handler.provided_node_features()
.or(self.message_handler.route_handler.provided_node_features())
.or(self.message_handler.onion_message_handler.provided_node_features());
let announcement = msgs::UnsignedNodeAnnouncement {
features: self.message_handler.chan_handler.provided_node_features(),
features,
timestamp: self.last_node_announcement_serial.fetch_add(1, Ordering::AcqRel) as u32,
node_id: PublicKey::from_secret_key(&self.secp_ctx, &self.our_node_secret),
rgb, alias, addresses,
Expand Down
13 changes: 13 additions & 0 deletions lightning/src/onion_message/messenger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use bitcoin::hashes::sha256::Hash as Sha256;
use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1, SecretKey};

use chain::keysinterface::{InMemorySigner, KeysInterface, KeysManager, Recipient, Sign};
use ln::features::{InitFeatures, NodeFeatures};
use ln::msgs::{self, OnionMessageHandler};
use ln::onion_utils;
use super::blinded_route::{BlindedRoute, ForwardTlvs, ReceiveTlvs};
Expand Down Expand Up @@ -345,6 +346,18 @@ impl<Signer: Sign, K: Deref, L: Deref> OnionMessageHandler for OnionMessenger<Si
let mut pending_msgs = self.pending_messages.lock().unwrap();
pending_msgs.remove(their_node_id);
}

fn provided_node_features(&self) -> NodeFeatures {
let mut features = NodeFeatures::empty();
features.set_onion_messages_optional();
features
}

fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures {
let mut features = InitFeatures::empty();
features.set_onion_messages_optional();
features
}
}

impl<Signer: Sign, K: Deref, L: Deref> OnionMessageProvider for OnionMessenger<Signer, K, L>
Expand Down
6 changes: 6 additions & 0 deletions lightning/src/routing/gossip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,12 @@ where C::Target: chain::Access, L::Target: Logger
})
}

fn provided_node_features(&self) -> NodeFeatures {
let mut features = NodeFeatures::empty();
features.set_gossip_queries_optional();
features
}

fn provided_init_features(&self, _their_node_id: &PublicKey) -> InitFeatures {
let mut features = InitFeatures::empty();
features.set_gossip_queries_optional();
Expand Down
8 changes: 7 additions & 1 deletion lightning/src/util/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ impl msgs::ChannelMessageHandler for TestChannelMessageHandler {
self.received_msg(wire::Message::Error(msg.clone()));
}
fn provided_node_features(&self) -> NodeFeatures {
NodeFeatures::empty()
NodeFeatures::known_channel_features()
}
fn provided_init_features(&self, _their_init_features: &PublicKey) -> InitFeatures {
InitFeatures::known_channel_features()
Expand Down Expand Up @@ -511,6 +511,12 @@ impl msgs::RoutingMessageHandler for TestRoutingMessageHandler {
Ok(())
}

fn provided_node_features(&self) -> NodeFeatures {
let mut features = NodeFeatures::empty();
features.set_gossip_queries_optional();
features
}

fn provided_init_features(&self, _their_init_features: &PublicKey) -> InitFeatures {
let mut features = InitFeatures::empty();
features.set_gossip_queries_optional();
Expand Down