|
12 | 12 | //! returned errors decode to the correct thing.
|
13 | 13 |
|
14 | 14 | use chain::channelmonitor::{CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS};
|
| 15 | +use chain::keysinterface::{KeysInterface, Recipient}; |
15 | 16 | use ln::{PaymentHash, PaymentSecret};
|
16 |
| -use ln::channelmanager::{HTLCForwardInfo, CLTV_FAR_FAR_AWAY}; |
| 17 | +use ln::channelmanager::{HTLCForwardInfo, CLTV_FAR_FAR_AWAY, MIN_CLTV_EXPIRY_DELTA, PendingHTLCInfo, PendingHTLCRouting}; |
17 | 18 | use ln::onion_utils;
|
18 |
| -use routing::network_graph::NetworkUpdate; |
19 |
| -use routing::router::Route; |
20 |
| -use ln::features::InitFeatures; |
| 19 | +use routing::network_graph::{NetworkUpdate, RoutingFees}; |
| 20 | +use routing::router::{get_route, PaymentParameters, Route, RouteHint, RouteHintHop}; |
| 21 | +use ln::features::{InitFeatures, InvoiceFeatures}; |
21 | 22 | use ln::msgs;
|
22 | 23 | use ln::msgs::{ChannelMessageHandler, ChannelUpdate, OptionalField};
|
23 | 24 | use util::events::{Event, MessageSendEvent, MessageSendEventsProvider};
|
24 | 25 | use util::ser::{Writeable, Writer};
|
| 26 | +use util::{byte_utils, test_utils}; |
25 | 27 | use util::config::UserConfig;
|
26 | 28 |
|
27 | 29 | use bitcoin::hash_types::BlockHash;
|
28 | 30 |
|
29 | 31 | use bitcoin::hashes::Hash;
|
| 32 | +use bitcoin::hashes::sha256::Hash as Sha256; |
30 | 33 |
|
31 | 34 | use bitcoin::secp256k1;
|
32 | 35 | use bitcoin::secp256k1::Secp256k1;
|
33 |
| -use bitcoin::secp256k1::key::SecretKey; |
| 36 | +use bitcoin::secp256k1::key::{PublicKey, SecretKey}; |
34 | 37 |
|
35 | 38 | use io;
|
36 | 39 | use prelude::*;
|
@@ -573,3 +576,232 @@ fn test_onion_failure() {
|
573 | 576 | nodes[2].node.fail_htlc_backwards(&payment_hash);
|
574 | 577 | }, true, Some(23), None, None);
|
575 | 578 | }
|
| 579 | + |
| 580 | +macro_rules! get_phantom_route { |
| 581 | + ($nodes: expr, $amt: expr, $channel: expr) => {{ |
| 582 | + let secp_ctx = Secp256k1::new(); |
| 583 | + let phantom_secret = $nodes[1].keys_manager.get_node_secret(Recipient::PhantomNode).unwrap(); |
| 584 | + let phantom_pubkey = PublicKey::from_secret_key(&secp_ctx, &phantom_secret); |
| 585 | + let phantom_route_hint = $nodes[1].node.get_phantom_route_hints(); |
| 586 | + let payment_params = PaymentParameters::from_node_id(phantom_pubkey) |
| 587 | + .with_features(InvoiceFeatures::known()) |
| 588 | + .with_route_hints(vec![RouteHint(vec![ |
| 589 | + RouteHintHop { |
| 590 | + src_node_id: $nodes[0].node.get_our_node_id(), |
| 591 | + short_channel_id: $channel.0.contents.short_channel_id, |
| 592 | + fees: RoutingFees { |
| 593 | + base_msat: $channel.0.contents.fee_base_msat, |
| 594 | + proportional_millionths: $channel.0.contents.fee_proportional_millionths, |
| 595 | + }, |
| 596 | + cltv_expiry_delta: $channel.0.contents.cltv_expiry_delta, |
| 597 | + htlc_minimum_msat: None, |
| 598 | + htlc_maximum_msat: None, |
| 599 | + }, |
| 600 | + RouteHintHop { |
| 601 | + src_node_id: phantom_route_hint.real_node_pubkey, |
| 602 | + short_channel_id: phantom_route_hint.phantom_scid, |
| 603 | + fees: RoutingFees { |
| 604 | + base_msat: 0, |
| 605 | + proportional_millionths: 0, |
| 606 | + }, |
| 607 | + cltv_expiry_delta: MIN_CLTV_EXPIRY_DELTA, |
| 608 | + htlc_minimum_msat: None, |
| 609 | + htlc_maximum_msat: None, |
| 610 | + } |
| 611 | + ])]); |
| 612 | + let scorer = test_utils::TestScorer::with_penalty(0); |
| 613 | + (get_route( |
| 614 | + &$nodes[0].node.get_our_node_id(), &payment_params, $nodes[0].network_graph, |
| 615 | + Some(&$nodes[0].node.list_usable_channels().iter().collect::<Vec<_>>()), |
| 616 | + $amt, TEST_FINAL_CLTV, $nodes[0].logger, &scorer |
| 617 | + ).unwrap(), phantom_route_hint.phantom_scid) |
| 618 | + } |
| 619 | +}} |
| 620 | + |
| 621 | +#[test] |
| 622 | +fn test_phantom_onion_hmac_failure() { |
| 623 | + let chanmon_cfgs = create_chanmon_cfgs(2); |
| 624 | + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); |
| 625 | + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); |
| 626 | + let nodes = create_network(2, &node_cfgs, &node_chanmgrs); |
| 627 | + |
| 628 | + let channel = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()); |
| 629 | + |
| 630 | + // Get the route. |
| 631 | + let recv_value_msat = 10_000; |
| 632 | + let (_, payment_hash, payment_secret) = get_payment_preimage_hash!(nodes[1], Some(recv_value_msat)); |
| 633 | + let (route, phantom_scid) = get_phantom_route!(nodes, recv_value_msat, channel); |
| 634 | + |
| 635 | + // Route the HTLC through to the destination. |
| 636 | + nodes[0].node.send_payment(&route, payment_hash.clone(), &Some(payment_secret)).unwrap(); |
| 637 | + check_added_monitors!(nodes[0], 1); |
| 638 | + let update_0 = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id()); |
| 639 | + let mut update_add = update_0.update_add_htlcs[0].clone(); |
| 640 | + |
| 641 | + nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &update_add); |
| 642 | + commitment_signed_dance!(nodes[1], nodes[0], &update_0.commitment_signed, false, true); |
| 643 | + |
| 644 | + // Modify the payload so the phantom hop's HMAC is bogus. |
| 645 | + let sha256_of_onion = { |
| 646 | + let mut channel_state = nodes[1].node.channel_state.lock().unwrap(); |
| 647 | + let mut pending_forward = channel_state.forward_htlcs.get_mut(&phantom_scid).unwrap(); |
| 648 | + match pending_forward[0] { |
| 649 | + HTLCForwardInfo::AddHTLC { |
| 650 | + forward_info: PendingHTLCInfo { |
| 651 | + routing: PendingHTLCRouting::Forward { ref mut onion_packet, .. }, |
| 652 | + .. |
| 653 | + }, .. |
| 654 | + } => { |
| 655 | + onion_packet.hmac[onion_packet.hmac.len() - 1] ^= 1; |
| 656 | + Sha256::hash(&onion_packet.hop_data).into_inner().to_vec() |
| 657 | + }, |
| 658 | + _ => panic!("Unexpected forward"), |
| 659 | + } |
| 660 | + }; |
| 661 | + expect_pending_htlcs_forwardable_ignore!(nodes[1]); |
| 662 | + nodes[1].node.process_pending_htlc_forwards(); |
| 663 | + expect_pending_htlcs_forwardable_ignore!(nodes[1]); |
| 664 | + nodes[1].node.process_pending_htlc_forwards(); |
| 665 | + let update_1 = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id()); |
| 666 | + check_added_monitors!(&nodes[1], 1); |
| 667 | + assert!(update_1.update_fail_htlcs.len() == 1); |
| 668 | + let fail_msg = update_1.update_fail_htlcs[0].clone(); |
| 669 | + nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &fail_msg); |
| 670 | + commitment_signed_dance!(nodes[0], nodes[1], update_1.commitment_signed, false); |
| 671 | + |
| 672 | + // Ensure the payment fails with the expected error. |
| 673 | + let mut fail_conditions = PaymentFailedConditions::new() |
| 674 | + .blamed_scid(phantom_scid) |
| 675 | + .blamed_chan_closed(true) |
| 676 | + .expected_htlc_error_data(0x8000 | 0x4000 | 5, &sha256_of_onion); |
| 677 | + expect_payment_failed_conditions!(nodes[0], payment_hash, false, fail_conditions); |
| 678 | +} |
| 679 | + |
| 680 | +#[test] |
| 681 | +fn test_phantom_invalid_onion_payload() { |
| 682 | + let chanmon_cfgs = create_chanmon_cfgs(2); |
| 683 | + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); |
| 684 | + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); |
| 685 | + let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs); |
| 686 | + |
| 687 | + let channel = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()); |
| 688 | + |
| 689 | + // Get the route. |
| 690 | + let recv_value_msat = 10_000; |
| 691 | + let (_, payment_hash, payment_secret) = get_payment_preimage_hash!(nodes[1], Some(recv_value_msat)); |
| 692 | + let (route, phantom_scid) = get_phantom_route!(nodes, recv_value_msat, channel); |
| 693 | + |
| 694 | + // We'll use the session priv later when constructing an invalid onion packet. |
| 695 | + let session_priv = [3; 32]; |
| 696 | + *nodes[0].keys_manager.override_session_priv.lock().unwrap() = Some(session_priv); |
| 697 | + nodes[0].node.send_payment(&route, payment_hash.clone(), &Some(payment_secret)).unwrap(); |
| 698 | + check_added_monitors!(nodes[0], 1); |
| 699 | + let update_0 = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id()); |
| 700 | + let mut update_add = update_0.update_add_htlcs[0].clone(); |
| 701 | + |
| 702 | + nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &update_add); |
| 703 | + commitment_signed_dance!(nodes[1], nodes[0], &update_0.commitment_signed, false, true); |
| 704 | + |
| 705 | + // Modify the onion packet to have an invalid payment amount. |
| 706 | + for (_, pending_forwards) in nodes[1].node.channel_state.lock().unwrap().forward_htlcs.iter_mut() { |
| 707 | + for f in pending_forwards.iter_mut() { |
| 708 | + match f { |
| 709 | + &mut HTLCForwardInfo::AddHTLC { |
| 710 | + forward_info: PendingHTLCInfo { |
| 711 | + routing: PendingHTLCRouting::Forward { ref mut onion_packet, .. }, |
| 712 | + .. |
| 713 | + }, .. |
| 714 | + } => { |
| 715 | + // Construct the onion payloads for the entire route and an invalid amount. |
| 716 | + let height = nodes[0].best_block_info().1; |
| 717 | + let session_priv = SecretKey::from_slice(&session_priv).unwrap(); |
| 718 | + let mut onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap(); |
| 719 | + let (mut onion_payloads, _, _) = onion_utils::build_onion_payloads(&route.paths[0], msgs::MAX_VALUE_MSAT + 1, &Some(payment_secret), height + 1, &None).unwrap(); |
| 720 | + // We only want to construct the onion packet for the last hop, not the entire route, so |
| 721 | + // remove the first hop's payload and its keys. |
| 722 | + onion_keys.remove(0); |
| 723 | + onion_payloads.remove(0); |
| 724 | + |
| 725 | + let new_onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash); |
| 726 | + onion_packet.hop_data = new_onion_packet.hop_data; |
| 727 | + onion_packet.hmac = new_onion_packet.hmac; |
| 728 | + }, |
| 729 | + _ => panic!("Unexpected forward"), |
| 730 | + } |
| 731 | + } |
| 732 | + } |
| 733 | + expect_pending_htlcs_forwardable_ignore!(nodes[1]); |
| 734 | + nodes[1].node.process_pending_htlc_forwards(); |
| 735 | + expect_pending_htlcs_forwardable_ignore!(nodes[1]); |
| 736 | + nodes[1].node.process_pending_htlc_forwards(); |
| 737 | + let update_1 = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id()); |
| 738 | + check_added_monitors!(&nodes[1], 1); |
| 739 | + assert!(update_1.update_fail_htlcs.len() == 1); |
| 740 | + let fail_msg = update_1.update_fail_htlcs[0].clone(); |
| 741 | + nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &fail_msg); |
| 742 | + commitment_signed_dance!(nodes[0], nodes[1], update_1.commitment_signed, false); |
| 743 | + |
| 744 | + // Ensure the payment fails with the expected error. |
| 745 | + let error_data = Vec::new(); |
| 746 | + let mut fail_conditions = PaymentFailedConditions::new() |
| 747 | + .blamed_scid(phantom_scid) |
| 748 | + .blamed_chan_closed(true) |
| 749 | + .expected_htlc_error_data(0x4000 | 22, &error_data); |
| 750 | + expect_payment_failed_conditions!(nodes[0], payment_hash, true, fail_conditions); |
| 751 | +} |
| 752 | + |
| 753 | +#[test] |
| 754 | +fn test_phantom_final_incorrect_cltv_expiry() { |
| 755 | + let chanmon_cfgs = create_chanmon_cfgs(2); |
| 756 | + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); |
| 757 | + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); |
| 758 | + let nodes = create_network(2, &node_cfgs, &node_chanmgrs); |
| 759 | + |
| 760 | + let channel = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()); |
| 761 | + |
| 762 | + // Get the route. |
| 763 | + let recv_value_msat = 10_000; |
| 764 | + let (_, payment_hash, payment_secret) = get_payment_preimage_hash!(nodes[1], Some(recv_value_msat)); |
| 765 | + let (route, phantom_scid) = get_phantom_route!(nodes, recv_value_msat, channel); |
| 766 | + |
| 767 | + // Route the HTLC through to the destination. |
| 768 | + nodes[0].node.send_payment(&route, payment_hash.clone(), &Some(payment_secret)).unwrap(); |
| 769 | + check_added_monitors!(nodes[0], 1); |
| 770 | + let update_0 = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id()); |
| 771 | + let mut update_add = update_0.update_add_htlcs[0].clone(); |
| 772 | + |
| 773 | + nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &update_add); |
| 774 | + commitment_signed_dance!(nodes[1], nodes[0], &update_0.commitment_signed, false, true); |
| 775 | + |
| 776 | + // Modify the payload so the phantom hop's HMAC is bogus. |
| 777 | + for (_, pending_forwards) in nodes[1].node.channel_state.lock().unwrap().forward_htlcs.iter_mut() { |
| 778 | + for f in pending_forwards.iter_mut() { |
| 779 | + match f { |
| 780 | + &mut HTLCForwardInfo::AddHTLC { |
| 781 | + forward_info: PendingHTLCInfo { ref mut outgoing_cltv_value, .. }, .. |
| 782 | + } => { |
| 783 | + *outgoing_cltv_value += 1; |
| 784 | + }, |
| 785 | + _ => panic!("Unexpected forward"), |
| 786 | + } |
| 787 | + } |
| 788 | + } |
| 789 | + expect_pending_htlcs_forwardable_ignore!(nodes[1]); |
| 790 | + nodes[1].node.process_pending_htlc_forwards(); |
| 791 | + expect_pending_htlcs_forwardable_ignore!(nodes[1]); |
| 792 | + nodes[1].node.process_pending_htlc_forwards(); |
| 793 | + let update_1 = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id()); |
| 794 | + check_added_monitors!(&nodes[1], 1); |
| 795 | + assert!(update_1.update_fail_htlcs.len() == 1); |
| 796 | + let fail_msg = update_1.update_fail_htlcs[0].clone(); |
| 797 | + nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &fail_msg); |
| 798 | + commitment_signed_dance!(nodes[0], nodes[1], update_1.commitment_signed, false); |
| 799 | + |
| 800 | + // Ensure the payment fails with the expected error. |
| 801 | + let expected_cltv = 82; |
| 802 | + let error_data = byte_utils::be32_to_array(expected_cltv).to_vec(); |
| 803 | + let mut fail_conditions = PaymentFailedConditions::new() |
| 804 | + .blamed_scid(phantom_scid) |
| 805 | + .expected_htlc_error_data(18, &error_data); |
| 806 | + expect_payment_failed_conditions!(nodes[0], payment_hash, false, fail_conditions); |
| 807 | +} |
0 commit comments