use ln::channelmonitor::ManyChannelMonitor;
use ln::router::{Route,RouteHop};
use ln::msgs;
-use ln::msgs::{HandleError,ChannelMessageHandler,MsgEncodable,MsgDecodable};
+use ln::msgs::{HandleError,ChannelMessageHandler};
use util::{byte_utils, events, internal_traits, rng};
use util::sha2::Sha256;
+use util::ser::{Readable, Writeable};
use util::chacha20poly1305rfc::ChaCha20;
use util::logger::Logger;
use util::errors::APIError;
use std::{ptr, mem};
use std::collections::HashMap;
use std::collections::hash_map;
+use std::io::Cursor;
use std::sync::{Mutex,MutexGuard,Arc};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::{Instant,Duration};
Fail(HTLCFailureMsg),
}
- #[cfg(feature = "fuzztarget")]
- impl PendingHTLCStatus {
- pub fn dummy() -> Self {
- let secp_ctx = ::secp256k1::Secp256k1::signing_only();
- PendingHTLCStatus::Forward(PendingForwardHTLCInfo {
- onion_packet: None,
- incoming_shared_secret: SharedSecret::new(&secp_ctx,
- &::secp256k1::key::PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &[1; 32]).unwrap()),
- &SecretKey::from_slice(&secp_ctx, &[1; 32]).unwrap()),
- payment_hash: [0; 32],
- short_channel_id: 0,
- amt_to_forward: 0,
- outgoing_cltv_value: 0,
- })
- }
- }
-
/// Tracks the inbound corresponding to an outbound HTLC
#[derive(Clone)]
pub struct HTLCPreviousHopData {
session_priv: SecretKey,
},
}
- #[cfg(any(test, feature = "fuzztarget"))]
+ #[cfg(test)]
impl HTLCSource {
pub fn dummy() -> Self {
HTLCSource::OutboundRoute {
}
#[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug
- pub enum HTLCFailReason {
+ pub(crate) enum HTLCFailReason {
ErrorPacket {
err: msgs::OnionErrorPacket,
},
data: Vec<u8>,
}
}
-
- #[cfg(feature = "fuzztarget")]
- impl HTLCFailReason {
- pub fn dummy() -> Self {
- HTLCFailReason::Reason {
- failure_code: 0, data: Vec::new(),
- }
- }
- }
}
-#[cfg(feature = "fuzztarget")]
-pub use self::channel_held_info::*;
-#[cfg(not(feature = "fuzztarget"))]
-pub(crate) use self::channel_held_info::*;
+pub(super) use self::channel_held_info::*;
struct MsgHandleErrInternal {
err: msgs::HandleError,
let next_hop_data = {
let mut decoded = [0; 65];
chacha.process(&msg.onion_routing_packet.hop_data[0..65], &mut decoded);
- match msgs::OnionHopData::decode(&decoded[..]) {
+ match msgs::OnionHopData::read(&mut Cursor::new(&decoded[..])) {
Err(err) => {
let error_code = match err {
msgs::DecodeError::UnknownRealmByte => 0x4000 | 1,
chacha.process(&packet_decrypted, &mut decryption_tmp[..]);
packet_decrypted = decryption_tmp;
- if let Ok(err_packet) = msgs::DecodedOnionErrorPacket::decode(&packet_decrypted) {
+ if let Ok(err_packet) = msgs::DecodedOnionErrorPacket::read(&mut Cursor::new(&packet_decrypted)) {
if err_packet.failuremsg.len() >= 2 {
let um = ChannelManager::gen_um_from_shared_secret(&shared_secret);
if err_packet.failuremsg.len() >= 4 {
let update_len = byte_utils::slice_to_be16(&err_packet.failuremsg[2..4]) as usize;
if err_packet.failuremsg.len() >= 4 + update_len {
- if let Ok(chan_update) = msgs::ChannelUpdate::decode(&err_packet.failuremsg[4..4 + update_len]) {
+ if let Ok(chan_update) = msgs::ChannelUpdate::read(&mut Cursor::new(&err_packet.failuremsg[4..4 + update_len])) {
res = Some(msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {
msg: chan_update,
});
use ln::channelmanager::{ChannelManager,OnionKeys};
use ln::router::{Route, RouteHop, Router};
use ln::msgs;
- use ln::msgs::{MsgEncodable,ChannelMessageHandler,RoutingMessageHandler};
+ use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler};
use util::test_utils;
use util::events::{Event, EventsProvider};
- use util::logger::Logger;
use util::errors::APIError;
+ use util::logger::Logger;
+ use util::ser::Writeable;
use bitcoin::util::hash::Sha256dHash;
use bitcoin::blockdata::block::{Block, BlockHeader};
assert_eq!(channel_state.short_to_id.len(), 0);
}
+ fn reconnect_nodes(node_a: &Node, node_b: &Node, pre_all_htlcs: bool, pending_htlc_claims: (usize, usize), pending_htlc_fails: (usize, usize)) {
+ let reestablish_1 = node_a.node.peer_connected(&node_b.node.get_our_node_id());
+ let reestablish_2 = node_b.node.peer_connected(&node_a.node.get_our_node_id());
+
+ let mut resp_1 = Vec::new();
+ for msg in reestablish_1 {
+ resp_1.push(node_b.node.handle_channel_reestablish(&node_a.node.get_our_node_id(), &msg).unwrap());
+ }
+ {
+ let mut added_monitors = node_b.chan_monitor.added_monitors.lock().unwrap();
+ if pending_htlc_claims.0 != 0 || pending_htlc_fails.0 != 0 {
+ assert_eq!(added_monitors.len(), 1);
+ } else {
+ assert!(added_monitors.is_empty());
+ }
+ added_monitors.clear();
+ }
+
+ let mut resp_2 = Vec::new();
+ for msg in reestablish_2 {
+ resp_2.push(node_a.node.handle_channel_reestablish(&node_b.node.get_our_node_id(), &msg).unwrap());
+ }
+ {
+ let mut added_monitors = node_a.chan_monitor.added_monitors.lock().unwrap();
+ if pending_htlc_claims.1 != 0 || pending_htlc_fails.1 != 0 {
+ assert_eq!(added_monitors.len(), 1);
+ } else {
+ assert!(added_monitors.is_empty());
+ }
+ added_monitors.clear();
+ }
+
+ // We dont yet support both needing updates, as that would require a different commitment dance:
+ assert!((pending_htlc_claims.0 == 0 && pending_htlc_fails.0 == 0) || (pending_htlc_claims.1 == 0 && pending_htlc_fails.1 == 0));
+
+ for chan_msgs in resp_1.drain(..) {
+ if pre_all_htlcs {
+ let _announcement_sigs_opt = node_a.node.handle_funding_locked(&node_b.node.get_our_node_id(), &chan_msgs.0.unwrap()).unwrap();
+ //TODO: Test announcement_sigs re-sending when we've implemented it
+ } else {
+ assert!(chan_msgs.0.is_none());
+ }
+ assert!(chan_msgs.1.is_none());
+ if pending_htlc_claims.0 != 0 || pending_htlc_fails.0 != 0 {
+ let commitment_update = chan_msgs.2.unwrap();
+ assert!(commitment_update.update_add_htlcs.is_empty()); // We can't relay while disconnected
+ assert_eq!(commitment_update.update_fulfill_htlcs.len(), pending_htlc_claims.0);
+ assert_eq!(commitment_update.update_fail_htlcs.len(), pending_htlc_fails.0);
+ assert!(commitment_update.update_fail_malformed_htlcs.is_empty());
+ for update_fulfill in commitment_update.update_fulfill_htlcs {
+ node_a.node.handle_update_fulfill_htlc(&node_b.node.get_our_node_id(), &update_fulfill).unwrap();
+ }
+ for update_fail in commitment_update.update_fail_htlcs {
+ node_a.node.handle_update_fail_htlc(&node_b.node.get_our_node_id(), &update_fail).unwrap();
+ }
+
+ commitment_signed_dance!(node_a, node_b, commitment_update.commitment_signed, false);
+ } else {
+ assert!(chan_msgs.2.is_none());
+ }
+ }
+
+ for chan_msgs in resp_2.drain(..) {
+ if pre_all_htlcs {
+ let _announcement_sigs_opt = node_b.node.handle_funding_locked(&node_a.node.get_our_node_id(), &chan_msgs.0.unwrap()).unwrap();
+ //TODO: Test announcement_sigs re-sending when we've implemented it
+ } else {
+ assert!(chan_msgs.0.is_none());
+ }
+ assert!(chan_msgs.1.is_none());
+ if pending_htlc_claims.1 != 0 || pending_htlc_fails.1 != 0 {
+ let commitment_update = chan_msgs.2.unwrap();
+ assert!(commitment_update.update_add_htlcs.is_empty()); // We can't relay while disconnected
+ assert_eq!(commitment_update.update_fulfill_htlcs.len(), pending_htlc_claims.0);
+ assert_eq!(commitment_update.update_fail_htlcs.len(), pending_htlc_fails.0);
+ assert!(commitment_update.update_fail_malformed_htlcs.is_empty());
+ for update_fulfill in commitment_update.update_fulfill_htlcs {
+ node_b.node.handle_update_fulfill_htlc(&node_a.node.get_our_node_id(), &update_fulfill).unwrap();
+ }
+ for update_fail in commitment_update.update_fail_htlcs {
+ node_b.node.handle_update_fail_htlc(&node_a.node.get_our_node_id(), &update_fail).unwrap();
+ }
+
+ commitment_signed_dance!(node_b, node_a, commitment_update.commitment_signed, false);
+ } else {
+ assert!(chan_msgs.2.is_none());
+ }
+ }
+ }
+
+ #[test]
+ fn test_simple_peer_disconnect() {
+ // Test that we can reconnect when there are no lost messages
+ let nodes = create_network(3);
+ create_announced_chan_between_nodes(&nodes, 0, 1);
+ create_announced_chan_between_nodes(&nodes, 1, 2);
+
+ nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
+ nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
+ reconnect_nodes(&nodes[0], &nodes[1], true, (0, 0), (0, 0));
+
+ let payment_preimage_1 = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 1000000).0;
+ let payment_hash_2 = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 1000000).1;
+ fail_payment(&nodes[0], &vec!(&nodes[1], &nodes[2]), payment_hash_2);
+ claim_payment(&nodes[0], &vec!(&nodes[1], &nodes[2]), payment_preimage_1);
+
+ nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
+ nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
+ reconnect_nodes(&nodes[0], &nodes[1], false, (0, 0), (0, 0));
+
+ let payment_preimage_3 = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 1000000).0;
+ let payment_preimage_4 = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 1000000).0;
+ let payment_hash_5 = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 1000000).1;
+ let payment_hash_6 = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 1000000).1;
+
+ nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
+ nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
+
+ claim_payment_along_route(&nodes[0], &vec!(&nodes[1], &nodes[2]), true, payment_preimage_3);
+ fail_payment_along_route(&nodes[0], &[&nodes[1], &nodes[2]], true, payment_hash_5);
+
+ reconnect_nodes(&nodes[0], &nodes[1], false, (1, 0), (1, 0));
+ {
+ let events = nodes[0].node.get_and_clear_pending_events();
+ assert_eq!(events.len(), 2);
+ match events[0] {
+ Event::PaymentSent { payment_preimage } => {
+ assert_eq!(payment_preimage, payment_preimage_3);
+ },
+ _ => panic!("Unexpected event"),
+ }
+ match events[1] {
+ Event::PaymentFailed { payment_hash } => {
+ assert_eq!(payment_hash, payment_hash_5);
+ },
+ _ => panic!("Unexpected event"),
+ }
+ }
+
+ claim_payment(&nodes[0], &vec!(&nodes[1], &nodes[2]), payment_preimage_4);
+ fail_payment(&nodes[0], &vec!(&nodes[1], &nodes[2]), payment_hash_6);
+ }
+
#[test]
fn test_invalid_channel_announcement() {
//Test BOLT 7 channel_announcement msg requirement for final node, gather data to build customed channel_announcement msgs