Skip to content

Commit 8b63892

Browse files
committed
Send back the actual received amount, not expected on HTLC fails
This resolves an incorrect implementation of the spec and fixes a major privacy leak. Fixes GH #289.
1 parent 49d6330 commit 8b63892

File tree

6 files changed

+38
-32
lines changed

6 files changed

+38
-32
lines changed

fuzz/fuzz_targets/chanmon_fail_consistency.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ pub fn do_test(data: &[u8]) {
439439
match event {
440440
events::Event::PaymentReceived { payment_hash, .. } => {
441441
if $fail {
442-
assert!(nodes[$node].fail_htlc_backwards(&payment_hash, 0));
442+
assert!(nodes[$node].fail_htlc_backwards(&payment_hash));
443443
} else {
444444
assert!(nodes[$node].claim_funds(PaymentPreimage(payment_hash.0)));
445445
}

fuzz/fuzz_targets/full_stack_target.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ pub fn do_test(data: &[u8], logger: &Arc<Logger>) {
451451
// fulfill this HTLC, but if they are, we can just take the first byte and
452452
// place that anywhere in our preimage.
453453
if &payment.0[1..] != &[0; 31] {
454-
channelmanager.fail_htlc_backwards(&payment, 0);
454+
channelmanager.fail_htlc_backwards(&payment);
455455
} else {
456456
let mut payment_preimage = PaymentPreimage([0; 32]);
457457
payment_preimage.0[0] = payment.0[0];
@@ -461,7 +461,7 @@ pub fn do_test(data: &[u8], logger: &Arc<Logger>) {
461461
},
462462
9 => {
463463
for payment in payments_received.drain(..) {
464-
channelmanager.fail_htlc_backwards(&payment, 0);
464+
channelmanager.fail_htlc_backwards(&payment);
465465
}
466466
},
467467
10 => {

src/ln/chanmon_update_fail_tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,7 @@ fn do_test_monitor_update_fail_raa(test_ignore_second_cs: bool) {
674674
let (_, payment_hash_1) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 1000000);
675675

676676
// Fail the payment backwards, failing the monitor update on nodes[1]'s receipt of the RAA
677-
assert!(nodes[2].node.fail_htlc_backwards(&payment_hash_1, 0));
677+
assert!(nodes[2].node.fail_htlc_backwards(&payment_hash_1));
678678
expect_pending_htlcs_forwardable!(nodes[2]);
679679
check_added_monitors!(nodes[2], 1);
680680

@@ -1451,7 +1451,7 @@ fn test_monitor_update_on_pending_forwards() {
14511451
send_payment(&nodes[0], &[&nodes[1], &nodes[2]], 5000000);
14521452

14531453
let (_, payment_hash_1) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 1000000);
1454-
assert!(nodes[2].node.fail_htlc_backwards(&payment_hash_1, 1000000));
1454+
assert!(nodes[2].node.fail_htlc_backwards(&payment_hash_1));
14551455
expect_pending_htlcs_forwardable!(nodes[2]);
14561456
check_added_monitors!(nodes[2], 1);
14571457

src/ln/channelmanager.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -252,10 +252,12 @@ pub(super) struct ChannelHolder {
252252
/// guarantees are made about the existence of a channel with the short id here, nor the short
253253
/// ids in the PendingForwardHTLCInfo!
254254
pub(super) forward_htlcs: HashMap<u64, Vec<HTLCForwardInfo>>,
255+
/// payment_hash -> Vec<(amount_received, htlc_source)> for tracking things that were to us and
256+
/// can be failed/claimed by the user
255257
/// Note that while this is held in the same mutex as the channels themselves, no consistency
256258
/// guarantees are made about the channels given here actually existing anymore by the time you
257259
/// go to read them!
258-
pub(super) claimable_htlcs: HashMap<PaymentHash, Vec<HTLCPreviousHopData>>,
260+
pub(super) claimable_htlcs: HashMap<PaymentHash, Vec<(u64, HTLCPreviousHopData)>>,
259261
/// Messages to send to peers - pushed to in the same lock that they are generated in (except
260262
/// for broadcast messages, where ordering isn't as strict).
261263
pub(super) pending_msg_events: Vec<events::MessageSendEvent>,
@@ -265,7 +267,7 @@ pub(super) struct MutChannelHolder<'a> {
265267
pub(super) short_to_id: &'a mut HashMap<u64, [u8; 32]>,
266268
pub(super) next_forward: &'a mut Instant,
267269
pub(super) forward_htlcs: &'a mut HashMap<u64, Vec<HTLCForwardInfo>>,
268-
pub(super) claimable_htlcs: &'a mut HashMap<PaymentHash, Vec<HTLCPreviousHopData>>,
270+
pub(super) claimable_htlcs: &'a mut HashMap<PaymentHash, Vec<(u64, HTLCPreviousHopData)>>,
269271
pub(super) pending_msg_events: &'a mut Vec<events::MessageSendEvent>,
270272
}
271273
impl ChannelHolder {
@@ -1308,8 +1310,8 @@ impl ChannelManager {
13081310
incoming_packet_shared_secret: forward_info.incoming_shared_secret,
13091311
};
13101312
match channel_state.claimable_htlcs.entry(forward_info.payment_hash) {
1311-
hash_map::Entry::Occupied(mut entry) => entry.get_mut().push(prev_hop_data),
1312-
hash_map::Entry::Vacant(entry) => { entry.insert(vec![prev_hop_data]); },
1313+
hash_map::Entry::Occupied(mut entry) => entry.get_mut().push((forward_info.amt_to_forward, prev_hop_data)),
1314+
hash_map::Entry::Vacant(entry) => { entry.insert(vec![(forward_info.amt_to_forward, prev_hop_data)]); },
13131315
};
13141316
new_events.push(events::Event::PaymentReceived {
13151317
payment_hash: forward_info.payment_hash,
@@ -1357,17 +1359,17 @@ impl ChannelManager {
13571359
/// after a PaymentReceived event.
13581360
/// expected_value is the value you expected the payment to be for (not the amount it actually
13591361
/// was for from the PaymentReceived event).
1360-
pub fn fail_htlc_backwards(&self, payment_hash: &PaymentHash, expected_value: u64) -> bool {
1362+
pub fn fail_htlc_backwards(&self, payment_hash: &PaymentHash) -> bool {
13611363
let _ = self.total_consistency_lock.read().unwrap();
13621364

13631365
let mut channel_state = Some(self.channel_state.lock().unwrap());
13641366
let removed_source = channel_state.as_mut().unwrap().claimable_htlcs.remove(payment_hash);
13651367
if let Some(mut sources) = removed_source {
1366-
for htlc_with_hash in sources.drain(..) {
1368+
for (recvd_value, htlc_with_hash) in sources.drain(..) {
13671369
if channel_state.is_none() { channel_state = Some(self.channel_state.lock().unwrap()); }
13681370
self.fail_htlc_backwards_internal(channel_state.take().unwrap(),
13691371
HTLCSource::PreviousHopData(htlc_with_hash), payment_hash,
1370-
HTLCFailReason::Reason { failure_code: 0x4000 | 15, data: byte_utils::be64_to_array(expected_value).to_vec() });
1372+
HTLCFailReason::Reason { failure_code: 0x4000 | 15, data: byte_utils::be64_to_array(recvd_value).to_vec() });
13711373
}
13721374
true
13731375
} else { false }
@@ -1485,7 +1487,10 @@ impl ChannelManager {
14851487
let mut channel_state = Some(self.channel_state.lock().unwrap());
14861488
let removed_source = channel_state.as_mut().unwrap().claimable_htlcs.remove(&payment_hash);
14871489
if let Some(mut sources) = removed_source {
1488-
for htlc_with_hash in sources.drain(..) {
1490+
// TODO: We should require the user specify the expected amount so that we can claim
1491+
// only payments for the correct amount, and reject payments for incorrect amounts
1492+
// (which are probably middle nodes probing to break our privacy).
1493+
for (_, htlc_with_hash) in sources.drain(..) {
14891494
if channel_state.is_none() { channel_state = Some(self.channel_state.lock().unwrap()); }
14901495
self.claim_funds_internal(channel_state.take().unwrap(), HTLCSource::PreviousHopData(htlc_with_hash), payment_preimage);
14911496
}
@@ -2910,7 +2915,8 @@ impl Writeable for ChannelManager {
29102915
for (payment_hash, previous_hops) in channel_state.claimable_htlcs.iter() {
29112916
payment_hash.write(writer)?;
29122917
(previous_hops.len() as u64).write(writer)?;
2913-
for previous_hop in previous_hops {
2918+
for &(recvd_amt, ref previous_hop) in previous_hops.iter() {
2919+
recvd_amt.write(writer)?;
29142920
previous_hop.write(writer)?;
29152921
}
29162922
}
@@ -3047,7 +3053,7 @@ impl<'a, R : ::std::io::Read> ReadableArgs<R, ChannelManagerReadArgs<'a>> for (S
30473053
let previous_hops_len: u64 = Readable::read(reader)?;
30483054
let mut previous_hops = Vec::with_capacity(cmp::min(previous_hops_len as usize, 2));
30493055
for _ in 0..previous_hops_len {
3050-
previous_hops.push(Readable::read(reader)?);
3056+
previous_hops.push((Readable::read(reader)?, Readable::read(reader)?));
30513057
}
30523058
claimable_htlcs.insert(payment_hash, previous_hops);
30533059
}

src/ln/functional_test_utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,7 @@ pub fn send_payment(origin: &Node, expected_route: &[&Node], recv_value: u64) {
713713
}
714714

715715
pub fn fail_payment_along_route(origin_node: &Node, expected_route: &[&Node], skip_last: bool, our_payment_hash: PaymentHash) {
716-
assert!(expected_route.last().unwrap().node.fail_htlc_backwards(&our_payment_hash, 0));
716+
assert!(expected_route.last().unwrap().node.fail_htlc_backwards(&our_payment_hash));
717717
expect_pending_htlcs_forwardable!(expected_route.last().unwrap());
718718
check_added_monitors!(expected_route.last().unwrap(), 1);
719719

src/ln/functional_tests.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1912,7 +1912,7 @@ fn test_htlc_on_chain_timeout() {
19121912
// Broadcast legit commitment tx from C on B's chain
19131913
let commitment_tx = nodes[2].node.channel_state.lock().unwrap().by_id.get(&chan_2.2).unwrap().last_local_commitment_txn.clone();
19141914
check_spends!(commitment_tx[0], chan_2.3.clone());
1915-
nodes[2].node.fail_htlc_backwards(&payment_hash, 0);
1915+
nodes[2].node.fail_htlc_backwards(&payment_hash);
19161916
check_added_monitors!(nodes[2], 0);
19171917
expect_pending_htlcs_forwardable!(nodes[2]);
19181918
check_added_monitors!(nodes[2], 1);
@@ -2093,7 +2093,7 @@ fn do_test_commitment_revoked_fail_backward_exhaustive(deliver_bs_raa: bool, use
20932093
let (_, second_payment_hash) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], value);
20942094
let (_, third_payment_hash) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], value);
20952095

2096-
assert!(nodes[2].node.fail_htlc_backwards(&first_payment_hash, 0));
2096+
assert!(nodes[2].node.fail_htlc_backwards(&first_payment_hash));
20972097
expect_pending_htlcs_forwardable!(nodes[2]);
20982098
check_added_monitors!(nodes[2], 1);
20992099
let updates = get_htlc_update_msgs!(nodes[2], nodes[1].node.get_our_node_id());
@@ -2106,7 +2106,7 @@ fn do_test_commitment_revoked_fail_backward_exhaustive(deliver_bs_raa: bool, use
21062106
let bs_raa = commitment_signed_dance!(nodes[1], nodes[2], updates.commitment_signed, false, true, false, true);
21072107
// Drop the last RAA from 3 -> 2
21082108

2109-
assert!(nodes[2].node.fail_htlc_backwards(&second_payment_hash, 0));
2109+
assert!(nodes[2].node.fail_htlc_backwards(&second_payment_hash));
21102110
expect_pending_htlcs_forwardable!(nodes[2]);
21112111
check_added_monitors!(nodes[2], 1);
21122112
let updates = get_htlc_update_msgs!(nodes[2], nodes[1].node.get_our_node_id());
@@ -2123,7 +2123,7 @@ fn do_test_commitment_revoked_fail_backward_exhaustive(deliver_bs_raa: bool, use
21232123
nodes[2].node.handle_revoke_and_ack(&nodes[1].node.get_our_node_id(), &as_raa).unwrap();
21242124
check_added_monitors!(nodes[2], 1);
21252125

2126-
assert!(nodes[2].node.fail_htlc_backwards(&third_payment_hash, 0));
2126+
assert!(nodes[2].node.fail_htlc_backwards(&third_payment_hash));
21272127
expect_pending_htlcs_forwardable!(nodes[2]);
21282128
check_added_monitors!(nodes[2], 1);
21292129
let updates = get_htlc_update_msgs!(nodes[2], nodes[1].node.get_our_node_id());
@@ -3769,10 +3769,10 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno
37693769

37703770
// Now fail back three of the over-dust-limit and three of the under-dust-limit payments in one go.
37713771
// Fail 0th below-dust, 4th above-dust, 8th above-dust, 10th below-dust HTLCs
3772-
assert!(nodes[4].node.fail_htlc_backwards(&payment_hash_1, ds_dust_limit*1000));
3773-
assert!(nodes[4].node.fail_htlc_backwards(&payment_hash_3, 1000000));
3774-
assert!(nodes[4].node.fail_htlc_backwards(&payment_hash_5, 1000000));
3775-
assert!(nodes[4].node.fail_htlc_backwards(&payment_hash_6, ds_dust_limit*1000));
3772+
assert!(nodes[4].node.fail_htlc_backwards(&payment_hash_1));
3773+
assert!(nodes[4].node.fail_htlc_backwards(&payment_hash_3));
3774+
assert!(nodes[4].node.fail_htlc_backwards(&payment_hash_5));
3775+
assert!(nodes[4].node.fail_htlc_backwards(&payment_hash_6));
37763776
check_added_monitors!(nodes[4], 0);
37773777
expect_pending_htlcs_forwardable!(nodes[4]);
37783778
check_added_monitors!(nodes[4], 1);
@@ -3785,8 +3785,8 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno
37853785
commitment_signed_dance!(nodes[3], nodes[4], four_removes.commitment_signed, false);
37863786

37873787
// Fail 3rd below-dust and 7th above-dust HTLCs
3788-
assert!(nodes[5].node.fail_htlc_backwards(&payment_hash_2, ds_dust_limit*1000));
3789-
assert!(nodes[5].node.fail_htlc_backwards(&payment_hash_4, 1000000));
3788+
assert!(nodes[5].node.fail_htlc_backwards(&payment_hash_2));
3789+
assert!(nodes[5].node.fail_htlc_backwards(&payment_hash_4));
37903790
check_added_monitors!(nodes[5], 0);
37913791
expect_pending_htlcs_forwardable!(nodes[5]);
37923792
check_added_monitors!(nodes[5], 1);
@@ -4079,7 +4079,7 @@ fn do_htlc_claim_previous_remote_commitment_only(use_dust: bool, check_revoke_no
40794079
// actually revoked.
40804080
let htlc_value = if use_dust { 50000 } else { 3000000 };
40814081
let (_, our_payment_hash) = route_payment(&nodes[0], &[&nodes[1]], htlc_value);
4082-
assert!(nodes[1].node.fail_htlc_backwards(&our_payment_hash, htlc_value));
4082+
assert!(nodes[1].node.fail_htlc_backwards(&our_payment_hash));
40834083
expect_pending_htlcs_forwardable!(nodes[1]);
40844084
check_added_monitors!(nodes[1], 1);
40854085

@@ -4405,7 +4405,7 @@ fn test_onion_failure() {
44054405
let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route, &session_priv).unwrap();
44064406
msg.reason = onion_utils::build_first_hop_failure_packet(&onion_keys[1].shared_secret[..], NODE|2, &[0;0]);
44074407
}, ||{
4408-
nodes[2].node.fail_htlc_backwards(&payment_hash, 0);
4408+
nodes[2].node.fail_htlc_backwards(&payment_hash);
44094409
}, true, Some(NODE|2), Some(msgs::HTLCFailChannelUpdate::NodeFailure{node_id: route.hops[1].pubkey, is_permanent: false}));
44104410

44114411
// intermediate node failure
@@ -4423,7 +4423,7 @@ fn test_onion_failure() {
44234423
let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route, &session_priv).unwrap();
44244424
msg.reason = onion_utils::build_first_hop_failure_packet(&onion_keys[1].shared_secret[..], PERM|NODE|2, &[0;0]);
44254425
}, ||{
4426-
nodes[2].node.fail_htlc_backwards(&payment_hash, 0);
4426+
nodes[2].node.fail_htlc_backwards(&payment_hash);
44274427
}, false, Some(PERM|NODE|2), Some(msgs::HTLCFailChannelUpdate::NodeFailure{node_id: route.hops[1].pubkey, is_permanent: true}));
44284428

44294429
// intermediate node failure
@@ -4434,7 +4434,7 @@ fn test_onion_failure() {
44344434
let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route, &session_priv).unwrap();
44354435
msg.reason = onion_utils::build_first_hop_failure_packet(&onion_keys[0].shared_secret[..], PERM|NODE|3, &[0;0]);
44364436
}, ||{
4437-
nodes[2].node.fail_htlc_backwards(&payment_hash, 0);
4437+
nodes[2].node.fail_htlc_backwards(&payment_hash);
44384438
}, true, Some(PERM|NODE|3), Some(msgs::HTLCFailChannelUpdate::NodeFailure{node_id: route.hops[0].pubkey, is_permanent: true}));
44394439

44404440
// final node failure
@@ -4443,7 +4443,7 @@ fn test_onion_failure() {
44434443
let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route, &session_priv).unwrap();
44444444
msg.reason = onion_utils::build_first_hop_failure_packet(&onion_keys[1].shared_secret[..], PERM|NODE|3, &[0;0]);
44454445
}, ||{
4446-
nodes[2].node.fail_htlc_backwards(&payment_hash, 0);
4446+
nodes[2].node.fail_htlc_backwards(&payment_hash);
44474447
}, false, Some(PERM|NODE|3), Some(msgs::HTLCFailChannelUpdate::NodeFailure{node_id: route.hops[1].pubkey, is_permanent: true}));
44484448

44494449
run_onion_failure_test("invalid_onion_version", 0, &nodes, &route, &payment_hash, |msg| { msg.onion_routing_packet.version = 1; }, ||{}, true,
@@ -4510,7 +4510,7 @@ fn test_onion_failure() {
45104510
}, ||{}, true, Some(UPDATE|14), Some(msgs::HTLCFailChannelUpdate::ChannelUpdateMessage{msg: ChannelUpdate::dummy()}));
45114511

45124512
run_onion_failure_test("unknown_payment_hash", 2, &nodes, &route, &payment_hash, |_| {}, || {
4513-
nodes[2].node.fail_htlc_backwards(&payment_hash, 0);
4513+
nodes[2].node.fail_htlc_backwards(&payment_hash);
45144514
}, false, Some(PERM|15), None);
45154515

45164516
run_onion_failure_test("final_expiry_too_soon", 1, &nodes, &route, &payment_hash, |msg| {

0 commit comments

Comments
 (0)