use util::ser::{Writeable, Readable, Writer};
use util::logger::Logger;
-use std::cmp;
-use std::sync::{RwLock,Arc};
+use std::{cmp, fmt};
+use std::sync::RwLock;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::collections::BTreeMap;
use std::collections::btree_map::Entry as BtreeEntry;
-use std;
+use std::ops::Deref;
+use bitcoin::hashes::hex::ToHex;
/// Receives and validates network updates from peers,
/// stores authentic and relevant data as a network graph.
/// This network graph is then used for routing payments.
/// Provides interface to help with initial routing sync by
/// serving historical announcements.
-pub struct NetGraphMsgHandler {
+pub struct NetGraphMsgHandler<C: Deref, L: Deref> where C::Target: ChainWatchInterface, L::Target: Logger {
secp_ctx: Secp256k1<secp256k1::VerifyOnly>,
/// Representation of the payment channel network
pub network_graph: RwLock<NetworkGraph>,
- chain_monitor: Arc<ChainWatchInterface>,
+ chain_monitor: C,
full_syncs_requested: AtomicUsize,
- logger: Arc<Logger>,
+ logger: L,
}
-impl NetGraphMsgHandler {
+impl<C: Deref, L: Deref> NetGraphMsgHandler<C, L> where C::Target: ChainWatchInterface, L::Target: Logger {
/// Creates a new tracker of the actual state of the network of channels and nodes,
/// assuming a fresh network graph.
/// Chain monitor is used to make sure announced channels exist on-chain,
/// channel data is correct, and that the announcement is signed with
/// channel owners' keys.
- pub fn new(chain_monitor: Arc<ChainWatchInterface>, logger: Arc<Logger>) -> Self {
+ pub fn new(chain_monitor: C, logger: L) -> Self {
NetGraphMsgHandler {
secp_ctx: Secp256k1::verification_only(),
network_graph: RwLock::new(NetworkGraph {
}),
full_syncs_requested: AtomicUsize::new(0),
chain_monitor,
- logger: logger.clone(),
+ logger,
}
}
/// Creates a new tracker of the actual state of the network of channels and nodes,
/// assuming an existing Network Graph.
- pub fn from_net_graph(chain_monitor: Arc<ChainWatchInterface>, logger: Arc<Logger>, network_graph: RwLock<NetworkGraph>) -> Self {
+ pub fn from_net_graph(chain_monitor: C, logger: L, network_graph: NetworkGraph) -> Self {
NetGraphMsgHandler {
secp_ctx: Secp256k1::verification_only(),
- network_graph: network_graph,
+ network_graph: RwLock::new(network_graph),
full_syncs_requested: AtomicUsize::new(0),
chain_monitor,
- logger: logger.clone(),
+ logger,
}
}
}
( $secp_ctx: expr, $msg: expr, $sig: expr, $pubkey: expr ) => {
match $secp_ctx.verify($msg, $sig, $pubkey) {
Ok(_) => {},
- Err(_) => return Err(LightningError{err: "Invalid signature from remote node", action: ErrorAction::IgnoreError}),
+ Err(_) => return Err(LightningError{err: "Invalid signature from remote node".to_owned(), action: ErrorAction::IgnoreError}),
}
};
}
-impl RoutingMessageHandler for NetGraphMsgHandler {
+impl<C: Deref + Sync + Send, L: Deref + Sync + Send> RoutingMessageHandler for NetGraphMsgHandler<C, L> where C::Target: ChainWatchInterface, L::Target: Logger {
fn handle_node_announcement(&self, msg: &msgs::NodeAnnouncement) -> Result<bool, LightningError> {
self.network_graph.write().unwrap().update_node_from_announcement(msg, Some(&self.secp_ctx))
}
fn handle_channel_announcement(&self, msg: &msgs::ChannelAnnouncement) -> Result<bool, LightningError> {
if msg.contents.node_id_1 == msg.contents.node_id_2 || msg.contents.bitcoin_key_1 == msg.contents.bitcoin_key_2 {
- return Err(LightningError{err: "Channel announcement node had a channel with itself", action: ErrorAction::IgnoreError});
+ return Err(LightningError{err: "Channel announcement node had a channel with itself".to_owned(), action: ErrorAction::IgnoreError});
}
let checked_utxo = match self.chain_monitor.get_chain_utxo(msg.contents.chain_hash, msg.contents.short_channel_id) {
.push_opcode(opcodes::all::OP_PUSHNUM_2)
.push_opcode(opcodes::all::OP_CHECKMULTISIG).into_script().to_v0_p2wsh();
if script_pubkey != expected_script {
- return Err(LightningError{err: "Channel announcement keys didn't match on-chain script", action: ErrorAction::IgnoreError});
+ return Err(LightningError{err: format!("Channel announcement key ({}) didn't match on-chain script ({})", script_pubkey.to_hex(), expected_script.to_hex()), action: ErrorAction::IgnoreError});
}
//TODO: Check if value is worth storing, use it to inform routing, and compare it
//to the new HTLC max field in channel_update
false
},
Err(ChainError::NotWatched) => {
- return Err(LightningError{err: "Channel announced on an unknown chain", action: ErrorAction::IgnoreError});
+ return Err(LightningError{err: format!("Channel announced on an unknown chain ({})", msg.contents.chain_hash.encode().to_hex()), action: ErrorAction::IgnoreError});
},
Err(ChainError::UnknownTx) => {
- return Err(LightningError{err: "Channel announced without corresponding UTXO entry", action: ErrorAction::IgnoreError});
+ return Err(LightningError{err: "Channel announced without corresponding UTXO entry".to_owned(), action: ErrorAction::IgnoreError});
},
};
let result = self.network_graph.write().unwrap().update_channel_from_announcement(msg, checked_utxo, Some(&self.secp_ctx));
- log_trace!(self, "Added channel_announcement for {}{}", msg.contents.short_channel_id, if !msg.contents.excess_data.is_empty() { " with excess uninterpreted data!" } else { "" });
+ log_trace!(self.logger, "Added channel_announcement for {}{}", msg.contents.short_channel_id, if !msg.contents.excess_data.is_empty() { " with excess uninterpreted data!" } else { "" });
result
}
&msgs::HTLCFailChannelUpdate::ChannelUpdateMessage { ref msg } => {
let _ = self.network_graph.write().unwrap().update_channel(msg, Some(&self.secp_ctx));
},
- &msgs::HTLCFailChannelUpdate::ChannelClosed { ref short_channel_id, ref is_permanent } => {
- self.network_graph.write().unwrap().close_channel_from_update(short_channel_id, &is_permanent);
+ &msgs::HTLCFailChannelUpdate::ChannelClosed { short_channel_id, is_permanent } => {
+ self.network_graph.write().unwrap().close_channel_from_update(short_channel_id, is_permanent);
},
- &msgs::HTLCFailChannelUpdate::NodeFailure { ref node_id, ref is_permanent } => {
- self.network_graph.write().unwrap().fail_node(node_id, &is_permanent);
+ &msgs::HTLCFailChannelUpdate::NodeFailure { ref node_id, is_permanent } => {
+ self.network_graph.write().unwrap().fail_node(node_id, is_permanent);
},
}
}
pub last_update_message: Option<msgs::ChannelUpdate>,
}
-impl std::fmt::Display for DirectionalChannelInfo {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
+impl fmt::Display for DirectionalChannelInfo {
+ fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "last_update {}, enabled {}, cltv_expiry_delta {}, htlc_minimum_msat {}, fees {:?}", self.last_update, self.enabled, self.cltv_expiry_delta, self.htlc_minimum_msat, self.fees)?;
Ok(())
}
pub announcement_message: Option<msgs::ChannelAnnouncement>,
}
-impl std::fmt::Display for ChannelInfo {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
+impl fmt::Display for ChannelInfo {
+ fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "features: {}, node_one: {}, one_to_two: {:?}, node_two: {}, two_to_one: {:?}",
log_bytes!(self.features.encode()), log_pubkey!(self.node_one), self.one_to_two, log_pubkey!(self.node_two), self.two_to_one)?;
Ok(())
pub announcement_info: Option<NodeAnnouncementInfo>
}
-impl std::fmt::Display for NodeInfo {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
+impl fmt::Display for NodeInfo {
+ fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "lowest_inbound_channel_fees: {:?}, channels: {:?}, announcement_info: {:?}",
self.lowest_inbound_channel_fees, &self.channels[..], self.announcement_info)?;
Ok(())
}
}
-impl std::fmt::Display for NetworkGraph {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
+impl fmt::Display for NetworkGraph {
+ fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "Network map\n[Channels]\n")?;
for (key, val) in self.channels.iter() {
write!(f, " {}: {}\n", key, val)?;
None
}
+ /// Creates a new, empty, network graph.
+ pub fn new() -> NetworkGraph {
+ Self {
+ channels: BTreeMap::new(),
+ nodes: BTreeMap::new(),
+ }
+ }
+
/// For an already known node (from channel announcements), update its stored properties from a given node announcement
/// Announcement signatures are checked here only if Secp256k1 object is provided.
fn update_node_from_announcement(&mut self, msg: &msgs::NodeAnnouncement, secp_ctx: Option<&Secp256k1<secp256k1::VerifyOnly>>) -> Result<bool, LightningError> {
}
match self.nodes.get_mut(&msg.contents.node_id) {
- None => Err(LightningError{err: "No existing channels for node_announcement", action: ErrorAction::IgnoreError}),
+ None => Err(LightningError{err: "No existing channels for node_announcement".to_owned(), action: ErrorAction::IgnoreError}),
Some(node) => {
if let Some(node_info) = node.announcement_info.as_ref() {
if node_info.last_update >= msg.contents.timestamp {
- return Err(LightningError{err: "Update older than last processed update", action: ErrorAction::IgnoreError});
+ return Err(LightningError{err: "Update older than last processed update".to_owned(), action: ErrorAction::IgnoreError});
}
}
Self::remove_channel_in_nodes(&mut self.nodes, &entry.get(), msg.contents.short_channel_id);
*entry.get_mut() = chan_info;
} else {
- return Err(LightningError{err: "Already have knowledge of channel", action: ErrorAction::IgnoreError})
+ return Err(LightningError{err: "Already have knowledge of channel".to_owned(), action: ErrorAction::IgnoreError})
}
},
BtreeEntry::Vacant(entry) => {
/// If permanent, removes a channel from the local storage.
/// May cause the removal of nodes too, if this was their last channel.
/// If not permanent, makes channels unavailable for routing.
- pub fn close_channel_from_update(&mut self, short_channel_id: &u64, is_permanent: &bool) {
- if *is_permanent {
- if let Some(chan) = self.channels.remove(short_channel_id) {
- Self::remove_channel_in_nodes(&mut self.nodes, &chan, *short_channel_id);
+ pub fn close_channel_from_update(&mut self, short_channel_id: u64, is_permanent: bool) {
+ if is_permanent {
+ if let Some(chan) = self.channels.remove(&short_channel_id) {
+ Self::remove_channel_in_nodes(&mut self.nodes, &chan, short_channel_id);
}
} else {
if let Some(chan) = self.channels.get_mut(&short_channel_id) {
}
}
- fn fail_node(&mut self, _node_id: &PublicKey, is_permanent: &bool) {
- if *is_permanent {
+ fn fail_node(&mut self, _node_id: &PublicKey, is_permanent: bool) {
+ if is_permanent {
// TODO: Wholly remove the node
} else {
// TODO: downgrade the node
let chan_was_enabled;
match self.channels.get_mut(&msg.contents.short_channel_id) {
- None => return Err(LightningError{err: "Couldn't find channel for update", action: ErrorAction::IgnoreError}),
+ None => return Err(LightningError{err: "Couldn't find channel for update".to_owned(), action: ErrorAction::IgnoreError}),
Some(channel) => {
macro_rules! maybe_update_channel_info {
( $target: expr, $src_node: expr) => {
if let Some(existing_chan_info) = $target.as_ref() {
if existing_chan_info.last_update >= msg.contents.timestamp {
- return Err(LightningError{err: "Update older than last processed update", action: ErrorAction::IgnoreError});
+ return Err(LightningError{err: "Update older than last processed update".to_owned(), action: ErrorAction::IgnoreError});
}
chan_was_enabled = existing_chan_info.enabled;
} else {
proportional_millionths
});
} else if chan_was_enabled {
- let mut node = self.nodes.get_mut(&dest_node_id).unwrap();
+ let node = self.nodes.get_mut(&dest_node_id).unwrap();
let mut lowest_inbound_channel_fees = None;
for chan_id in node.channels.iter() {
use std::sync::Arc;
- fn create_net_graph_msg_handler() -> (Secp256k1<All>, NetGraphMsgHandler) {
+ fn create_net_graph_msg_handler() -> (Secp256k1<All>, NetGraphMsgHandler<Arc<chaininterface::ChainWatchInterfaceUtil>, Arc<test_utils::TestLogger>>) {
let secp_ctx = Secp256k1::new();
- let logger: Arc<Logger> = Arc::new(test_utils::TestLogger::new());
- let chain_monitor = Arc::new(chaininterface::ChainWatchInterfaceUtil::new(Network::Testnet, Arc::clone(&logger)));
+ let logger = Arc::new(test_utils::TestLogger::new());
+ let chain_monitor = Arc::new(chaininterface::ChainWatchInterfaceUtil::new(Network::Testnet));
let net_graph_msg_handler = NetGraphMsgHandler::new(chain_monitor, Arc::clone(&logger));
(secp_ctx, net_graph_msg_handler)
}