X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=src%2Fln%2Fchannelmanager.rs;h=f12c3f7ac4a8c31b40362b971ad826ae643d96a3;hb=c578e4a346efb4361b53d18525bdb74de07cbae8;hp=20e6f3739ec63ee3eee62715cd21bb8a21f4805e;hpb=a66e597e958584b7fbfff8f5891d656010cd58fa;p=rust-lightning diff --git a/src/ln/channelmanager.rs b/src/ln/channelmanager.rs index 20e6f373..f12c3f7a 100644 --- a/src/ln/channelmanager.rs +++ b/src/ln/channelmanager.rs @@ -50,11 +50,17 @@ mod channel_held_info { pub(super) outgoing_cltv_value: u32, } + #[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug + pub enum HTLCFailureMsg { + Relay(msgs::UpdateFailHTLC), + Malformed(msgs::UpdateFailMalformedHTLC), + } + /// Stores whether we can't forward an HTLC or relevant forwarding info #[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug pub enum PendingHTLCStatus { Forward(PendingForwardHTLCInfo), - Fail(msgs::UpdateFailHTLC), + Fail(HTLCFailureMsg), } #[cfg(feature = "fuzztarget")] @@ -114,6 +120,32 @@ enum PendingOutboundHTLC { } } +struct MsgHandleErrInternal { + err: msgs::HandleError, + needs_channel_force_close: bool, +} +impl MsgHandleErrInternal { + #[inline] + fn send_err_msg_no_close(err: &'static str, channel_id: [u8; 32]) -> Self { + Self { + err: HandleError { + err, + action: Some(msgs::ErrorAction::SendErrorMessage { + msg: msgs::ErrorMessage { + channel_id, + data: err.to_string() + }, + }), + }, + needs_channel_force_close: false, + } + } + #[inline] + fn from_no_close(err: msgs::HandleError) -> Self { + Self { err, needs_channel_force_close: false } + } +} + /// We hold back HTLCs we intend to relay for a random interval in the range (this, 5*this). This /// provides some limited amount of privacy. Ideally this would range from somewhere like 1 second /// to 30 seconds, but people expect lightning to be, you know, kinda fast, sadly. We could @@ -183,11 +215,10 @@ pub struct ChannelManager { const CLTV_EXPIRY_DELTA: u16 = 6 * 24 * 2; //TODO? macro_rules! secp_call { - ( $res : expr ) => { + ( $res: expr, $err_msg: expr, $action: expr ) => { match $res { Ok(key) => key, - //TODO: Make the err a parameter! - Err(_) => return Err(HandleError{err: "Key error", action: None}) + Err(_) => return Err(HandleError{err: $err_msg, action: Some($action)}) } }; } @@ -469,10 +500,9 @@ impl ChannelManager { // can only fail if an intermediary hop has an invalid public key or session_priv is invalid #[inline] - fn construct_onion_keys_callback (secp_ctx: &Secp256k1, route: &Route, session_priv: &SecretKey, mut callback: FType) -> Result<(), HandleError> { + fn construct_onion_keys_callback (secp_ctx: &Secp256k1, route: &Route, session_priv: &SecretKey, mut callback: FType) -> Result<(), secp256k1::Error> { let mut blinded_priv = session_priv.clone(); let mut blinded_pub = PublicKey::from_secret_key(secp_ctx, &blinded_priv); - let mut first_iteration = true; for hop in route.hops.iter() { let shared_secret = SharedSecret::new(secp_ctx, &hop.pubkey, &blinded_priv); @@ -483,13 +513,9 @@ impl ChannelManager { let mut blinding_factor = [0u8; 32]; sha.result(&mut blinding_factor); - if first_iteration { - blinded_pub = PublicKey::from_secret_key(secp_ctx, &blinded_priv); - first_iteration = false; - } let ephemeral_pubkey = blinded_pub; - secp_call!(blinded_priv.mul_assign(secp_ctx, &secp_call!(SecretKey::from_slice(secp_ctx, &blinding_factor)))); + blinded_priv.mul_assign(secp_ctx, &SecretKey::from_slice(secp_ctx, &blinding_factor)?)?; blinded_pub = PublicKey::from_secret_key(secp_ctx, &blinded_priv); callback(shared_secret, blinding_factor, ephemeral_pubkey, hop); @@ -499,7 +525,7 @@ impl ChannelManager { } // can only fail if an intermediary hop has an invalid public key or session_priv is invalid - fn construct_onion_keys(secp_ctx: &Secp256k1, route: &Route, session_priv: &SecretKey) -> Result, HandleError> { + fn construct_onion_keys(secp_ctx: &Secp256k1, route: &Route, session_priv: &SecretKey) -> Result, secp256k1::Error> { let mut res = Vec::with_capacity(route.hops.len()); Self::construct_onion_keys_callback(secp_ctx, route, session_priv, |shared_secret, _blinding_factor, ephemeral_pubkey, _| { @@ -619,7 +645,7 @@ impl ChannelManager { Ok(msgs::OnionPacket{ version: 0, - public_key: onion_keys.first().unwrap().ephemeral_pubkey, + public_key: Ok(onion_keys.first().unwrap().ephemeral_pubkey), hop_data: packet_data, hmac: hmac_res, }) @@ -675,10 +701,7 @@ impl ChannelManager { ChannelManager::encrypt_failure_packet(shared_secret, &failure_packet.encode()[..]) } - fn decode_update_add_htlc_onion(&self, msg: &msgs::UpdateAddHTLC) -> (PendingHTLCStatus, SharedSecret, MutexGuard) { - let shared_secret = SharedSecret::new(&self.secp_ctx, &msg.onion_routing_packet.public_key, &self.our_network_key); - let (rho, mu) = ChannelManager::gen_rho_mu_from_shared_secret(&shared_secret); - + fn decode_update_add_htlc_onion(&self, msg: &msgs::UpdateAddHTLC) -> (PendingHTLCStatus, Option, MutexGuard) { macro_rules! get_onion_hash { () => { { @@ -691,6 +714,19 @@ impl ChannelManager { } } + if let Err(_) = msg.onion_routing_packet.public_key { + log_info!(self, "Failed to accept/forward incoming HTLC with invalid ephemeral pubkey"); + return (PendingHTLCStatus::Fail(HTLCFailureMsg::Malformed(msgs::UpdateFailMalformedHTLC { + channel_id: msg.channel_id, + htlc_id: msg.htlc_id, + sha256_of_onion: get_onion_hash!(), + failure_code: 0x8000 | 0x4000 | 6, + })), None, self.channel_state.lock().unwrap()); + } + + let shared_secret = SharedSecret::new(&self.secp_ctx, &msg.onion_routing_packet.public_key.unwrap(), &self.our_network_key); + let (rho, mu) = ChannelManager::gen_rho_mu_from_shared_secret(&shared_secret); + let mut channel_state = None; macro_rules! return_err { ($msg: expr, $err_code: expr, $data: expr) => { @@ -699,11 +735,11 @@ impl ChannelManager { if channel_state.is_none() { channel_state = Some(self.channel_state.lock().unwrap()); } - return (PendingHTLCStatus::Fail(msgs::UpdateFailHTLC { + return (PendingHTLCStatus::Fail(HTLCFailureMsg::Relay(msgs::UpdateFailHTLC { channel_id: msg.channel_id, htlc_id: msg.htlc_id, reason: ChannelManager::build_first_hop_failure_packet(&shared_secret, $err_code, $data), - }), shared_secret, channel_state.unwrap()); + })), Some(shared_secret), channel_state.unwrap()); } } } @@ -770,7 +806,7 @@ impl ChannelManager { chacha.process(&msg.onion_routing_packet.hop_data[65..], &mut new_packet_data[0..19*65]); chacha.process(&ChannelManager::ZERO[0..65], &mut new_packet_data[19*65..]); - let mut new_pubkey = msg.onion_routing_packet.public_key.clone(); + let mut new_pubkey = msg.onion_routing_packet.public_key.unwrap(); let blinding_factor = { let mut sha = Sha256::new(); @@ -780,26 +816,19 @@ impl ChannelManager { sha.result(&mut res); match SecretKey::from_slice(&self.secp_ctx, &res) { Err(_) => { - // Return temporary node failure as its technically our issue, not the - // channel's issue. - return_err!("Blinding factor is an invalid private key", 0x2000 | 2, &[0;0]); + return_err!("Blinding factor is an invalid private key", 0x8000 | 0x4000 | 6, &get_onion_hash!()); }, Ok(key) => key } }; - match new_pubkey.mul_assign(&self.secp_ctx, &blinding_factor) { - Err(_) => { - // Return temporary node failure as its technically our issue, not the - // channel's issue. - return_err!("New blinding factor is an invalid private key", 0x2000 | 2, &[0;0]); - }, - Ok(_) => {} - }; + if let Err(_) = new_pubkey.mul_assign(&self.secp_ctx, &blinding_factor) { + return_err!("New blinding factor is an invalid private key", 0x8000 | 0x4000 | 6, &get_onion_hash!()); + } let outgoing_packet = msgs::OnionPacket { version: 0, - public_key: new_pubkey, + public_key: Ok(new_pubkey), hop_data: new_packet_data, hmac: next_hop_data.hmac.clone(), }; @@ -846,7 +875,7 @@ impl ChannelManager { } } - (pending_forward_info, shared_secret, channel_state.unwrap()) + (pending_forward_info, Some(shared_secret), channel_state.unwrap()) } /// only fails if the channel does not yet have an assigned short_id @@ -867,6 +896,7 @@ impl ChannelManager { htlc_minimum_msat: chan.get_our_htlc_minimum_msat(), fee_base_msat: chan.get_our_fee_base_msat(&*self.fee_estimator), fee_proportional_millionths: self.fee_proportional_millionths, + excess_data: Vec::new(), }; let msg_hash = Sha256dHash::from_data(&unsigned.encode()[..]); @@ -900,15 +930,17 @@ impl ChannelManager { } } - let session_priv = secp_call!(SecretKey::from_slice(&self.secp_ctx, &{ + let session_priv = SecretKey::from_slice(&self.secp_ctx, &{ let mut session_key = [0; 32]; rng::fill_bytes(&mut session_key); session_key - })); + }).expect("RNG is bad!"); let cur_height = self.latest_block_height.load(Ordering::Acquire) as u32 + 1; - let onion_keys = ChannelManager::construct_onion_keys(&self.secp_ctx, &route, &session_priv)?; + //TODO: This should return something other than HandleError, that's really intended for + //p2p-returns only. + let onion_keys = secp_call!(ChannelManager::construct_onion_keys(&self.secp_ctx, &route, &session_priv), "Pubkey along hop was maliciously selected", msgs::ErrorAction::IgnoreError); let (onion_payloads, htlc_msat, htlc_cltv) = ChannelManager::build_onion_payloads(&route, cur_height)?; let onion_packet = ChannelManager::construct_onion_packet(onion_payloads, onion_keys, &payment_hash)?; @@ -958,6 +990,7 @@ impl ChannelManager { update_add_htlcs: vec![update_add], update_fulfill_htlcs: Vec::new(), update_fail_htlcs: Vec::new(), + update_fail_malformed_htlcs: Vec::new(), commitment_signed, }, }); @@ -1020,19 +1053,22 @@ impl ChannelManager { } } - fn get_announcement_sigs(&self, chan: &Channel) -> Result, HandleError> { - if !chan.is_usable() || !chan.should_announce() { return Ok(None) } + fn get_announcement_sigs(&self, chan: &Channel) -> Option { + if !chan.should_announce() { return None } - let (announcement, our_bitcoin_sig) = chan.get_channel_announcement(self.get_our_node_id(), self.genesis_hash.clone())?; + let (announcement, our_bitcoin_sig) = match chan.get_channel_announcement(self.get_our_node_id(), self.genesis_hash.clone()) { + Ok(res) => res, + Err(_) => return None, // Only in case of state precondition violations eg channel is closing + }; let msghash = Message::from_slice(&Sha256dHash::from_data(&announcement.encode()[..])[..]).unwrap(); let our_node_sig = self.secp_ctx.sign(&msghash, &self.our_network_key); - Ok(Some(msgs::AnnouncementSignatures { + Some(msgs::AnnouncementSignatures { channel_id: chan.channel_id(), short_channel_id: chan.get_short_channel_id().unwrap(), node_signature: our_node_sig, bitcoin_signature: our_bitcoin_sig, - })) + }) } /// Processes HTLCs which are pending waiting on random forward delay. @@ -1102,6 +1138,7 @@ impl ChannelManager { update_add_htlcs: add_htlc_msgs, update_fulfill_htlcs: Vec::new(), update_fail_htlcs: Vec::new(), + update_fail_malformed_htlcs: Vec::new(), commitment_signed: commitment_msg, }, })); @@ -1225,6 +1262,7 @@ impl ChannelManager { update_add_htlcs: Vec::new(), update_fulfill_htlcs: Vec::new(), update_fail_htlcs: vec![msg], + update_fail_malformed_htlcs: Vec::new(), commitment_signed: commitment_msg, }, }); @@ -1324,6 +1362,7 @@ impl ChannelManager { update_add_htlcs: Vec::new(), update_fulfill_htlcs: vec![msg], update_fail_htlcs: Vec::new(), + update_fail_malformed_htlcs: Vec::new(), commitment_signed: commitment_msg, } }); @@ -1366,14 +1405,7 @@ impl ChainListener for ChannelManager { channel_state.by_id.retain(|_, channel| { let chan_res = channel.block_connected(header, height, txn_matched, indexes_of_txn_matched); if let Ok(Some(funding_locked)) = chan_res { - let announcement_sigs = match self.get_announcement_sigs(channel) { - Ok(res) => res, - Err(e) => { - log_error!(self, "Got error handling message: {}!", e.err); - //TODO: push e on events and blow up the channel (it has bad keys) - return true; - } - }; + let announcement_sigs = self.get_announcement_sigs(channel); new_events.push(events::Event::SendFundingLocked { node_id: channel.get_their_node_id(), msg: funding_locked, @@ -1477,6 +1509,38 @@ impl ChainListener for ChannelManager { } } +macro_rules! handle_error { + ($self: ident, $internal: expr, $their_node_id: expr) => { + match $internal { + Ok(msg) => Ok(msg), + Err(MsgHandleErrInternal { err, needs_channel_force_close }) => { + if needs_channel_force_close { + match &err.action { + &Some(msgs::ErrorAction::DisconnectPeer { msg: Some(ref msg) }) => { + if msg.channel_id == [0; 32] { + $self.peer_disconnected(&$their_node_id, true); + } else { + $self.force_close_channel(&msg.channel_id); + } + }, + &Some(msgs::ErrorAction::DisconnectPeer { msg: None }) => {}, + &Some(msgs::ErrorAction::IgnoreError) => {}, + &Some(msgs::ErrorAction::SendErrorMessage { ref msg }) => { + if msg.channel_id == [0; 32] { + $self.peer_disconnected(&$their_node_id, true); + } else { + $self.force_close_channel(&msg.channel_id); + } + }, + &None => {}, + } + } + Err(err) + }, + } + } +} + impl ChannelMessageHandler for ChannelManager { //TODO: Handle errors and close channel (or so) fn handle_open_channel(&self, their_node_id: &PublicKey, msg: &msgs::OpenChannel) -> Result { @@ -1613,7 +1677,7 @@ impl ChannelMessageHandler for ChannelManager { return Err(HandleError{err: "Got a message for a channel from the wrong node!", action: None}) } chan.funding_locked(&msg)?; - return Ok(self.get_announcement_sigs(chan)?); + return Ok(self.get_announcement_sigs(chan)); }, None => return Err(HandleError{err: "Failed to find corresponding channel", action: None}) }; @@ -1722,11 +1786,11 @@ impl ChannelMessageHandler for ChannelManager { } if !acceptable_cycle { log_info!(self, "Failed to accept incoming HTLC: Payment looped through us twice"); - pending_forward_info = PendingHTLCStatus::Fail(msgs::UpdateFailHTLC { + pending_forward_info = PendingHTLCStatus::Fail(HTLCFailureMsg::Relay(msgs::UpdateFailHTLC { channel_id: msg.channel_id, htlc_id: msg.htlc_id, - reason: ChannelManager::build_first_hop_failure_packet(&shared_secret, 0x4000 | 0x2000 | 2, &[0;0]), - }); + reason: ChannelManager::build_first_hop_failure_packet(&shared_secret.unwrap(), 0x4000 | 0x2000 | 2, &[0;0]), + })); } else { will_forward = true; } @@ -1764,7 +1828,7 @@ impl ChannelMessageHandler for ChannelManager { }; *outbound_route = PendingOutboundHTLC::CycledRoute { source_short_channel_id, - incoming_packet_shared_secret: shared_secret, + incoming_packet_shared_secret: shared_secret.unwrap(), route, session_priv, }; @@ -1772,7 +1836,7 @@ impl ChannelMessageHandler for ChannelManager { hash_map::Entry::Vacant(e) => { e.insert(PendingOutboundHTLC::IntermediaryHopData { source_short_channel_id, - incoming_packet_shared_secret: shared_secret, + incoming_packet_shared_secret: shared_secret.unwrap(), }); } } @@ -1977,10 +2041,10 @@ impl ChannelMessageHandler for ChannelManager { match channel_state.by_id.get_mut(&msg.channel_id) { Some(chan) => { if chan.get_their_node_id() != *their_node_id { - return Err(HandleError{err: "Got a message for a channel from the wrong node!", action: None}) + return Err(HandleError{err: "Got a message for a channel from the wrong node!", action: Some(msgs::ErrorAction::IgnoreError) }) } if !chan.is_usable() { - return Err(HandleError{err: "Got an announcement_signatures before we were ready for it", action: None }); + return Err(HandleError{err: "Got an announcement_signatures before we were ready for it", action: Some(msgs::ErrorAction::IgnoreError) }); } let our_node_id = self.get_our_node_id(); @@ -1988,8 +2052,9 @@ impl ChannelMessageHandler for ChannelManager { let were_node_one = announcement.node_id_1 == our_node_id; let msghash = Message::from_slice(&Sha256dHash::from_data(&announcement.encode()[..])[..]).unwrap(); - secp_call!(self.secp_ctx.verify(&msghash, &msg.node_signature, if were_node_one { &announcement.node_id_2 } else { &announcement.node_id_1 })); - secp_call!(self.secp_ctx.verify(&msghash, &msg.bitcoin_signature, if were_node_one { &announcement.bitcoin_key_2 } else { &announcement.bitcoin_key_1 })); + let bad_sig_action = msgs::ErrorAction::SendErrorMessage { msg: msgs::ErrorMessage { channel_id: msg.channel_id.clone(), data: "Invalid signature in announcement_signatures".to_string() } }; + secp_call!(self.secp_ctx.verify(&msghash, &msg.node_signature, if were_node_one { &announcement.node_id_2 } else { &announcement.node_id_1 }), "Bad announcement_signatures node_signature", bad_sig_action); + secp_call!(self.secp_ctx.verify(&msghash, &msg.bitcoin_signature, if were_node_one { &announcement.bitcoin_key_2 } else { &announcement.bitcoin_key_1 }), "Bad announcement_signatures bitcoin_signature", bad_sig_action); let our_node_sig = self.secp_ctx.sign(&msghash, &self.our_network_key); @@ -2001,7 +2066,7 @@ impl ChannelMessageHandler for ChannelManager { contents: announcement, }, self.get_channel_update(chan).unwrap()) // can only fail if we're not in a ready state }, - None => return Err(HandleError{err: "Failed to find corresponding channel", action: None}) + None => return Err(HandleError{err: "Failed to find corresponding channel", action: Some(msgs::ErrorAction::IgnoreError)}) } }; let mut pending_events = self.pending_events.lock().unwrap(); @@ -2053,6 +2118,18 @@ impl ChannelMessageHandler for ChannelManager { } } } + + fn handle_error(&self, their_node_id: &PublicKey, msg: &msgs::ErrorMessage) { + if msg.channel_id == [0; 32] { + for chan in self.list_channels() { + if chan.remote_network_id == *their_node_id { + self.force_close_channel(&chan.channel_id); + } + } + } else { + self.force_close_channel(&msg.channel_id); + } + } } #[cfg(test)] @@ -2071,13 +2148,14 @@ mod tests { use bitcoin::util::hash::Sha256dHash; use bitcoin::blockdata::block::{Block, BlockHeader}; use bitcoin::blockdata::transaction::{Transaction, TxOut}; + use bitcoin::blockdata::constants::genesis_block; use bitcoin::network::constants::Network; use bitcoin::network::serialize::serialize; use bitcoin::network::serialize::BitcoinHash; use hex; - use secp256k1::Secp256k1; + use secp256k1::{Secp256k1, Message}; use secp256k1::key::{PublicKey,SecretKey}; use crypto::sha2::Sha256; @@ -2252,11 +2330,9 @@ mod tests { } struct Node { - feeest: Arc, chain_monitor: Arc, tx_broadcaster: Arc, chan_monitor: Arc, - node_id: SecretKey, node: Arc, router: Router, } @@ -2476,9 +2552,10 @@ mod tests { impl SendEvent { fn from_event(event: Event) -> SendEvent { match event { - Event::UpdateHTLCs { node_id, updates: msgs::CommitmentUpdate { update_add_htlcs, update_fulfill_htlcs, update_fail_htlcs, commitment_signed } } => { + Event::UpdateHTLCs { node_id, updates: msgs::CommitmentUpdate { update_add_htlcs, update_fulfill_htlcs, update_fail_htlcs, update_fail_malformed_htlcs, commitment_signed } } => { assert!(update_fulfill_htlcs.is_empty()); assert!(update_fail_htlcs.is_empty()); + assert!(update_fail_malformed_htlcs.is_empty()); SendEvent { node_id: node_id, msgs: update_add_htlcs, commitment_msg: commitment_signed } }, _ => panic!("Unexpected event type!"), @@ -2635,10 +2712,11 @@ mod tests { let events = node.node.get_and_clear_pending_events(); assert_eq!(events.len(), 1); match events[0] { - Event::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref commitment_signed } } => { + Event::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref commitment_signed } } => { assert!(update_add_htlcs.is_empty()); assert_eq!(update_fulfill_htlcs.len(), 1); assert!(update_fail_htlcs.is_empty()); + assert!(update_fail_malformed_htlcs.is_empty()); expected_next_node = node_id.clone(); next_msgs = Some((update_fulfill_htlcs[0].clone(), commitment_signed.clone())); }, @@ -2759,10 +2837,11 @@ mod tests { let events = node.node.get_and_clear_pending_events(); assert_eq!(events.len(), 1); match events[0] { - Event::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref commitment_signed } } => { + Event::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref commitment_signed } } => { assert!(update_add_htlcs.is_empty()); assert!(update_fulfill_htlcs.is_empty()); assert_eq!(update_fail_htlcs.len(), 1); + assert!(update_fail_malformed_htlcs.is_empty()); expected_next_node = node_id.clone(); next_msgs = Some((update_fail_htlcs[0].clone(), commitment_signed.clone())); }, @@ -2793,7 +2872,7 @@ mod tests { for _ in 0..node_count { let feeest = Arc::new(test_utils::TestFeeEstimator { sat_per_kw: 253 }); - let chain_monitor = Arc::new(chaininterface::ChainWatchInterfaceUtil::new(Arc::clone(&logger))); + let chain_monitor = Arc::new(chaininterface::ChainWatchInterfaceUtil::new(Network::Testnet, Arc::clone(&logger))); let tx_broadcaster = Arc::new(test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new())}); let chan_monitor = Arc::new(test_utils::TestChannelMonitor::new(chain_monitor.clone(), tx_broadcaster.clone())); let node_id = { @@ -2802,8 +2881,8 @@ mod tests { SecretKey::from_slice(&secp_ctx, &key_slice).unwrap() }; let node = ChannelManager::new(node_id.clone(), 0, true, Network::Testnet, feeest.clone(), chan_monitor.clone(), chain_monitor.clone(), tx_broadcaster.clone(), Arc::clone(&logger)).unwrap(); - let router = Router::new(PublicKey::from_secret_key(&secp_ctx, &node_id), Arc::clone(&logger)); - nodes.push(Node { feeest, chain_monitor, tx_broadcaster, chan_monitor, node_id, node, router }); + let router = Router::new(PublicKey::from_secret_key(&secp_ctx, &node_id), chain_monitor.clone(), Arc::clone(&logger)); + nodes.push(Node { chain_monitor, tx_broadcaster, chan_monitor, node, router }); } nodes @@ -3212,4 +3291,78 @@ mod tests { assert_eq!(channel_state.by_id.len(), 0); assert_eq!(channel_state.short_to_id.len(), 0); } + + #[test] + fn test_invalid_channel_announcement() { + //Test BOLT 7 channel_announcement msg requirement for final node, gather data to build customed channel_announcement msgs + let secp_ctx = Secp256k1::new(); + let nodes = create_network(2); + + let chan_announcement = create_chan_between_nodes(&nodes[0], &nodes[1]); + + let a_channel_lock = nodes[0].node.channel_state.lock().unwrap(); + let b_channel_lock = nodes[1].node.channel_state.lock().unwrap(); + let as_chan = a_channel_lock.by_id.get(&chan_announcement.3).unwrap(); + let bs_chan = b_channel_lock.by_id.get(&chan_announcement.3).unwrap(); + + let _ = nodes[0].router.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelClosed { short_channel_id : as_chan.get_short_channel_id().unwrap() } ); + + let as_bitcoin_key = PublicKey::from_secret_key(&secp_ctx, &as_chan.get_local_keys().funding_key); + let bs_bitcoin_key = PublicKey::from_secret_key(&secp_ctx, &bs_chan.get_local_keys().funding_key); + + let as_network_key = nodes[0].node.get_our_node_id(); + let bs_network_key = nodes[1].node.get_our_node_id(); + + let were_node_one = as_bitcoin_key.serialize()[..] < bs_bitcoin_key.serialize()[..]; + + let mut chan_announcement; + + macro_rules! dummy_unsigned_msg { + () => { + msgs::UnsignedChannelAnnouncement { + features: msgs::GlobalFeatures::new(), + chain_hash: genesis_block(Network::Testnet).header.bitcoin_hash(), + short_channel_id: as_chan.get_short_channel_id().unwrap(), + node_id_1: if were_node_one { as_network_key } else { bs_network_key }, + node_id_2: if !were_node_one { bs_network_key } else { as_network_key }, + bitcoin_key_1: if were_node_one { as_bitcoin_key } else { bs_bitcoin_key }, + bitcoin_key_2: if !were_node_one { bs_bitcoin_key } else { as_bitcoin_key }, + excess_data: Vec::new(), + }; + } + } + + macro_rules! sign_msg { + ($unsigned_msg: expr) => { + let msghash = Message::from_slice(&Sha256dHash::from_data(&$unsigned_msg.encode()[..])[..]).unwrap(); + let as_bitcoin_sig = secp_ctx.sign(&msghash, &as_chan.get_local_keys().funding_key); + let bs_bitcoin_sig = secp_ctx.sign(&msghash, &bs_chan.get_local_keys().funding_key); + let as_node_sig = secp_ctx.sign(&msghash, &nodes[0].node.our_network_key); + let bs_node_sig = secp_ctx.sign(&msghash, &nodes[1].node.our_network_key); + chan_announcement = msgs::ChannelAnnouncement { + node_signature_1 : if were_node_one { as_node_sig } else { bs_node_sig}, + node_signature_2 : if !were_node_one { bs_node_sig } else { as_node_sig}, + bitcoin_signature_1: if were_node_one { as_bitcoin_sig } else { bs_bitcoin_sig }, + bitcoin_signature_2 : if !were_node_one { bs_bitcoin_sig } else { as_bitcoin_sig }, + contents: $unsigned_msg + } + } + } + + let unsigned_msg = dummy_unsigned_msg!(); + sign_msg!(unsigned_msg); + assert_eq!(nodes[0].router.handle_channel_announcement(&chan_announcement).unwrap(), true); + let _ = nodes[0].router.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelClosed { short_channel_id : as_chan.get_short_channel_id().unwrap() } ); + + // Configured with Network::Testnet + let mut unsigned_msg = dummy_unsigned_msg!(); + unsigned_msg.chain_hash = genesis_block(Network::Bitcoin).header.bitcoin_hash(); + sign_msg!(unsigned_msg); + assert!(nodes[0].router.handle_channel_announcement(&chan_announcement).is_err()); + + let mut unsigned_msg = dummy_unsigned_msg!(); + unsigned_msg.chain_hash = Sha256dHash::from_data(&[1,2,3,4,5,6,7,8,9]); + sign_msg!(unsigned_msg); + assert!(nodes[0].router.handle_channel_announcement(&chan_announcement).is_err()); + } }