use bitcoin::hashes::Hash;
use bitcoin::hash_types::BlockHash;
+use bitcoin::network::constants::Network;
+use bitcoin::blockdata::constants::genesis_block;
+
use crate::ln::features::{ChannelFeatures, NodeFeatures, InitFeatures};
use crate::ln::msgs::{DecodeError, ErrorAction, Init, LightningError, RoutingMessageHandler, NetAddress, MAX_VALUE_MSAT};
use crate::ln::msgs::{ChannelAnnouncement, ChannelUpdate, NodeAnnouncement, GossipTimestampFilter};
false
}
}
+
+ /// Used to broadcast forward gossip messages which were validated async.
+ ///
+ /// Note that this will ignore events other than `Broadcast*` or messages with too much excess
+ /// data.
+ pub(super) fn forward_gossip_msg(&self, mut ev: MessageSendEvent) {
+ match &mut ev {
+ MessageSendEvent::BroadcastChannelAnnouncement { msg, ref mut update_msg } => {
+ if msg.contents.excess_data.len() > MAX_EXCESS_BYTES_FOR_RELAY { return; }
+ if update_msg.as_ref()
+ .map(|msg| msg.contents.excess_data.len()).unwrap_or(0) > MAX_EXCESS_BYTES_FOR_RELAY
+ {
+ *update_msg = None;
+ }
+ },
+ MessageSendEvent::BroadcastChannelUpdate { msg } => {
+ if msg.contents.excess_data.len() > MAX_EXCESS_BYTES_FOR_RELAY { return; }
+ },
+ MessageSendEvent::BroadcastNodeAnnouncement { msg } => {
+ if msg.contents.excess_data.len() > MAX_EXCESS_BYTES_FOR_RELAY ||
+ msg.contents.excess_address_data.len() > MAX_EXCESS_BYTES_FOR_RELAY ||
+ msg.contents.excess_data.len() + msg.contents.excess_address_data.len() > MAX_EXCESS_BYTES_FOR_RELAY
+ {
+ return;
+ }
+ },
+ _ => return,
+ }
+ self.pending_events.lock().unwrap().push(ev);
+ }
}
impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
fn handle_channel_announcement(&self, msg: &msgs::ChannelAnnouncement) -> Result<bool, LightningError> {
self.network_graph.update_channel_from_announcement(msg, &self.utxo_lookup)?;
- log_gossip!(self.logger, "Added channel_announcement for {}{}", msg.contents.short_channel_id, if !msg.contents.excess_data.is_empty() { " with excess uninterpreted data!" } else { "" });
Ok(msg.contents.excess_data.len() <= MAX_EXCESS_BYTES_FOR_RELAY)
}
}
fn get_next_channel_announcement(&self, starting_point: u64) -> Option<(ChannelAnnouncement, Option<ChannelUpdate>, Option<ChannelUpdate>)> {
- let channels = self.network_graph.channels.read().unwrap();
+ let mut channels = self.network_graph.channels.write().unwrap();
for (_, ref chan) in channels.range(starting_point..) {
if chan.announcement_message.is_some() {
let chan_announcement = chan.announcement_message.clone().unwrap();
}
fn get_next_node_announcement(&self, starting_point: Option<&NodeId>) -> Option<NodeAnnouncement> {
- let nodes = self.network_graph.nodes.read().unwrap();
+ let mut nodes = self.network_graph.nodes.write().unwrap();
let iter = if let Some(node_id) = starting_point {
nodes.range((Bound::Excluded(node_id), Bound::Unbounded))
} else {
/// to request gossip messages for each channel. The sync is considered complete
/// when the final reply_scids_end message is received, though we are not
/// tracking this directly.
- fn peer_connected(&self, their_node_id: &PublicKey, init_msg: &Init) -> Result<(), ()> {
+ fn peer_connected(&self, their_node_id: &PublicKey, init_msg: &Init, _inbound: bool) -> Result<(), ()> {
// We will only perform a sync with peers that support gossip_queries.
if !init_msg.features.supports_gossip_queries() {
// Don't disconnect peers for not supporting gossip queries. We may wish to have
// (has at least one update). A peer may still want to know the channel
// exists even if its not yet routable.
let mut batches: Vec<Vec<u64>> = vec![Vec::with_capacity(MAX_SCIDS_PER_REPLY)];
- let channels = self.network_graph.channels.read().unwrap();
+ let mut channels = self.network_graph.channels.write().unwrap();
for (_, ref chan) in channels.range(inclusive_start_scid.unwrap()..exclusive_end_scid.unwrap()) {
if let Some(chan_announcement) = &chan.announcement_message {
// Construct a new batch if last one is full
features.set_gossip_queries_optional();
features
}
+
+ fn processing_queue_high(&self) -> bool {
+ self.network_graph.pending_checks.too_many_checks_pending()
+ }
}
impl<G: Deref<Target=NetworkGraph<L>>, U: Deref, L: Deref> MessageSendEventsProvider for P2PGossipSync<G, U, L>
(0, features, required),
(1, announcement_received_time, (default_value, 0)),
(2, node_one, required),
- (4, one_to_two_wrap, ignorable),
+ (4, one_to_two_wrap, upgradable_option),
(6, node_two, required),
- (8, two_to_one_wrap, ignorable),
+ (8, two_to_one_wrap, upgradable_option),
(10, capacity_sats, required),
(12, announcement_message, required),
});
///
/// While this may be smaller than the actual channel capacity, amounts greater than
/// [`Self::as_msat`] should not be routed through the channel.
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, PartialEq)]
pub enum EffectiveCapacity {
/// The available liquidity in the channel known from being a channel counterparty, and thus a
/// direct hop.
/// Fees for routing via a given channel or a node
#[derive(Eq, PartialEq, Copy, Clone, Debug, Hash)]
pub struct RoutingFees {
- /// Flat routing fee in satoshis
+ /// Flat routing fee in millisatoshis.
pub base_msat: u32,
/// Liquidity-based routing fee in millionths of a routed amount.
/// In other words, 10000 is 1%.
read_tlv_fields!(reader, {
(0, _lowest_inbound_channel_fees, option),
- (2, announcement_info_wrap, ignorable),
+ (2, announcement_info_wrap, upgradable_option),
(4, channels, vec_type),
});
impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
/// Creates a new, empty, network graph.
- pub fn new(genesis_hash: BlockHash, logger: L) -> NetworkGraph<L> {
+ pub fn new(network: Network, logger: L) -> NetworkGraph<L> {
Self {
secp_ctx: Secp256k1::verification_only(),
- genesis_hash,
+ genesis_hash: genesis_block(network).header.block_hash(),
logger,
channels: RwLock::new(IndexedMap::new()),
nodes: RwLock::new(IndexedMap::new()),
announcement_received_time,
};
- self.add_channel_between_nodes(msg.short_channel_id, chan_info, utxo_value)
+ self.add_channel_between_nodes(msg.short_channel_id, chan_info, utxo_value)?;
+
+ log_gossip!(self.logger, "Added channel_announcement for {}{}", msg.short_channel_id, if !msg.excess_data.is_empty() { " with excess uninterpreted data!" } else { "" });
+ Ok(())
}
/// Marks a channel in the graph as failed if a corresponding HTLC fail was sent.
}
#[cfg(test)]
-mod tests {
+pub(crate) mod tests {
use crate::ln::channelmanager;
use crate::ln::chan_utils::make_funding_redeemscript;
#[cfg(feature = "std")]
use crate::ln::features::InitFeatures;
use crate::routing::gossip::{P2PGossipSync, NetworkGraph, NetworkUpdate, NodeAlias, MAX_EXCESS_BYTES_FOR_RELAY, NodeId, RoutingFees, ChannelUpdateInfo, ChannelInfo, NodeAnnouncementInfo, NodeInfo};
- use crate::routing::utxo::UtxoLookupError;
+ use crate::routing::utxo::{UtxoLookupError, UtxoResult};
use crate::ln::msgs::{RoutingMessageHandler, UnsignedNodeAnnouncement, NodeAnnouncement,
UnsignedChannelAnnouncement, ChannelAnnouncement, UnsignedChannelUpdate, ChannelUpdate,
ReplyChannelRange, QueryChannelRange, QueryShortChannelIds, MAX_VALUE_MSAT};
use crate::sync::Arc;
fn create_network_graph() -> NetworkGraph<Arc<test_utils::TestLogger>> {
- let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
let logger = Arc::new(test_utils::TestLogger::new());
- NetworkGraph::new(genesis_hash, logger)
+ NetworkGraph::new(Network::Testnet, logger)
}
fn create_gossip_sync(network_graph: &NetworkGraph<Arc<test_utils::TestLogger>>) -> (
assert!(!gossip_sync.should_request_full_sync(&node_id));
}
- fn get_signed_node_announcement<F: Fn(&mut UnsignedNodeAnnouncement)>(f: F, node_key: &SecretKey, secp_ctx: &Secp256k1<secp256k1::All>) -> NodeAnnouncement {
+ pub(crate) fn get_signed_node_announcement<F: Fn(&mut UnsignedNodeAnnouncement)>(f: F, node_key: &SecretKey, secp_ctx: &Secp256k1<secp256k1::All>) -> NodeAnnouncement {
let node_id = NodeId::from_pubkey(&PublicKey::from_secret_key(&secp_ctx, node_key));
let mut unsigned_announcement = UnsignedNodeAnnouncement {
features: channelmanager::provided_node_features(&UserConfig::default()),
}
}
- fn get_signed_channel_announcement<F: Fn(&mut UnsignedChannelAnnouncement)>(f: F, node_1_key: &SecretKey, node_2_key: &SecretKey, secp_ctx: &Secp256k1<secp256k1::All>) -> ChannelAnnouncement {
+ pub(crate) fn get_signed_channel_announcement<F: Fn(&mut UnsignedChannelAnnouncement)>(f: F, node_1_key: &SecretKey, node_2_key: &SecretKey, secp_ctx: &Secp256k1<secp256k1::All>) -> ChannelAnnouncement {
let node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_1_key);
let node_id_2 = PublicKey::from_secret_key(&secp_ctx, node_2_key);
let node_1_btckey = &SecretKey::from_slice(&[40; 32]).unwrap();
}
}
- fn get_channel_script(secp_ctx: &Secp256k1<secp256k1::All>) -> Script {
+ pub(crate) fn get_channel_script(secp_ctx: &Secp256k1<secp256k1::All>) -> Script {
let node_1_btckey = SecretKey::from_slice(&[40; 32]).unwrap();
let node_2_btckey = SecretKey::from_slice(&[39; 32]).unwrap();
make_funding_redeemscript(&PublicKey::from_secret_key(secp_ctx, &node_1_btckey),
&PublicKey::from_secret_key(secp_ctx, &node_2_btckey)).to_v0_p2wsh()
}
- fn get_signed_channel_update<F: Fn(&mut UnsignedChannelUpdate)>(f: F, node_key: &SecretKey, secp_ctx: &Secp256k1<secp256k1::All>) -> ChannelUpdate {
+ pub(crate) fn get_signed_channel_update<F: Fn(&mut UnsignedChannelUpdate)>(f: F, node_key: &SecretKey, secp_ctx: &Secp256k1<secp256k1::All>) -> ChannelUpdate {
let mut unsigned_channel_update = UnsignedChannelUpdate {
chain_hash: genesis_block(Network::Testnet).header.block_hash(),
short_channel_id: 0,
let valid_announcement = get_signed_channel_announcement(|_| {}, node_1_privkey, node_2_privkey, &secp_ctx);
// Test if the UTXO lookups were not supported
- let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
- let network_graph = NetworkGraph::new(genesis_hash, &logger);
+ let network_graph = NetworkGraph::new(Network::Testnet, &logger);
let mut gossip_sync = P2PGossipSync::new(&network_graph, None, &logger);
match gossip_sync.handle_channel_announcement(&valid_announcement) {
Ok(res) => assert!(res),
// Test if an associated transaction were not on-chain (or not confirmed).
let chain_source = test_utils::TestChainSource::new(Network::Testnet);
- *chain_source.utxo_ret.lock().unwrap() = Err(UtxoLookupError::UnknownTx);
- let network_graph = NetworkGraph::new(genesis_hash, &logger);
+ *chain_source.utxo_ret.lock().unwrap() = UtxoResult::Sync(Err(UtxoLookupError::UnknownTx));
+ let network_graph = NetworkGraph::new(Network::Testnet, &logger);
gossip_sync = P2PGossipSync::new(&network_graph, Some(&chain_source), &logger);
let valid_announcement = get_signed_channel_announcement(|unsigned_announcement| {
};
// Now test if the transaction is found in the UTXO set and the script is correct.
- *chain_source.utxo_ret.lock().unwrap() = Ok(TxOut { value: 0, script_pubkey: good_script.clone() });
+ *chain_source.utxo_ret.lock().unwrap() =
+ UtxoResult::Sync(Ok(TxOut { value: 0, script_pubkey: good_script.clone() }));
let valid_announcement = get_signed_channel_announcement(|unsigned_announcement| {
unsigned_announcement.short_channel_id += 2;
}, node_1_privkey, node_2_privkey, &secp_ctx);
// If we receive announcement for the same channel, once we've validated it against the
// chain, we simply ignore all new (duplicate) announcements.
- *chain_source.utxo_ret.lock().unwrap() = Ok(TxOut { value: 0, script_pubkey: good_script });
+ *chain_source.utxo_ret.lock().unwrap() =
+ UtxoResult::Sync(Ok(TxOut { value: 0, script_pubkey: good_script }));
match gossip_sync.handle_channel_announcement(&valid_announcement) {
Ok(_) => panic!(),
Err(e) => assert_eq!(e.err, "Already have chain-validated channel")
let secp_ctx = Secp256k1::new();
let logger = test_utils::TestLogger::new();
let chain_source = test_utils::TestChainSource::new(Network::Testnet);
- let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
- let network_graph = NetworkGraph::new(genesis_hash, &logger);
+ let network_graph = NetworkGraph::new(Network::Testnet, &logger);
let gossip_sync = P2PGossipSync::new(&network_graph, Some(&chain_source), &logger);
let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap();
{
// Announce a channel we will update
let good_script = get_channel_script(&secp_ctx);
- *chain_source.utxo_ret.lock().unwrap() = Ok(TxOut { value: amount_sats, script_pubkey: good_script.clone() });
+ *chain_source.utxo_ret.lock().unwrap() =
+ UtxoResult::Sync(Ok(TxOut { value: amount_sats, script_pubkey: good_script.clone() }));
let valid_channel_announcement = get_signed_channel_announcement(|_| {}, node_1_privkey, node_2_privkey, &secp_ctx);
short_channel_id = valid_channel_announcement.contents.short_channel_id;
#[test]
fn handling_network_update() {
let logger = test_utils::TestLogger::new();
- let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
- let network_graph = NetworkGraph::new(genesis_hash, &logger);
+ let network_graph = NetworkGraph::new(Network::Testnet, &logger);
let secp_ctx = Secp256k1::new();
let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap();
{
// Get a new network graph since we don't want to track removed nodes in this test with "std"
- let network_graph = NetworkGraph::new(genesis_hash, &logger);
+ let network_graph = NetworkGraph::new(Network::Testnet, &logger);
// Announce a channel to test permanent node failure
let valid_channel_announcement = get_signed_channel_announcement(|_| {}, node_1_privkey, node_2_privkey, &secp_ctx);
// Test the removal of channels with `remove_stale_channels_and_tracking`.
let logger = test_utils::TestLogger::new();
let chain_source = test_utils::TestChainSource::new(Network::Testnet);
- let genesis_hash = genesis_block(Network::Testnet).header.block_hash();
- let network_graph = NetworkGraph::new(genesis_hash, &logger);
+ let network_graph = NetworkGraph::new(Network::Testnet, &logger);
let gossip_sync = P2PGossipSync::new(&network_graph, Some(&chain_source), &logger);
let secp_ctx = Secp256k1::new();
// It should ignore if gossip_queries feature is not enabled
{
let init_msg = Init { features: InitFeatures::empty(), remote_network_address: None };
- gossip_sync.peer_connected(&node_id_1, &init_msg).unwrap();
+ gossip_sync.peer_connected(&node_id_1, &init_msg, true).unwrap();
let events = gossip_sync.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 0);
}
let mut features = InitFeatures::empty();
features.set_gossip_queries_optional();
let init_msg = Init { features, remote_network_address: None };
- gossip_sync.peer_connected(&node_id_1, &init_msg).unwrap();
+ gossip_sync.peer_connected(&node_id_1, &init_msg, true).unwrap();
let events = gossip_sync.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 1);
match &events[0] {