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 {
/// confirmations on the claim transaction.
///
/// Note that for `ChannelMonitors` which track a channel which went on-chain with versions of
- /// LDK prior to 0.0.108, balances may not be fully captured if our counterparty broadcasted
+ /// LDK prior to 0.0.111, balances may not be fully captured if our counterparty broadcasted
/// a revoked state.
///
/// See [`Balance`] for additional details on the types of claimable balances which
}
/// An error when accessing the chain via [`Access`].
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub enum AccessError {
/// The requested chain is unknown.
UnknownChain,
}
fn check_get_channel_ready(&mut self, height: u32) -> Option<msgs::ChannelReady> {
+ // Called:
+ // * always when a new block/transactions are confirmed with the new height
+ // * when funding is signed with a height of 0
if self.funding_tx_confirmation_height == 0 && self.minimum_depth != Some(0) {
return None;
}
// We got a reorg but not enough to trigger a force close, just ignore.
false
} else {
- if self.channel_state < ChannelState::ChannelFunded as u32 {
+ if self.funding_tx_confirmation_height != 0 && self.channel_state < ChannelState::ChannelFunded as u32 {
// We should never see a funding transaction on-chain until we've received
// funding_signed (if we're an outbound channel), or seen funding_generated (if we're
// an inbound channel - before that we have no known funding TXID). The fuzzer,
}
fn provided_node_features(&self) -> NodeFeatures {
- NodeFeatures::known()
+ NodeFeatures::known_channel_features()
}
fn provided_init_features(&self, _their_init_features: &PublicKey) -> InitFeatures {
//! (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.
+//! (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
],
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
// Byte 3
ShutdownAnySegwit,
// Byte 4
- ,
+ OnionMessages,
// Byte 5
ChannelType | SCIDPrivacy,
// Byte 6
// Byte 3
ShutdownAnySegwit,
// Byte 4
- ,
+ OnionMessages,
// Byte 5
ChannelType | SCIDPrivacy,
// Byte 6
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);
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 {
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> {
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()
}
}
}
}
+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 {
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());
// - 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[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);
assert_eq!(node_features.flags[5], 0b10100000);
assert_eq!(node_features.flags[6], 0b00001000);
}
// 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
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.
/// 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 {
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()
}
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;
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;
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;
// 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,
_ => panic!(),
}
}
+
+#[test]
+fn test_connect_before_funding() {
+ // Tests for a particularly dumb explicit panic that existed prior to 0.0.111 for 0conf
+ // channels. If we received a block while awaiting funding for 0-conf channels we'd hit an
+ // explicit panic when deciding if we should broadcast our channel_ready message.
+ let chanmon_cfgs = create_chanmon_cfgs(2);
+ let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
+
+ let mut manually_accept_conf = test_default_channel_config();
+ manually_accept_conf.manually_accept_inbound_channels = true;
+
+ let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(manually_accept_conf)]);
+ let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+
+ nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 10_001, 42, None).unwrap();
+ let open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
+
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_channel);
+ let events = nodes[1].node.get_and_clear_pending_events();
+ assert_eq!(events.len(), 1);
+ match events[0] {
+ Event::OpenChannelRequest { temporary_channel_id, .. } => {
+ nodes[1].node.accept_inbound_channel_from_trusted_peer_0conf(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 0).unwrap();
+ },
+ _ => panic!("Unexpected event"),
+ };
+
+ let mut accept_channel = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
+ assert_eq!(accept_channel.minimum_depth, 0);
+ nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &accept_channel);
+
+ let events = nodes[0].node.get_and_clear_pending_events();
+ assert_eq!(events.len(), 1);
+ match events[0] {
+ Event::FundingGenerationReady { .. } => {},
+ _ => panic!("Unexpected event"),
+ }
+
+ connect_blocks(&nodes[0], 1);
+ connect_blocks(&nodes[1], 1);
+}
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};
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>
})
}
+ 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();
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()
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();