X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Frouting%2Fgossip.rs;h=40969b180af9d6904d79eb29d8cdf05b3c624bc9;hb=42e2f1d1a645156180cbcc664989df78175301d2;hp=11bf532e90fc40388f0debf30968fa5c6cb813bd;hpb=c3de782a2baab0c742332bea4783c393edb83311;p=rust-lightning diff --git a/lightning/src/routing/gossip.rs b/lightning/src/routing/gossip.rs index 11bf532e..40969b18 100644 --- a/lightning/src/routing/gossip.rs +++ b/lightning/src/routing/gossip.rs @@ -40,7 +40,7 @@ use crate::io_extras::{copy, sink}; use crate::prelude::*; use core::{cmp, fmt}; use core::convert::TryFrom; -use crate::sync::{RwLock, RwLockReadGuard}; +use crate::sync::{RwLock, RwLockReadGuard, LockTestExt}; #[cfg(feature = "std")] use core::sync::atomic::{AtomicUsize, Ordering}; use crate::sync::Mutex; @@ -366,6 +366,11 @@ impl NetworkGraph where L::Target: Logger { }, } } + + /// Gets the genesis hash for this network graph. + pub fn get_genesis_hash(&self) -> BlockHash { + self.genesis_hash + } } macro_rules! secp_verify_sig { @@ -965,7 +970,7 @@ impl<'a> DirectedChannelInfo<'a> { htlc_maximum_msat = cmp::min(htlc_maximum_msat, capacity_msat); EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat: htlc_maximum_msat } }, - None => EffectiveCapacity::MaximumHTLC { amount_msat: htlc_maximum_msat }, + None => EffectiveCapacity::AdvertisedMaxHTLC { amount_msat: htlc_maximum_msat }, }; Self { @@ -1019,7 +1024,7 @@ pub enum EffectiveCapacity { liquidity_msat: u64, }, /// The maximum HTLC amount in one direction as advertised on the gossip network. - MaximumHTLC { + AdvertisedMaxHTLC { /// The maximum HTLC amount denominated in millisatoshi. amount_msat: u64, }, @@ -1033,6 +1038,11 @@ pub enum EffectiveCapacity { /// A capacity sufficient to route any payment, typically used for private channels provided by /// an invoice. Infinite, + /// The maximum HTLC amount as provided by an invoice route hint. + HintMaxHTLC { + /// The maximum HTLC amount denominated in millisatoshi. + amount_msat: u64, + }, /// A capacity that is unknown possibly because either the chain state is unavailable to know /// the total capacity or the `htlc_maximum_msat` was not advertised on the gossip network. Unknown, @@ -1047,8 +1057,9 @@ impl EffectiveCapacity { pub fn as_msat(&self) -> u64 { match self { EffectiveCapacity::ExactLiquidity { liquidity_msat } => *liquidity_msat, - EffectiveCapacity::MaximumHTLC { amount_msat } => *amount_msat, + EffectiveCapacity::AdvertisedMaxHTLC { amount_msat } => *amount_msat, EffectiveCapacity::Total { capacity_msat, .. } => *capacity_msat, + EffectiveCapacity::HintMaxHTLC { amount_msat } => *amount_msat, EffectiveCapacity::Infinite => u64::max_value(), EffectiveCapacity::Unknown => UNKNOWN_CHANNEL_CAPACITY_MSAT, } @@ -1056,7 +1067,7 @@ impl EffectiveCapacity { } /// Fees for routing via a given channel or a node -#[derive(Eq, PartialEq, Copy, Clone, Debug, Hash)] +#[derive(Eq, PartialEq, Copy, Clone, Debug, Hash, Ord, PartialOrd)] pub struct RoutingFees { /// Flat routing fee in millisatoshis. pub base_msat: u32, @@ -1327,9 +1338,14 @@ impl fmt::Display for NetworkGraph where L::Target: Logger { impl Eq for NetworkGraph where L::Target: Logger {} impl PartialEq for NetworkGraph where L::Target: Logger { fn eq(&self, other: &Self) -> bool { - self.genesis_hash == other.genesis_hash && - *self.channels.read().unwrap() == *other.channels.read().unwrap() && - *self.nodes.read().unwrap() == *other.nodes.read().unwrap() + // For a total lockorder, sort by position in memory and take the inner locks in that order. + // (Assumes that we can't move within memory while a lock is held). + let ord = ((self as *const _) as usize) < ((other as *const _) as usize); + let a = if ord { (&self.channels, &self.nodes) } else { (&other.channels, &other.nodes) }; + let b = if ord { (&other.channels, &other.nodes) } else { (&self.channels, &self.nodes) }; + let (channels_a, channels_b) = (a.0.unsafe_well_ordered_double_lock_self(), b.0.unsafe_well_ordered_double_lock_self()); + let (nodes_a, nodes_b) = (a.1.unsafe_well_ordered_double_lock_self(), b.1.unsafe_well_ordered_double_lock_self()); + self.genesis_hash.eq(&other.genesis_hash) && channels_a.eq(&channels_b) && nodes_a.eq(&nodes_b) } } @@ -1573,6 +1589,13 @@ impl NetworkGraph where L::Target: Logger { return Err(LightningError{err: "Channel announcement node had a channel with itself".to_owned(), action: ErrorAction::IgnoreError}); } + if msg.chain_hash != self.genesis_hash { + return Err(LightningError { + err: "Channel announcement chain hash does not match genesis hash".to_owned(), + action: ErrorAction::IgnoreAndLog(Level::Debug), + }); + } + { let channels = self.channels.read().unwrap(); @@ -1819,6 +1842,13 @@ impl NetworkGraph where L::Target: Logger { fn update_channel_intern(&self, msg: &msgs::UnsignedChannelUpdate, full_msg: Option<&msgs::ChannelUpdate>, sig: Option<&secp256k1::ecdsa::Signature>) -> Result<(), LightningError> { let chan_enabled = msg.flags & (1 << 1) != (1 << 1); + if msg.chain_hash != self.genesis_hash { + return Err(LightningError { + err: "Channel update chain hash does not match genesis hash".to_owned(), + action: ErrorAction::IgnoreAndLog(Level::Debug), + }); + } + #[cfg(all(feature = "std", not(test), not(feature = "_test_utils")))] { // Note that many tests rely on being able to set arbitrarily old timestamps, thus we @@ -2311,6 +2341,16 @@ pub(crate) mod tests { Ok(_) => panic!(), Err(e) => assert_eq!(e.err, "Channel announcement node had a channel with itself") }; + + // Test that channel announcements with the wrong chain hash are ignored (network graph is testnet, + // announcement is mainnet). + let incorrect_chain_announcement = get_signed_channel_announcement(|unsigned_announcement| { + unsigned_announcement.chain_hash = genesis_block(Network::Bitcoin).header.block_hash(); + }, node_1_privkey, node_2_privkey, &secp_ctx); + match gossip_sync.handle_channel_announcement(&incorrect_chain_announcement) { + Ok(_) => panic!(), + Err(e) => assert_eq!(e.err, "Channel announcement chain hash does not match genesis hash") + }; } #[test] @@ -2415,6 +2455,17 @@ pub(crate) mod tests { Ok(_) => panic!(), Err(e) => assert_eq!(e.err, "Invalid signature on channel_update message") }; + + // Test that channel updates with the wrong chain hash are ignored (network graph is testnet, channel + // update is mainet). + let incorrect_chain_update = get_signed_channel_update(|unsigned_channel_update| { + unsigned_channel_update.chain_hash = genesis_block(Network::Bitcoin).header.block_hash(); + }, node_1_privkey, &secp_ctx); + + match gossip_sync.handle_channel_update(&incorrect_chain_update) { + Ok(_) => panic!(), + Err(e) => assert_eq!(e.err, "Channel update chain hash does not match genesis hash") + }; } #[test] @@ -2850,7 +2901,7 @@ pub(crate) mod tests { // It should ignore if gossip_queries feature is not enabled { - let init_msg = Init { features: InitFeatures::empty(), remote_network_address: None }; + let init_msg = Init { features: InitFeatures::empty(), networks: None, remote_network_address: None }; 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); @@ -2860,7 +2911,7 @@ pub(crate) mod tests { { let mut features = InitFeatures::empty(); features.set_gossip_queries_optional(); - let init_msg = Init { features, remote_network_address: None }; + let init_msg = Init { features, networks: None, remote_network_address: None }; 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); @@ -3353,31 +3404,28 @@ pub(crate) mod tests { } } -#[cfg(all(test, feature = "_bench_unstable"))] -mod benches { +#[cfg(ldk_bench)] +pub mod benches { use super::*; - - use test::Bencher; use std::io::Read; + use criterion::{black_box, Criterion}; - #[bench] - fn read_network_graph(bench: &mut Bencher) { + pub fn read_network_graph(bench: &mut Criterion) { let logger = crate::util::test_utils::TestLogger::new(); let mut d = crate::routing::router::bench_utils::get_route_file().unwrap(); let mut v = Vec::new(); d.read_to_end(&mut v).unwrap(); - bench.iter(|| { - let _ = NetworkGraph::read(&mut std::io::Cursor::new(&v), &logger).unwrap(); - }); + bench.bench_function("read_network_graph", |b| b.iter(|| + NetworkGraph::read(&mut std::io::Cursor::new(black_box(&v)), &logger).unwrap() + )); } - #[bench] - fn write_network_graph(bench: &mut Bencher) { + pub fn write_network_graph(bench: &mut Criterion) { let logger = crate::util::test_utils::TestLogger::new(); let mut d = crate::routing::router::bench_utils::get_route_file().unwrap(); let net_graph = NetworkGraph::read(&mut d, &logger).unwrap(); - bench.iter(|| { - let _ = net_graph.encode(); - }); + bench.bench_function("write_network_graph", |b| b.iter(|| + black_box(&net_graph).encode() + )); } }