use lightning::routing::network_graph::{NetworkGraph, RoutingFees};
use lightning::routing::router::{Route, RouteHint, RouteHintHop, RouteParameters, find_route};
use lightning::util::logger::Logger;
-use secp256k1::key::PublicKey;
+use secp256k1::PublicKey;
use core::convert::TryInto;
use core::ops::Deref;
use core::time::Duration;
.current_timestamp()
.payment_hash(Hash::from_slice(&payment_hash.0).unwrap())
.payment_secret(payment_secret)
- .min_final_cltv_expiry(MIN_FINAL_CLTV_EXPIRY.into());
+ .min_final_cltv_expiry(MIN_FINAL_CLTV_EXPIRY.into())
+ .expiry_time(Duration::from_secs(invoice_expiry_delta_secs.into()));
if let Some(amt) = amt_msat {
invoice = invoice.amount_milli_satoshis(amt);
}
proportional_millionths: forwarding_info.fee_proportional_millionths,
},
cltv_expiry_delta: forwarding_info.cltv_expiry_delta,
- htlc_minimum_msat: None,
- htlc_maximum_msat: None,}])
+ htlc_minimum_msat: channel.inbound_htlc_minimum_msat,
+ htlc_maximum_msat: channel.inbound_htlc_maximum_msat,}])
};
// If all channels are private, return the route hint for the highest inbound capacity channel
// per counterparty node. If channels with an higher inbound capacity than the
// Invoice SCIDs should always use inbound SCID aliases over the real channel ID, if one is
// available.
+ let chan = &nodes[1].node.list_usable_channels()[0];
assert_eq!(invoice.route_hints().len(), 1);
assert_eq!(invoice.route_hints()[0].0.len(), 1);
- assert_eq!(invoice.route_hints()[0].0[0].short_channel_id,
- nodes[1].node.list_usable_channels()[0].inbound_scid_alias.unwrap());
+ assert_eq!(invoice.route_hints()[0].0[0].short_channel_id, chan.inbound_scid_alias.unwrap());
+
+ assert_eq!(invoice.route_hints()[0].0[0].htlc_minimum_msat, chan.inbound_htlc_minimum_msat);
+ assert_eq!(invoice.route_hints()[0].0[0].htlc_maximum_msat, chan.inbound_htlc_maximum_msat);
let payment_params = PaymentParameters::from_node_id(invoice.recover_payee_pub_key())
.with_features(invoice.features().unwrap().clone())
} else {
None
};
+ let non_default_invoice_expiry_secs = 4200;
- let invoice = ::utils::create_phantom_invoice::<EnforcingSigner, &test_utils::TestKeysInterface>(Some(payment_amt), payment_hash, "test".to_string(), 3600, route_hints, &nodes[1].keys_manager, Currency::BitcoinTestnet).unwrap();
+ let invoice = ::utils::create_phantom_invoice::<
+ EnforcingSigner, &test_utils::TestKeysInterface
+ >(
+ Some(payment_amt), payment_hash, "test".to_string(), non_default_invoice_expiry_secs,
+ route_hints, &nodes[1].keys_manager, Currency::BitcoinTestnet
+ ).unwrap();
let (payment_hash, payment_secret) = (PaymentHash(invoice.payment_hash().into_inner()), *invoice.payment_secret());
let payment_preimage = if user_generated_pmt_hash {
user_payment_preimage
assert_eq!(invoice.min_final_cltv_expiry(), MIN_FINAL_CLTV_EXPIRY as u64);
assert_eq!(invoice.description(), InvoiceDescription::Direct(&Description("test".to_string())));
assert_eq!(invoice.route_hints().len(), 2);
+ assert_eq!(invoice.expiry_time(), Duration::from_secs(non_default_invoice_expiry_secs.into()));
assert!(!invoice.features().unwrap().supports_basic_mpp());
let payment_params = PaymentParameters::from_node_id(invoice.recover_payee_pub_key())
}
}
+ #[test]
+ #[cfg(feature = "std")]
+ fn test_multi_node_hints_has_htlc_min_max_values() {
+ let mut chanmon_cfgs = create_chanmon_cfgs(3);
+ let seed_1 = [42 as u8; 32];
+ let seed_2 = [43 as u8; 32];
+ let cross_node_seed = [44 as u8; 32];
+ chanmon_cfgs[1].keys_manager.backing = PhantomKeysManager::new(&seed_1, 43, 44, &cross_node_seed);
+ chanmon_cfgs[2].keys_manager.backing = PhantomKeysManager::new(&seed_2, 43, 44, &cross_node_seed);
+ let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
+ let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
+ let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
+
+ create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+ create_unannounced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001, InitFeatures::known(), InitFeatures::known());
+
+ let payment_amt = 20_000;
+ let (payment_hash, _payment_secret) = nodes[1].node.create_inbound_payment(Some(payment_amt), 3600).unwrap();
+ let route_hints = vec![
+ nodes[1].node.get_phantom_route_hints(),
+ nodes[2].node.get_phantom_route_hints(),
+ ];
+
+ let invoice = ::utils::create_phantom_invoice::<EnforcingSigner, &test_utils::TestKeysInterface>(Some(payment_amt), Some(payment_hash), "test".to_string(), 3600, route_hints, &nodes[1].keys_manager, Currency::BitcoinTestnet).unwrap();
+
+ let chan_0_1 = &nodes[1].node.list_usable_channels()[0];
+ assert_eq!(invoice.route_hints()[0].0[0].htlc_minimum_msat, chan_0_1.inbound_htlc_minimum_msat);
+ assert_eq!(invoice.route_hints()[0].0[0].htlc_maximum_msat, chan_0_1.inbound_htlc_maximum_msat);
+
+ let chan_0_2 = &nodes[2].node.list_usable_channels()[0];
+ assert_eq!(invoice.route_hints()[1].0[0].htlc_minimum_msat, chan_0_2.inbound_htlc_minimum_msat);
+ assert_eq!(invoice.route_hints()[1].0[0].htlc_maximum_msat, chan_0_2.inbound_htlc_maximum_msat);
+ }
+
#[test]
#[cfg(feature = "std")]
fn create_phantom_invoice_with_description_hash() {
];
let description_hash = crate::Sha256(Hash::hash("Description hash phantom invoice".as_bytes()));
- let invoice = ::utils::create_phantom_invoice_with_description_hash::<EnforcingSigner,&test_utils::TestKeysInterface>(Some(payment_amt), None, 3600, description_hash, route_hints, &nodes[1].keys_manager, Currency::BitcoinTestnet).unwrap();
-
+ let non_default_invoice_expiry_secs = 4200;
+ let invoice = ::utils::create_phantom_invoice_with_description_hash::<
+ EnforcingSigner, &test_utils::TestKeysInterface,
+ >(
+ Some(payment_amt), None, non_default_invoice_expiry_secs, description_hash,
+ route_hints, &nodes[1].keys_manager, Currency::BitcoinTestnet
+ )
+ .unwrap();
assert_eq!(invoice.amount_pico_btc(), Some(200_000));
assert_eq!(invoice.min_final_cltv_expiry(), MIN_FINAL_CLTV_EXPIRY as u64);
+ assert_eq!(invoice.expiry_time(), Duration::from_secs(non_default_invoice_expiry_secs.into()));
assert_eq!(invoice.description(), InvoiceDescription::Hash(&crate::Sha256(Sha256::hash("Description hash phantom invoice".as_bytes()))));
}