Merge pull request #570 from naumenkogs/2020_04_routing_message_handler_tests

Add tests for routing message handler
This commit is contained in:
Matt Corallo 2020-04-11 18:31:00 +00:00 committed by GitHub
commit c9c9415e5f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 820 additions and 18 deletions

View file

@ -507,7 +507,7 @@ mod tests {
fn handle_channel_announcement(&self, _msg: &ChannelAnnouncement) -> Result<bool, LightningError> { Ok(false) }
fn handle_channel_update(&self, _msg: &ChannelUpdate) -> Result<bool, LightningError> { Ok(false) }
fn handle_htlc_fail_channel_update(&self, _update: &HTLCFailChannelUpdate) { }
fn get_next_channel_announcements(&self, _starting_point: u64, _batch_amount: u8) -> Vec<(ChannelAnnouncement, ChannelUpdate, ChannelUpdate)> { Vec::new() }
fn get_next_channel_announcements(&self, _starting_point: u64, _batch_amount: u8) -> Vec<(ChannelAnnouncement, Option<ChannelUpdate>, Option<ChannelUpdate>)> { Vec::new() }
fn get_next_node_announcements(&self, _starting_point: Option<&PublicKey>, _batch_amount: u8) -> Vec<NodeAnnouncement> { Vec::new() }
fn should_request_full_sync(&self, _node_id: &PublicKey) -> bool { false }
}

View file

@ -22,6 +22,7 @@ use std::marker::PhantomData;
use std::ptr;
/// Used to give chain error details upstream
#[derive(Clone)]
pub enum ChainError {
/// Client doesn't support UTXO lookup (but the chain hash matches our genesis block hash)
NotSupported,

View file

@ -601,7 +601,7 @@ pub trait RoutingMessageHandler : Send + Sync {
/// Gets a subset of the channel announcements and updates required to dump our routing table
/// to a remote node, starting at the short_channel_id indicated by starting_point and
/// including the batch_amount entries immediately higher in numerical value than starting_point.
fn get_next_channel_announcements(&self, starting_point: u64, batch_amount: u8) -> Vec<(ChannelAnnouncement, ChannelUpdate, ChannelUpdate)>;
fn get_next_channel_announcements(&self, starting_point: u64, batch_amount: u8) -> Vec<(ChannelAnnouncement, Option<ChannelUpdate>, Option<ChannelUpdate>)>;
/// Gets a subset of the node announcements required to dump our routing table to a remote node,
/// starting at the node *after* the provided publickey and including batch_amount entries
/// immediately higher (as defined by <PublicKey as Ord>::cmp) than starting_point.

View file

@ -355,10 +355,14 @@ impl<Descriptor: SocketDescriptor, CM: Deref> PeerManager<Descriptor, CM> where
InitSyncTracker::ChannelsSyncing(c) if c < 0xffff_ffff_ffff_ffff => {
let steps = ((MSG_BUFF_SIZE - peer.pending_outbound_buffer.len() + 2) / 3) as u8;
let all_messages = self.message_handler.route_handler.get_next_channel_announcements(c, steps);
for &(ref announce, ref update_a, ref update_b) in all_messages.iter() {
for &(ref announce, ref update_a_option, ref update_b_option) in all_messages.iter() {
encode_and_send_msg!(announce);
encode_and_send_msg!(update_a);
encode_and_send_msg!(update_b);
if let &Some(ref update_a) = update_a_option {
encode_and_send_msg!(update_a);
}
if let &Some(ref update_b) = update_b_option {
encode_and_send_msg!(update_b);
}
peer.sync_status = InitSyncTracker::ChannelsSyncing(announce.contents.short_channel_id + 1);
}
if all_messages.is_empty() || all_messages.len() != steps as usize {
@ -1313,7 +1317,7 @@ mod tests {
Err(msgs::LightningError { err: "", action: msgs::ErrorAction::IgnoreError })
}
fn handle_htlc_fail_channel_update(&self, _update: &msgs::HTLCFailChannelUpdate) {}
fn get_next_channel_announcements(&self, starting_point: u64, batch_amount: u8) -> Vec<(msgs::ChannelAnnouncement, msgs::ChannelUpdate,msgs::ChannelUpdate)> {
fn get_next_channel_announcements(&self, starting_point: u64, batch_amount: u8) -> Vec<(msgs::ChannelAnnouncement, Option<msgs::ChannelUpdate>, Option<msgs::ChannelUpdate>)> {
let mut chan_anns = Vec::new();
const TOTAL_UPDS: u64 = 100;
let end: u64 = min(starting_point + batch_amount as u64, TOTAL_UPDS - self.chan_anns_sent.load(Ordering::Acquire) as u64);
@ -1322,7 +1326,7 @@ mod tests {
let chan_upd_2 = get_dummy_channel_update(i);
let chan_ann = get_dummy_channel_announcement(i);
chan_anns.push((chan_ann, chan_upd_1, chan_upd_2));
chan_anns.push((chan_ann, Some(chan_upd_1), Some(chan_upd_2)));
}
self.chan_anns_sent.fetch_add(chan_anns.len(), Ordering::AcqRel);

View file

@ -559,6 +559,7 @@ impl RoutingMessageHandler for Router {
add_channel_to_node!(msg.contents.node_id_1);
add_channel_to_node!(msg.contents.node_id_2);
log_trace!(self, "Added channel_announcement for {}{}", msg.contents.short_channel_id, if !should_relay { " with excess uninterpreted data!" } else { "" });
Ok(should_relay)
}
@ -663,19 +664,16 @@ impl RoutingMessageHandler for Router {
Ok(msg.contents.excess_data.is_empty())
}
fn get_next_channel_announcements(&self, starting_point: u64, batch_amount: u8) -> Vec<(msgs::ChannelAnnouncement, msgs::ChannelUpdate,msgs::ChannelUpdate)> {
fn get_next_channel_announcements(&self, starting_point: u64, batch_amount: u8) -> Vec<(msgs::ChannelAnnouncement, Option<msgs::ChannelUpdate>, Option<msgs::ChannelUpdate>)> {
let mut result = Vec::with_capacity(batch_amount as usize);
let network = self.network_map.read().unwrap();
let mut iter = network.channels.range(starting_point..);
while result.len() < batch_amount as usize {
if let Some((_, ref chan)) = iter.next() {
if chan.announcement_message.is_some() &&
chan.one_to_two.last_update_message.is_some() &&
chan.two_to_one.last_update_message.is_some() {
if chan.announcement_message.is_some() {
result.push((chan.announcement_message.clone().unwrap(),
chan.one_to_two.last_update_message.clone().unwrap(),
chan.two_to_one.last_update_message.clone().unwrap()));
chan.one_to_two.last_update_message.clone(),
chan.two_to_one.last_update_message.clone()));
} else {
// TODO: We may end up sending un-announced channel_updates if we are sending
// initial sync data while receiving announce/updates for this channel.
@ -1057,7 +1055,8 @@ mod tests {
use ln::channelmanager;
use ln::router::{Router,NodeInfo,NetworkMap,ChannelInfo,DirectionalChannelInfo,RouteHint};
use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
use ln::msgs::{ErrorAction, LightningError, RoutingMessageHandler};
use ln::msgs::{ErrorAction, LightningError, RoutingMessageHandler, UnsignedNodeAnnouncement, NodeAnnouncement,
UnsignedChannelAnnouncement, ChannelAnnouncement, UnsignedChannelUpdate, ChannelUpdate, HTLCFailChannelUpdate};
use util::test_utils;
use util::test_utils::TestVecWriter;
use util::logger::Logger;
@ -1066,6 +1065,10 @@ mod tests {
use bitcoin_hashes::sha256d::Hash as Sha256dHash;
use bitcoin_hashes::Hash;
use bitcoin::network::constants::Network;
use bitcoin::blockdata::constants::genesis_block;
use bitcoin::blockdata::script::Builder;
use bitcoin::blockdata::opcodes;
use bitcoin::util::hash::BitcoinHash;
use hex;
@ -1074,6 +1077,7 @@ mod tests {
use secp256k1::Secp256k1;
use std::sync::Arc;
use std::collections::btree_map::Entry as BtreeEntry;
fn create_router() -> (Secp256k1<All>, PublicKey, Router) {
let secp_ctx = Secp256k1::new();
@ -1864,4 +1868,770 @@ mod tests {
assert!(router.should_request_full_sync(&node_id));
assert!(!router.should_request_full_sync(&node_id));
}
#[test]
fn handling_node_announcements() {
let (secp_ctx, _, router) = create_router();
let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap();
let node_2_privkey = &SecretKey::from_slice(&[41; 32]).unwrap();
let node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_1_privkey);
let node_id_2 = PublicKey::from_secret_key(&secp_ctx, node_2_privkey);
let node_1_btckey = &SecretKey::from_slice(&[40; 32]).unwrap();
let node_2_btckey = &SecretKey::from_slice(&[39; 32]).unwrap();
let zero_hash = Sha256dHash::hash(&[0; 32]);
let first_announcement_time = 500;
let mut unsigned_announcement = UnsignedNodeAnnouncement {
features: NodeFeatures::supported(),
timestamp: first_announcement_time,
node_id: node_id_1,
rgb: [0; 3],
alias: [0; 32],
addresses: Vec::new(),
excess_address_data: Vec::new(),
excess_data: Vec::new(),
};
let mut msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
let valid_announcement = NodeAnnouncement {
signature: secp_ctx.sign(&msghash, node_1_privkey),
contents: unsigned_announcement.clone()
};
match router.handle_node_announcement(&valid_announcement) {
Ok(_) => panic!(),
Err(e) => assert_eq!("No existing channels for node_announcement", e.err)
};
{
// Announce a channel to add a corresponding node.
let unsigned_announcement = UnsignedChannelAnnouncement {
features: ChannelFeatures::supported(),
chain_hash: genesis_block(Network::Testnet).header.bitcoin_hash(),
short_channel_id: 0,
node_id_1,
node_id_2,
bitcoin_key_1: PublicKey::from_secret_key(&secp_ctx, node_1_btckey),
bitcoin_key_2: PublicKey::from_secret_key(&secp_ctx, node_2_btckey),
excess_data: Vec::new(),
};
let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
let valid_announcement = ChannelAnnouncement {
node_signature_1: secp_ctx.sign(&msghash, node_1_privkey),
node_signature_2: secp_ctx.sign(&msghash, node_2_privkey),
bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey),
bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey),
contents: unsigned_announcement.clone(),
};
match router.handle_channel_announcement(&valid_announcement) {
Ok(res) => assert!(res),
_ => panic!()
};
}
match router.handle_node_announcement(&valid_announcement) {
Ok(res) => assert!(res),
Err(_) => panic!()
};
let fake_msghash = hash_to_message!(&zero_hash);
match router.handle_node_announcement(
&NodeAnnouncement {
signature: secp_ctx.sign(&fake_msghash, node_1_privkey),
contents: unsigned_announcement.clone()
}) {
Ok(_) => panic!(),
Err(e) => assert_eq!(e.err, "Invalid signature from remote node")
};
unsigned_announcement.timestamp += 1000;
unsigned_announcement.excess_data.push(1);
msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
let announcement_with_data = NodeAnnouncement {
signature: secp_ctx.sign(&msghash, node_1_privkey),
contents: unsigned_announcement.clone()
};
// Return false because contains excess data.
match router.handle_node_announcement(&announcement_with_data) {
Ok(res) => assert!(!res),
Err(_) => panic!()
};
unsigned_announcement.excess_data = Vec::new();
// Even though previous announcement was not relayed further, we still accepted it,
// so we now won't accept announcements before the previous one.
unsigned_announcement.timestamp -= 10;
msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
let outdated_announcement = NodeAnnouncement {
signature: secp_ctx.sign(&msghash, node_1_privkey),
contents: unsigned_announcement.clone()
};
match router.handle_node_announcement(&outdated_announcement) {
Ok(_) => panic!(),
Err(e) => assert_eq!(e.err, "Update older than last processed update")
};
}
#[test]
fn handling_channel_announcements() {
let secp_ctx = Secp256k1::new();
let our_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(
&hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap()[..]).unwrap());
let logger: Arc<Logger> = Arc::new(test_utils::TestLogger::new());
let chain_monitor = Arc::new(test_utils::TestChainWatcher::new());
let router = Router::new(our_id, chain_monitor.clone(), Arc::clone(&logger));
let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap();
let node_2_privkey = &SecretKey::from_slice(&[41; 32]).unwrap();
let node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_1_privkey);
let node_id_2 = PublicKey::from_secret_key(&secp_ctx, node_2_privkey);
let node_1_btckey = &SecretKey::from_slice(&[40; 32]).unwrap();
let node_2_btckey = &SecretKey::from_slice(&[39; 32]).unwrap();
let good_script = Builder::new().push_opcode(opcodes::all::OP_PUSHNUM_2)
.push_slice(&PublicKey::from_secret_key(&secp_ctx, node_1_btckey).serialize())
.push_slice(&PublicKey::from_secret_key(&secp_ctx, node_2_btckey).serialize())
.push_opcode(opcodes::all::OP_PUSHNUM_2)
.push_opcode(opcodes::all::OP_CHECKMULTISIG).into_script().to_v0_p2wsh();
let mut unsigned_announcement = UnsignedChannelAnnouncement {
features: ChannelFeatures::supported(),
chain_hash: genesis_block(Network::Testnet).header.bitcoin_hash(),
short_channel_id: 0,
node_id_1,
node_id_2,
bitcoin_key_1: PublicKey::from_secret_key(&secp_ctx, node_1_btckey),
bitcoin_key_2: PublicKey::from_secret_key(&secp_ctx, node_2_btckey),
excess_data: Vec::new(),
};
let channel_key = NetworkMap::get_key(unsigned_announcement.short_channel_id,
unsigned_announcement.chain_hash);
let mut msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
let valid_announcement = ChannelAnnouncement {
node_signature_1: secp_ctx.sign(&msghash, node_1_privkey),
node_signature_2: secp_ctx.sign(&msghash, node_2_privkey),
bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey),
bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey),
contents: unsigned_announcement.clone(),
};
// Test if the UTXO lookups were not supported
*chain_monitor.utxo_ret.lock().unwrap() = Err(chaininterface::ChainError::NotSupported);
match router.handle_channel_announcement(&valid_announcement) {
Ok(res) => assert!(res),
_ => panic!()
};
{
let network = router.network_map.write().unwrap();
match network.channels.get(&channel_key) {
None => panic!(),
Some(_) => ()
}
}
// If we receive announcement for the same channel (with UTXO lookups disabled),
// drop new one on the floor, since we can't see any changes.
match router.handle_channel_announcement(&valid_announcement) {
Ok(_) => panic!(),
Err(e) => assert_eq!(e.err, "Already have knowledge of channel")
};
// Test if an associated transaction were not on-chain (or not confirmed).
*chain_monitor.utxo_ret.lock().unwrap() = Err(chaininterface::ChainError::UnknownTx);
unsigned_announcement.short_channel_id += 1;
msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
let valid_announcement = ChannelAnnouncement {
node_signature_1: secp_ctx.sign(&msghash, node_1_privkey),
node_signature_2: secp_ctx.sign(&msghash, node_2_privkey),
bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey),
bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey),
contents: unsigned_announcement.clone(),
};
match router.handle_channel_announcement(&valid_announcement) {
Ok(_) => panic!(),
Err(e) => assert_eq!(e.err, "Channel announced without corresponding UTXO entry")
};
// Now test if the transaction is found in the UTXO set and the script is correct.
unsigned_announcement.short_channel_id += 1;
*chain_monitor.utxo_ret.lock().unwrap() = Ok((good_script.clone(), 0));
let channel_key = NetworkMap::get_key(unsigned_announcement.short_channel_id,
unsigned_announcement.chain_hash);
msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
let valid_announcement = ChannelAnnouncement {
node_signature_1: secp_ctx.sign(&msghash, node_1_privkey),
node_signature_2: secp_ctx.sign(&msghash, node_2_privkey),
bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey),
bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey),
contents: unsigned_announcement.clone(),
};
match router.handle_channel_announcement(&valid_announcement) {
Ok(res) => assert!(res),
_ => panic!()
};
{
let network = router.network_map.write().unwrap();
match network.channels.get(&channel_key) {
None => panic!(),
Some(_) => ()
}
}
// If we receive announcement for the same channel (but TX is not confirmed),
// drop new one on the floor, since we can't see any changes.
*chain_monitor.utxo_ret.lock().unwrap() = Err(chaininterface::ChainError::UnknownTx);
match router.handle_channel_announcement(&valid_announcement) {
Ok(_) => panic!(),
Err(e) => assert_eq!(e.err, "Channel announced without corresponding UTXO entry")
};
// But if it is confirmed, replace the channel
*chain_monitor.utxo_ret.lock().unwrap() = Ok((good_script, 0));
unsigned_announcement.features = ChannelFeatures::empty();
msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
let valid_announcement = ChannelAnnouncement {
node_signature_1: secp_ctx.sign(&msghash, node_1_privkey),
node_signature_2: secp_ctx.sign(&msghash, node_2_privkey),
bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey),
bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey),
contents: unsigned_announcement.clone(),
};
match router.handle_channel_announcement(&valid_announcement) {
Ok(res) => assert!(res),
_ => panic!()
};
{
let mut network = router.network_map.write().unwrap();
match network.channels.entry(channel_key) {
BtreeEntry::Occupied(channel_entry) => {
assert_eq!(channel_entry.get().features, ChannelFeatures::empty());
},
_ => panic!()
}
}
// Don't relay valid channels with excess data
unsigned_announcement.short_channel_id += 1;
unsigned_announcement.excess_data.push(1);
msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
let valid_announcement = ChannelAnnouncement {
node_signature_1: secp_ctx.sign(&msghash, node_1_privkey),
node_signature_2: secp_ctx.sign(&msghash, node_2_privkey),
bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey),
bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey),
contents: unsigned_announcement.clone(),
};
match router.handle_channel_announcement(&valid_announcement) {
Ok(res) => assert!(!res),
_ => panic!()
};
unsigned_announcement.excess_data = Vec::new();
let invalid_sig_announcement = ChannelAnnouncement {
node_signature_1: secp_ctx.sign(&msghash, node_1_privkey),
node_signature_2: secp_ctx.sign(&msghash, node_2_privkey),
bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey),
bitcoin_signature_2: secp_ctx.sign(&msghash, node_1_btckey),
contents: unsigned_announcement.clone(),
};
match router.handle_channel_announcement(&invalid_sig_announcement) {
Ok(_) => panic!(),
Err(e) => assert_eq!(e.err, "Invalid signature from remote node")
};
unsigned_announcement.node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_2_privkey);
msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
let channel_to_itself_announcement = ChannelAnnouncement {
node_signature_1: secp_ctx.sign(&msghash, node_1_privkey),
node_signature_2: secp_ctx.sign(&msghash, node_1_privkey),
bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey),
bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey),
contents: unsigned_announcement.clone(),
};
match router.handle_channel_announcement(&channel_to_itself_announcement) {
Ok(_) => panic!(),
Err(e) => assert_eq!(e.err, "Channel announcement node had a channel with itself")
};
}
#[test]
fn handling_channel_update() {
let (secp_ctx, _, router) = create_router();
let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap();
let node_2_privkey = &SecretKey::from_slice(&[41; 32]).unwrap();
let node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_1_privkey);
let node_id_2 = PublicKey::from_secret_key(&secp_ctx, node_2_privkey);
let node_1_btckey = &SecretKey::from_slice(&[40; 32]).unwrap();
let node_2_btckey = &SecretKey::from_slice(&[39; 32]).unwrap();
let zero_hash = Sha256dHash::hash(&[0; 32]);
let short_channel_id = 0;
let chain_hash = genesis_block(Network::Testnet).header.bitcoin_hash();
let channel_key = NetworkMap::get_key(short_channel_id, chain_hash);
{
// Announce a channel we will update
let unsigned_announcement = UnsignedChannelAnnouncement {
features: ChannelFeatures::empty(),
chain_hash,
short_channel_id,
node_id_1,
node_id_2,
bitcoin_key_1: PublicKey::from_secret_key(&secp_ctx, node_1_btckey),
bitcoin_key_2: PublicKey::from_secret_key(&secp_ctx, node_2_btckey),
excess_data: Vec::new(),
};
let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
let valid_channel_announcement = ChannelAnnouncement {
node_signature_1: secp_ctx.sign(&msghash, node_1_privkey),
node_signature_2: secp_ctx.sign(&msghash, node_2_privkey),
bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey),
bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey),
contents: unsigned_announcement.clone(),
};
match router.handle_channel_announcement(&valid_channel_announcement) {
Ok(_) => (),
Err(_) => panic!()
};
}
let mut unsigned_channel_update = UnsignedChannelUpdate {
chain_hash,
short_channel_id,
timestamp: 100,
flags: 0,
cltv_expiry_delta: 144,
htlc_minimum_msat: 1000000,
fee_base_msat: 10000,
fee_proportional_millionths: 20,
excess_data: Vec::new()
};
let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_channel_update.encode()[..])[..]);
let valid_channel_update = ChannelUpdate {
signature: secp_ctx.sign(&msghash, node_1_privkey),
contents: unsigned_channel_update.clone()
};
match router.handle_channel_update(&valid_channel_update) {
Ok(res) => assert!(res),
_ => panic!()
};
{
let network = router.network_map.write().unwrap();
match network.channels.get(&channel_key) {
None => panic!(),
Some(channel_info) => {
assert_eq!(channel_info.one_to_two.cltv_expiry_delta, 144);
assert_eq!(channel_info.two_to_one.cltv_expiry_delta, u16::max_value());
}
}
}
unsigned_channel_update.timestamp += 100;
unsigned_channel_update.excess_data.push(1);
let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_channel_update.encode()[..])[..]);
let valid_channel_update = ChannelUpdate {
signature: secp_ctx.sign(&msghash, node_1_privkey),
contents: unsigned_channel_update.clone()
};
// Return false because contains excess data
match router.handle_channel_update(&valid_channel_update) {
Ok(res) => assert!(!res),
_ => panic!()
};
unsigned_channel_update.short_channel_id += 1;
let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_channel_update.encode()[..])[..]);
let valid_channel_update = ChannelUpdate {
signature: secp_ctx.sign(&msghash, node_1_privkey),
contents: unsigned_channel_update.clone()
};
match router.handle_channel_update(&valid_channel_update) {
Ok(_) => panic!(),
Err(e) => assert_eq!(e.err, "Couldn't find channel for update")
};
unsigned_channel_update.short_channel_id = short_channel_id;
// Even though previous update was not relayed further, we still accepted it,
// so we now won't accept update before the previous one.
unsigned_channel_update.timestamp -= 10;
let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_channel_update.encode()[..])[..]);
let valid_channel_update = ChannelUpdate {
signature: secp_ctx.sign(&msghash, node_1_privkey),
contents: unsigned_channel_update.clone()
};
match router.handle_channel_update(&valid_channel_update) {
Ok(_) => panic!(),
Err(e) => assert_eq!(e.err, "Update older than last processed update")
};
unsigned_channel_update.timestamp += 500;
let fake_msghash = hash_to_message!(&zero_hash);
let invalid_sig_channel_update = ChannelUpdate {
signature: secp_ctx.sign(&fake_msghash, node_1_privkey),
contents: unsigned_channel_update.clone()
};
match router.handle_channel_update(&invalid_sig_channel_update) {
Ok(_) => panic!(),
Err(e) => assert_eq!(e.err, "Invalid signature from remote node")
};
}
#[test]
fn handling_htlc_fail_channel_update() {
let (secp_ctx, our_id, router) = create_router();
let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap();
let node_2_privkey = &SecretKey::from_slice(&[41; 32]).unwrap();
let node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_1_privkey);
let node_id_2 = PublicKey::from_secret_key(&secp_ctx, node_2_privkey);
let node_1_btckey = &SecretKey::from_slice(&[40; 32]).unwrap();
let node_2_btckey = &SecretKey::from_slice(&[39; 32]).unwrap();
let short_channel_id = 0;
let chain_hash = genesis_block(Network::Testnet).header.bitcoin_hash();
let channel_key = NetworkMap::get_key(short_channel_id, chain_hash);
{
// There is only local node in the table at the beginning.
let network = router.network_map.read().unwrap();
assert_eq!(network.nodes.len(), 1);
assert_eq!(network.nodes.contains_key(&our_id), true);
}
{
// Announce a channel we will update
let unsigned_announcement = UnsignedChannelAnnouncement {
features: ChannelFeatures::empty(),
chain_hash,
short_channel_id,
node_id_1,
node_id_2,
bitcoin_key_1: PublicKey::from_secret_key(&secp_ctx, node_1_btckey),
bitcoin_key_2: PublicKey::from_secret_key(&secp_ctx, node_2_btckey),
excess_data: Vec::new(),
};
let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
let valid_channel_announcement = ChannelAnnouncement {
node_signature_1: secp_ctx.sign(&msghash, node_1_privkey),
node_signature_2: secp_ctx.sign(&msghash, node_2_privkey),
bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey),
bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey),
contents: unsigned_announcement.clone(),
};
match router.handle_channel_announcement(&valid_channel_announcement) {
Ok(_) => (),
Err(_) => panic!()
};
}
let channel_close_msg = HTLCFailChannelUpdate::ChannelClosed {
short_channel_id,
is_permanent: false
};
router.handle_htlc_fail_channel_update(&channel_close_msg);
{
// Non-permanent closing just disables a channel
let network = router.network_map.write().unwrap();
match network.channels.get(&channel_key) {
None => panic!(),
Some(channel_info) => {
assert!(!channel_info.one_to_two.enabled);
assert!(!channel_info.two_to_one.enabled);
}
}
}
let channel_close_msg = HTLCFailChannelUpdate::ChannelClosed {
short_channel_id,
is_permanent: true
};
router.handle_htlc_fail_channel_update(&channel_close_msg);
{
// Permanent closing deletes a channel
let network = router.network_map.read().unwrap();
assert_eq!(network.channels.len(), 0);
// Nodes are also deleted because there are no associated channels anymore
// Only the local node remains in the table.
assert_eq!(network.nodes.len(), 1);
assert_eq!(network.nodes.contains_key(&our_id), true);
}
// TODO: Test HTLCFailChannelUpdate::NodeFailure, which is not implemented yet.
}
#[test]
fn getting_next_channel_announcements() {
let (secp_ctx, _, router) = create_router();
let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap();
let node_2_privkey = &SecretKey::from_slice(&[41; 32]).unwrap();
let node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_1_privkey);
let node_id_2 = PublicKey::from_secret_key(&secp_ctx, node_2_privkey);
let node_1_btckey = &SecretKey::from_slice(&[40; 32]).unwrap();
let node_2_btckey = &SecretKey::from_slice(&[39; 32]).unwrap();
let short_channel_id = 1;
let chain_hash = genesis_block(Network::Testnet).header.bitcoin_hash();
let channel_key = NetworkMap::get_key(short_channel_id, chain_hash);
// Channels were not announced yet.
let channels_with_announcements = router.get_next_channel_announcements(0, 1);
assert_eq!(channels_with_announcements.len(), 0);
{
// Announce a channel we will update
let unsigned_announcement = UnsignedChannelAnnouncement {
features: ChannelFeatures::empty(),
chain_hash,
short_channel_id,
node_id_1,
node_id_2,
bitcoin_key_1: PublicKey::from_secret_key(&secp_ctx, node_1_btckey),
bitcoin_key_2: PublicKey::from_secret_key(&secp_ctx, node_2_btckey),
excess_data: Vec::new(),
};
let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
let valid_channel_announcement = ChannelAnnouncement {
node_signature_1: secp_ctx.sign(&msghash, node_1_privkey),
node_signature_2: secp_ctx.sign(&msghash, node_2_privkey),
bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey),
bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey),
contents: unsigned_announcement.clone(),
};
match router.handle_channel_announcement(&valid_channel_announcement) {
Ok(_) => (),
Err(_) => panic!()
};
}
// Contains initial channel announcement now.
let channels_with_announcements = router.get_next_channel_announcements(channel_key, 1);
assert_eq!(channels_with_announcements.len(), 1);
if let Some(channel_announcements) = channels_with_announcements.first() {
let &(_, ref update_1, ref update_2) = channel_announcements;
assert_eq!(update_1, &None);
assert_eq!(update_2, &None);
} else {
panic!();
}
{
// Valid channel update
let unsigned_channel_update = UnsignedChannelUpdate {
chain_hash,
short_channel_id,
timestamp: 101,
flags: 0,
cltv_expiry_delta: 144,
htlc_minimum_msat: 1000000,
fee_base_msat: 10000,
fee_proportional_millionths: 20,
excess_data: Vec::new()
};
let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_channel_update.encode()[..])[..]);
let valid_channel_update = ChannelUpdate {
signature: secp_ctx.sign(&msghash, node_1_privkey),
contents: unsigned_channel_update.clone()
};
match router.handle_channel_update(&valid_channel_update) {
Ok(_) => (),
Err(_) => panic!()
};
}
// Now contains an initial announcement and an update.
let channels_with_announcements = router.get_next_channel_announcements(channel_key, 1);
assert_eq!(channels_with_announcements.len(), 1);
if let Some(channel_announcements) = channels_with_announcements.first() {
let &(_, ref update_1, ref update_2) = channel_announcements;
assert_ne!(update_1, &None);
assert_eq!(update_2, &None);
} else {
panic!();
}
{
// Channel update with excess data.
let unsigned_channel_update = UnsignedChannelUpdate {
chain_hash,
short_channel_id,
timestamp: 102,
flags: 0,
cltv_expiry_delta: 144,
htlc_minimum_msat: 1000000,
fee_base_msat: 10000,
fee_proportional_millionths: 20,
excess_data: [1; 3].to_vec()
};
let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_channel_update.encode()[..])[..]);
let valid_channel_update = ChannelUpdate {
signature: secp_ctx.sign(&msghash, node_1_privkey),
contents: unsigned_channel_update.clone()
};
match router.handle_channel_update(&valid_channel_update) {
Ok(_) => (),
Err(_) => panic!()
};
}
// Test that announcements with excess data won't be returned
let channels_with_announcements = router.get_next_channel_announcements(channel_key, 1);
assert_eq!(channels_with_announcements.len(), 1);
if let Some(channel_announcements) = channels_with_announcements.first() {
let &(_, ref update_1, ref update_2) = channel_announcements;
assert_eq!(update_1, &None);
assert_eq!(update_2, &None);
} else {
panic!();
}
// Further starting point have no channels after it
let channels_with_announcements = router.get_next_channel_announcements(channel_key + 1000, 1);
assert_eq!(channels_with_announcements.len(), 0);
}
#[test]
fn getting_next_node_announcements() {
let (secp_ctx, _, router) = create_router();
let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap();
let node_2_privkey = &SecretKey::from_slice(&[41; 32]).unwrap();
let node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_1_privkey);
let node_id_2 = PublicKey::from_secret_key(&secp_ctx, node_2_privkey);
let node_1_btckey = &SecretKey::from_slice(&[40; 32]).unwrap();
let node_2_btckey = &SecretKey::from_slice(&[39; 32]).unwrap();
let short_channel_id = 1;
let chain_hash = genesis_block(Network::Testnet).header.bitcoin_hash();
// No nodes yet.
let next_announcements = router.get_next_node_announcements(None, 10);
assert_eq!(next_announcements.len(), 0);
{
// Announce a channel to add 2 nodes
let unsigned_announcement = UnsignedChannelAnnouncement {
features: ChannelFeatures::empty(),
chain_hash,
short_channel_id,
node_id_1,
node_id_2,
bitcoin_key_1: PublicKey::from_secret_key(&secp_ctx, node_1_btckey),
bitcoin_key_2: PublicKey::from_secret_key(&secp_ctx, node_2_btckey),
excess_data: Vec::new(),
};
let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
let valid_channel_announcement = ChannelAnnouncement {
node_signature_1: secp_ctx.sign(&msghash, node_1_privkey),
node_signature_2: secp_ctx.sign(&msghash, node_2_privkey),
bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey),
bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey),
contents: unsigned_announcement.clone(),
};
match router.handle_channel_announcement(&valid_channel_announcement) {
Ok(_) => (),
Err(_) => panic!()
};
}
// Nodes were never announced
let next_announcements = router.get_next_node_announcements(None, 3);
assert_eq!(next_announcements.len(), 0);
{
let mut unsigned_announcement = UnsignedNodeAnnouncement {
features: NodeFeatures::supported(),
timestamp: 1000,
node_id: node_id_1,
rgb: [0; 3],
alias: [0; 32],
addresses: Vec::new(),
excess_address_data: Vec::new(),
excess_data: Vec::new(),
};
let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
let valid_announcement = NodeAnnouncement {
signature: secp_ctx.sign(&msghash, node_1_privkey),
contents: unsigned_announcement.clone()
};
match router.handle_node_announcement(&valid_announcement) {
Ok(_) => (),
Err(_) => panic!()
};
unsigned_announcement.node_id = node_id_2;
let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
let valid_announcement = NodeAnnouncement {
signature: secp_ctx.sign(&msghash, node_2_privkey),
contents: unsigned_announcement.clone()
};
match router.handle_node_announcement(&valid_announcement) {
Ok(_) => (),
Err(_) => panic!()
};
}
let next_announcements = router.get_next_node_announcements(None, 3);
assert_eq!(next_announcements.len(), 2);
// Skip the first node.
let next_announcements = router.get_next_node_announcements(Some(&node_id_1), 2);
assert_eq!(next_announcements.len(), 1);
{
// Later announcement which should not be relayed (excess data) prevent us from sharing a node
let unsigned_announcement = UnsignedNodeAnnouncement {
features: NodeFeatures::supported(),
timestamp: 1010,
node_id: node_id_2,
rgb: [0; 3],
alias: [0; 32],
addresses: Vec::new(),
excess_address_data: Vec::new(),
excess_data: [1; 3].to_vec(),
};
let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
let valid_announcement = NodeAnnouncement {
signature: secp_ctx.sign(&msghash, node_2_privkey),
contents: unsigned_announcement.clone()
};
match router.handle_node_announcement(&valid_announcement) {
Ok(res) => assert!(!res),
Err(_) => panic!()
};
}
let next_announcements = router.get_next_node_announcements(Some(&node_id_1), 2);
assert_eq!(next_announcements.len(), 0);
}
}

View file

@ -1,5 +1,5 @@
use chain::chaininterface;
use chain::chaininterface::ConfirmationTarget;
use chain::chaininterface::{ConfirmationTarget, ChainError, ChainWatchInterface};
use chain::transaction::OutPoint;
use chain::keysinterface;
use ln::channelmonitor;
@ -13,7 +13,9 @@ use util::logger::{Logger, Level, Record};
use util::ser::{Readable, ReadableArgs, Writer, Writeable};
use bitcoin::blockdata::transaction::Transaction;
use bitcoin::blockdata::script::Script;
use bitcoin::blockdata::script::{Builder, Script};
use bitcoin::blockdata::block::Block;
use bitcoin::blockdata::opcodes;
use bitcoin_hashes::sha256d::Hash as Sha256dHash;
use bitcoin::network::constants::Network;
@ -176,7 +178,7 @@ impl msgs::RoutingMessageHandler for TestRoutingMessageHandler {
Err(LightningError { err: "", action: msgs::ErrorAction::IgnoreError })
}
fn handle_htlc_fail_channel_update(&self, _update: &msgs::HTLCFailChannelUpdate) {}
fn get_next_channel_announcements(&self, _starting_point: u64, _batch_amount: u8) -> Vec<(msgs::ChannelAnnouncement, msgs::ChannelUpdate,msgs::ChannelUpdate)> {
fn get_next_channel_announcements(&self, _starting_point: u64, _batch_amount: u8) -> Vec<(msgs::ChannelAnnouncement, Option<msgs::ChannelUpdate>, Option<msgs::ChannelUpdate>)> {
Vec::new()
}
fn get_next_node_announcements(&self, _starting_point: Option<&PublicKey>, _batch_amount: u8) -> Vec<msgs::NodeAnnouncement> {
@ -263,3 +265,28 @@ impl TestKeysInterface {
}
}
}
pub struct TestChainWatcher {
pub utxo_ret: Mutex<Result<(Script, u64), ChainError>>,
}
impl TestChainWatcher {
pub fn new() -> Self {
let script = Builder::new().push_opcode(opcodes::OP_TRUE).into_script();
Self { utxo_ret: Mutex::new(Ok((script, u64::max_value()))) }
}
}
impl ChainWatchInterface for TestChainWatcher {
fn install_watch_tx(&self, _txid: &Sha256dHash, _script_pub_key: &Script) { }
fn install_watch_outpoint(&self, _outpoint: (Sha256dHash, u32), _out_script: &Script) { }
fn watch_all_txn(&self) { }
fn filter_block<'a>(&self, _block: &'a Block) -> (Vec<&'a Transaction>, Vec<u32>) {
(Vec::new(), Vec::new())
}
fn reentered(&self) -> usize { 0 }
fn get_chain_utxo(&self, _genesis_hash: Sha256dHash, _unspent_tx_output_identifier: u64) -> Result<(Script, u64), ChainError> {
self.utxo_ret.lock().unwrap().clone()
}
}