Skip to content

Commit 1f0b99f

Browse files
committed
Add test for onion failure processing
1 parent 920d145 commit 1f0b99f

File tree

1 file changed

+264
-11
lines changed

1 file changed

+264
-11
lines changed

src/ln/channelmanager.rs

Lines changed: 264 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -669,8 +669,8 @@ impl ChannelManager {
669669
Ok(res)
670670
}
671671

672-
/// returns the hop data, as well as the first-hop value_msat and CLTV value we should send.
673-
fn build_onion_payloads(route: &Route, starting_htlc_offset: u32) -> Result<(Vec<msgs::OnionHopData>, u64, u32), APIError> {
672+
// Only separated out for testing, we always use realm 0
673+
fn build_onion_payloads_with_realm(route: &Route, starting_htlc_offset: u32, realm: u8) -> Result<(Vec<msgs::OnionHopData>, u64, u32), APIError> {
674674
let mut cur_value_msat = 0u64;
675675
let mut cur_cltv = starting_htlc_offset;
676676
let mut last_short_channel_id = 0;
@@ -685,7 +685,7 @@ impl ChannelManager {
685685
let value_msat = if cur_value_msat == 0 { hop.fee_msat } else { cur_value_msat };
686686
let cltv = if cur_cltv == starting_htlc_offset { hop.cltv_expiry_delta + starting_htlc_offset } else { cur_cltv };
687687
res[idx] = msgs::OnionHopData {
688-
realm: 0,
688+
realm: realm,
689689
data: msgs::OnionRealm0HopData {
690690
short_channel_id: last_short_channel_id,
691691
amt_to_forward: value_msat,
@@ -706,6 +706,11 @@ impl ChannelManager {
706706
Ok((res, cur_value_msat, cur_cltv))
707707
}
708708

709+
#[inline]
710+
fn build_onion_payloads(route: &Route, starting_htlc_offset: u32) -> Result<(Vec<msgs::OnionHopData>, u64, u32), APIError> {
711+
ChannelManager::build_onion_payloads_with_realm(route, starting_htlc_offset, 0)
712+
}
713+
709714
#[inline]
710715
fn shift_arr_right(arr: &mut [u8; 20*65]) {
711716
unsafe {
@@ -1083,11 +1088,15 @@ impl ChannelManager {
10831088
}
10841089
}
10851090

1086-
let session_priv = SecretKey::from_slice(&self.secp_ctx, &{
1087-
let mut session_key = [0; 32];
1088-
rng::fill_bytes(&mut session_key);
1089-
session_key
1090-
}).expect("RNG is bad!");
1091+
let session_priv = if cfg!(test) {
1092+
SecretKey::from_slice(&self.secp_ctx, &[3; 32]).unwrap()
1093+
} else {
1094+
SecretKey::from_slice(&self.secp_ctx, &{
1095+
let mut session_key = [0; 32];
1096+
rng::fill_bytes(&mut session_key);
1097+
session_key
1098+
}).expect("RNG is bad!")
1099+
};
10911100

10921101
let cur_height = self.latest_block_height.load(Ordering::Acquire) as u32 + 1;
10931102

@@ -2552,12 +2561,12 @@ mod tests {
25522561
use chain::chaininterface;
25532562
use chain::transaction::OutPoint;
25542563
use chain::chaininterface::ChainListener;
2555-
use ln::channelmanager::{ChannelManager,OnionKeys};
2564+
use ln::channelmanager::{ChannelManager,OnionKeys,HTLCSource};
25562565
use ln::channelmonitor::{CLTV_CLAIM_BUFFER, HTLC_FAIL_TIMEOUT_BLOCKS};
25572566
use ln::router::{Route, RouteHop, Router};
25582567
use ln::msgs;
2559-
use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler};
2560-
use util::test_utils;
2568+
use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler,HTLCFailChannelUpdate};
2569+
use util::{test_utils, rng};
25612570
use util::events::{Event, EventsProvider};
25622571
use util::errors::APIError;
25632572
use util::logger::Logger;
@@ -5389,4 +5398,248 @@ mod tests {
53895398
sign_msg!(unsigned_msg);
53905399
assert!(nodes[0].router.handle_channel_announcement(&chan_announcement).is_err());
53915400
}
5401+
5402+
fn run_onion_failure_test<F1,F2>(_name: &str, test_case: u8, nodes: &Vec<Node>, channels: &[(msgs::ChannelUpdate, msgs::ChannelUpdate, [u8; 32], Transaction)], route: &Route, payment_hash: &[u8; 32], mut callback1: F1, mut callback2: F2, expected_retryable: bool, expected_error_code: Option<u16>, expected_channel_update: Option<HTLCFailChannelUpdate>)
5403+
where F1: for <'a> FnMut(&'a mut msgs::UpdateAddHTLC),
5404+
F2: for <'a> FnMut(&'a mut msgs::UpdateAddHTLC),
5405+
{
5406+
use ln::msgs::HTLCFailChannelUpdate;
5407+
5408+
// reset block height
5409+
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
5410+
for ix in 0..nodes.len() {
5411+
nodes[ix].chain_monitor.block_connected_checked(&header, 1, &Vec::new()[..], &[0; 0]);
5412+
}
5413+
5414+
macro_rules! expect_update_htlc_event {
5415+
($node: expr) => {{
5416+
let events = $node.node.get_and_clear_pending_events();
5417+
assert_eq!(events.len(), 1);
5418+
match events[0] {
5419+
Event::UpdateHTLCs { node_id:_, ref updates } => { },
5420+
_ => panic!("Unexpected event"),
5421+
};
5422+
$node.node.channel_state.lock().unwrap().next_forward = Instant::now();
5423+
$node.node.process_pending_htlc_forwards();
5424+
}}
5425+
}
5426+
5427+
macro_rules! expect_pending_htlcs_forwardable {
5428+
($node: expr) => {{
5429+
let events = $node.node.get_and_clear_pending_events();
5430+
assert_eq!(events.len(), 1);
5431+
match events[0] {
5432+
Event::PendingHTLCsForwardable { .. } => { },
5433+
_ => panic!("Unexpected event"),
5434+
};
5435+
$node.node.channel_state.lock().unwrap().next_forward = Instant::now();
5436+
$node.node.process_pending_htlc_forwards();
5437+
}}
5438+
};
5439+
5440+
macro_rules! expect_pending_htlcs_forwardable {
5441+
($node: expr) => {{
5442+
let events = $node.node.get_and_clear_pending_events();
5443+
assert_eq!(events.len(), 1);
5444+
match events[0] {
5445+
Event::PendingHTLCsForwardable { .. } => { },
5446+
_ => panic!("Unexpected event"),
5447+
};
5448+
$node.node.channel_state.lock().unwrap().next_forward = Instant::now();
5449+
$node.node.process_pending_htlc_forwards();
5450+
}}
5451+
};
5452+
5453+
macro_rules! expect_forward_event {
5454+
($node: expr) => {{
5455+
let mut events = $node.node.get_and_clear_pending_events();
5456+
assert_eq!(events.len(), 1);
5457+
check_added_monitors!($node, 1);
5458+
SendEvent::from_event(events.remove(0))
5459+
}}
5460+
};
5461+
5462+
macro_rules! expect_forward_event {
5463+
($node: expr) => {{
5464+
let mut events = $node.node.get_and_clear_pending_events();
5465+
assert_eq!(events.len(), 1);
5466+
check_added_monitors!($node, 1);
5467+
SendEvent::from_event(events.remove(0))
5468+
}}
5469+
};
5470+
5471+
macro_rules! expect_fail_backward_event {
5472+
($node: expr) => {{
5473+
let events = $node.node.get_and_clear_pending_events();
5474+
assert_eq!(events.len(), 1);
5475+
match events[0] {
5476+
Event::UpdateHTLCs { node_id:_, updates: msgs::CommitmentUpdate { update_add_htlcs:_, update_fulfill_htlcs:_, ref update_fail_htlcs, update_fail_malformed_htlcs:_, update_fee:_, ref commitment_signed } } => {
5477+
assert_eq!(update_fail_htlcs.len(),1);
5478+
(update_fail_htlcs[0].clone(), commitment_signed.clone())
5479+
},
5480+
_ => panic!("Unexpected event type!"),
5481+
}
5482+
}}
5483+
};
5484+
5485+
nodes[0].node.send_payment(route.clone(), payment_hash.clone()).unwrap();
5486+
let payment_event = expect_forward_event!(nodes[0]);
5487+
let mut update_add_1 = payment_event.msgs[0].clone();
5488+
5489+
callback1(&mut update_add_1);
5490+
5491+
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &update_add_1).unwrap();
5492+
5493+
// 0 => 1
5494+
let (as_revoke_and_ack, as_commitment_signed) = nodes[1].node.handle_commitment_signed(&nodes[0].node.get_our_node_id(), &payment_event.commitment_msg).unwrap();
5495+
check_added_monitors!(nodes[1], 1);
5496+
assert!(nodes[0].node.handle_revoke_and_ack(&nodes[1].node.get_our_node_id(), &as_revoke_and_ack).unwrap().is_none());
5497+
check_added_monitors!(nodes[0], 1);
5498+
let (bs_revoke_and_ack, bs_none) = nodes[0].node.handle_commitment_signed(&nodes[1].node.get_our_node_id(), &as_commitment_signed.unwrap()).unwrap();
5499+
assert!(bs_none.is_none());
5500+
check_added_monitors!(nodes[0], 1);
5501+
let commitment_update = nodes[1].node.handle_revoke_and_ack(&nodes[0].node.get_our_node_id(), &bs_revoke_and_ack).unwrap();
5502+
check_added_monitors!(nodes[1], 1);
5503+
5504+
let (update_fail_htlc, commitment_signed) = match test_case {
5505+
0 => { // intermediat node failure
5506+
assert!(commitment_update.is_some());
5507+
let commitment_update = commitment_update.unwrap();
5508+
assert!(commitment_update.update_fail_htlcs.len() == 1);
5509+
(commitment_update.update_fail_htlcs[0].clone(), commitment_update.commitment_signed)
5510+
},
5511+
1 => { // final node failure
5512+
assert!(commitment_update.is_none());
5513+
expect_pending_htlcs_forwardable!(&nodes[1]);
5514+
5515+
let ref payment_event = expect_forward_event!(nodes[1]);
5516+
let mut update_add_2 = payment_event.msgs[0].clone();
5517+
5518+
callback2(&mut update_add_2);
5519+
5520+
nodes[2].node.handle_update_add_htlc(&nodes[1].node.get_our_node_id(), &update_add_2).unwrap();
5521+
let (as_revoke_and_ack, as_commitment_signed) = nodes[2].node.handle_commitment_signed(&nodes[1].node.get_our_node_id(), &payment_event.commitment_msg).unwrap();
5522+
check_added_monitors!(nodes[2], 1);
5523+
assert!(nodes[1].node.handle_revoke_and_ack(&nodes[2].node.get_our_node_id(), &as_revoke_and_ack).unwrap().is_none());
5524+
5525+
check_added_monitors!(nodes[1], 1);
5526+
let (bs_revoke_and_ack, bs_none) = nodes[1].node.handle_commitment_signed(&nodes[2].node.get_our_node_id(), &as_commitment_signed.unwrap()).unwrap();
5527+
assert!(bs_none.is_none());
5528+
check_added_monitors!(nodes[1], 1);
5529+
let commitment_update = nodes[2].node.handle_revoke_and_ack(&nodes[1].node.get_our_node_id(), &bs_revoke_and_ack).unwrap().unwrap();
5530+
check_added_monitors!(nodes[2], 1);
5531+
5532+
assert!(commitment_update.update_fail_htlcs.len() == 1);
5533+
nodes[1].node.handle_update_fail_htlc(&nodes[2].node.get_our_node_id(), &commitment_update.update_fail_htlcs[0]).unwrap();
5534+
commitment_signed_dance!(nodes[1], nodes[2], commitment_update.commitment_signed, true);
5535+
5536+
let (update_fail_htlc_msg, commitment_signed) = expect_fail_backward_event!(nodes[1]);
5537+
(update_fail_htlc_msg, commitment_signed)
5538+
},
5539+
_ => unreachable!(),
5540+
};
5541+
5542+
// origin node fail handling
5543+
nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &update_fail_htlc).unwrap();
5544+
commitment_signed_dance!(nodes[0], nodes[1], commitment_signed, false);
5545+
5546+
let events = nodes[0].node.get_and_clear_pending_events();
5547+
//TODO assert_eq!(events.len(), 2);
5548+
for evt in events.iter() {
5549+
match evt {
5550+
&Event::PaymentFailed { payment_hash:_, ref rejected_by_dest} => {
5551+
assert_eq!(*rejected_by_dest, !expected_retryable);
5552+
},
5553+
&Event::RouteUpdate { ref update } => {
5554+
/* TODO check expected channel update */
5555+
/*
5556+
expected_channel_update.unwrap()
5557+
assert!(expected_channel_update.is_some());
5558+
if let Some(expected_update) = expected_channel_update {
5559+
assert!(fail_channel_update.is_some());
5560+
match fail_channel_update.unwrap() {
5561+
expected_update => {},
5562+
_ => panic!("Unexpected channel update"),
5563+
}
5564+
}
5565+
*/
5566+
},
5567+
_ => panic!("Unexpected event"),
5568+
};
5569+
}
5570+
}
5571+
5572+
#[test]
5573+
fn test_onion_failure() {
5574+
use ln::msgs::ChannelUpdate;
5575+
use ln::channelmanager::CLTV_FAR_FAR_AWAY;
5576+
use bitcoin::blockdata::transaction::Transaction;
5577+
5578+
const BADONION: u16 = 0x8000;
5579+
const PERM: u16 = 0x4000;
5580+
const NODE: u16 = 0x1000;
5581+
const UPDATE: u16 = 0x1000;
5582+
5583+
let mut nodes = create_network(3);
5584+
let channels = [create_announced_chan_between_nodes(&nodes, 0, 1), create_announced_chan_between_nodes(&nodes, 1, 2)];
5585+
let (_, payment_hash) = get_payment_preimage_hash!(nodes[0]);
5586+
let route = nodes[0].router.get_route(&nodes[2].node.get_our_node_id(), None, &Vec::new(), 40000, TEST_FINAL_CLTV).unwrap();
5587+
//
5588+
run_onion_failure_test("invalid_realm", 0, &nodes, &channels, &route, &payment_hash, |msg| {
5589+
let session_priv = SecretKey::from_slice(&::secp256k1::Secp256k1::without_caps(), &[3; 32]).unwrap();
5590+
let cur_height = nodes[0].node.latest_block_height.load(Ordering::Acquire) as u32 + 1;
5591+
let onion_keys = ChannelManager::construct_onion_keys(&Secp256k1::new(), &route, &session_priv).unwrap();
5592+
let (onion_payloads, _htlc_msat, _htlc_cltv) = ChannelManager::build_onion_payloads_with_realm(&route, cur_height, 100).unwrap();
5593+
let onion_packet = ChannelManager::construct_onion_packet(onion_payloads, onion_keys, &payment_hash);
5594+
msg.onion_routing_packet = onion_packet;
5595+
}, |_msg| {}, true, Some(PERM|1), None);
5596+
5597+
//TODO temporary_node_failure(NODE|2)
5598+
//TODO permanent_node_failure(PERM|NODE|2)
5599+
//TODO required_node_feature_missing
5600+
run_onion_failure_test("invalid_onion_version", 0, &nodes, &channels, &route, &payment_hash, |msg| { msg.onion_routing_packet.version = 1; }, |_msg| {}, true, Some(BADONION|PERM|4), None);
5601+
run_onion_failure_test("invalid_onion_hmac", 0, &nodes, &channels, &route, &payment_hash, |msg| { msg.onion_routing_packet.hmac = [3; 32]; }, |_msg| {}, true, Some(BADONION|PERM|5), None);
5602+
//TODO invalid_onion_key
5603+
//TODO temporary_channel_failure(UPDATE|7)
5604+
//TODO permanent_channel_failure(PERM|8)
5605+
//TODO required_channel_feature_missing(PERM|9)
5606+
//TODO unknown_next_peer(PERM|10)
5607+
//TODO amount_below_minimum(UPDATE|11)
5608+
//TODO fee_insufficient(UPDATE|12)
5609+
run_onion_failure_test("incorrect_cltv_expiry", 0, &nodes, &channels, &route, &payment_hash, |msg| {
5610+
// need to violate: cltv_expiry - cltv_expiry_delta >= outgoing_cltv_value
5611+
msg.cltv_expiry -= 1;
5612+
}, |_msg| {}, true, Some(UPDATE|13), None);
5613+
run_onion_failure_test("expiry_too_soon", 0, &nodes, &channels, &route, &payment_hash, |msg| {
5614+
let height = msg.cltv_expiry - CLTV_CLAIM_BUFFER - HTLC_FAIL_TIMEOUT_BLOCKS + 1;
5615+
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
5616+
nodes[1].chain_monitor.block_connected_checked(&header, height, &Vec::new()[..], &[0; 0]);
5617+
}, |_msg| {}, true, Some(UPDATE|14), None);
5618+
// TODO: unknown_payment_hash (PERM|15)
5619+
// TODO: unknown_payment_amount (PERM|15)
5620+
run_onion_failure_test("final_expiry_too_soon", 1, &nodes, &channels, &route, &payment_hash, |_msg| {}, |msg| {
5621+
let height = msg.cltv_expiry - CLTV_CLAIM_BUFFER - HTLC_FAIL_TIMEOUT_BLOCKS + 1;
5622+
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
5623+
nodes[2].chain_monitor.block_connected_checked(&header, height, &Vec::new()[..], &[0; 0]);
5624+
}, true, Some(17), None);
5625+
run_onion_failure_test("final_incorrect_cltv_expiry", 1, &nodes, &channels, &route, &payment_hash, |_msg| {}, |msg| { msg.cltv_expiry += 1; }, true, Some(18), None);
5626+
/* TODO this raise 'Invalid commitment tx signature from peer'
5627+
run_onion_failure_test("final_incorrect_htlc_amount", 1, &nodes, &channels, &route, &payment_hash, |_msg| {}, |msg| {
5628+
// violate amt_to_forward > msg.amount_msat
5629+
msg.amount_msat -= 1;
5630+
}, true, Some(19), None);
5631+
*/
5632+
// TODO: channel_disabled (UPDATE|20)
5633+
run_onion_failure_test("expiry_too_far", 0, &nodes, &channels, &route, &payment_hash, |msg| {
5634+
let session_priv = SecretKey::from_slice(&::secp256k1::Secp256k1::without_caps(), &[3; 32]).unwrap();
5635+
let mut route = route.clone();
5636+
let height = 1;
5637+
route.hops[1].cltv_expiry_delta += CLTV_FAR_FAR_AWAY + route.hops[0].cltv_expiry_delta + 1;
5638+
let onion_keys = ChannelManager::construct_onion_keys(&Secp256k1::new(), &route, &session_priv).unwrap();
5639+
let (onion_payloads, _htlc_msat, htlc_cltv) = ChannelManager::build_onion_payloads(&route, height).unwrap();
5640+
let onion_packet = ChannelManager::construct_onion_packet(onion_payloads, onion_keys, &payment_hash);
5641+
msg.cltv_expiry = htlc_cltv;
5642+
msg.onion_routing_packet = onion_packet;
5643+
}, |_msg| {}, true, Some(21), None);
5644+
}
53925645
}

0 commit comments

Comments
 (0)