X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning-invoice%2Fsrc%2Futils.rs;h=8da9994a3f7729ea1df9c407dd567fc811782d6a;hb=61341df39e90de9d650851a624c0644f5c9dd055;hp=20247ed321a72d87180ccc6347c1cd7e6f9f55a2;hpb=8cde7e8db9b7a4084bd47d506d039b7decdd8c41;p=rust-lightning diff --git a/lightning-invoice/src/utils.rs b/lightning-invoice/src/utils.rs index 20247ed3..8da9994a 100644 --- a/lightning-invoice/src/utils.rs +++ b/lightning-invoice/src/utils.rs @@ -1,15 +1,22 @@ //! Convenient utilities to create an invoice. -use {Currency, Invoice, InvoiceBuilder, SignOrCreationError, RawInvoice}; + +use {Currency, DEFAULT_EXPIRY_TIME, Invoice, InvoiceBuilder, SignOrCreationError, RawInvoice}; +use payment::{Payer, Router}; + use bech32::ToBase32; use bitcoin_hashes::Hash; use lightning::chain; use lightning::chain::chaininterface::{BroadcasterInterface, FeeEstimator}; use lightning::chain::keysinterface::{Sign, KeysInterface}; -use lightning::ln::channelmanager::{ChannelManager, MIN_FINAL_CLTV_EXPIRY}; -use lightning::ln::features::InvoiceFeatures; -use lightning::routing::network_graph::RoutingFees; -use lightning::routing::router::RouteHintHop; +use lightning::ln::{PaymentHash, PaymentSecret}; +use lightning::ln::channelmanager::{ChannelDetails, ChannelManager, PaymentId, PaymentSendFailure, MIN_FINAL_CLTV_EXPIRY}; +use lightning::ln::msgs::LightningError; +use lightning::routing; +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 std::convert::TryInto; use std::ops::Deref; /// Utility to construct an invoice. Generally, unless you want to do something like a custom @@ -36,12 +43,12 @@ where Some(id) => id, None => continue, }; - let forwarding_info = match channel.counterparty_forwarding_info { + let forwarding_info = match channel.counterparty.forwarding_info { Some(info) => info, None => continue, }; - route_hints.push(vec![RouteHintHop { - src_node_id: channel.remote_network_id, + route_hints.push(RouteHint(vec![RouteHintHop { + src_node_id: channel.counterparty.node_id, short_channel_id, fees: RoutingFees { base_msat: forwarding_info.fee_base_msat, @@ -50,12 +57,12 @@ where cltv_expiry_delta: forwarding_info.cltv_expiry_delta, htlc_minimum_msat: None, htlc_maximum_msat: None, - }]); + }])); } let (payment_hash, payment_secret) = channelmanager.create_inbound_payment( amt_msat, - 7200, // default invoice expiry is 2 hours + DEFAULT_EXPIRY_TIME.try_into().unwrap(), 0, ); let our_node_pubkey = channelmanager.get_our_node_id(); @@ -65,13 +72,13 @@ where .payee_pub_key(our_node_pubkey) .payment_hash(Hash::from_slice(&payment_hash.0).unwrap()) .payment_secret(payment_secret) - .features(InvoiceFeatures::known()) + .basic_mpp() .min_final_cltv_expiry(MIN_FINAL_CLTV_EXPIRY.into()); if let Some(amt) = amt_msat { - invoice = invoice.amount_pico_btc(amt * 10); + invoice = invoice.amount_milli_satoshis(amt); } - for hint in route_hints.drain(..) { - invoice = invoice.route(hint); + for hint in route_hints { + invoice = invoice.private_route(hint); } let raw_invoice = match invoice.build_raw() { @@ -89,14 +96,68 @@ where } } +/// A [`Router`] implemented using [`find_route`]. +pub struct DefaultRouter where G: Deref, L::Target: Logger { + network_graph: G, + logger: L, +} + +impl DefaultRouter where G: Deref, L::Target: Logger { + /// Creates a new router using the given [`NetworkGraph`] and [`Logger`]. + pub fn new(network_graph: G, logger: L) -> Self { + Self { network_graph, logger } + } +} + +impl Router for DefaultRouter +where G: Deref, L::Target: Logger { + fn find_route( + &self, payer: &PublicKey, params: &RouteParameters, first_hops: Option<&[&ChannelDetails]>, + scorer: &S + ) -> Result { + find_route(payer, params, &*self.network_graph, first_hops, &*self.logger, scorer) + } +} + +impl Payer for ChannelManager +where + M::Target: chain::Watch, + T::Target: BroadcasterInterface, + K::Target: KeysInterface, + F::Target: FeeEstimator, + L::Target: Logger, +{ + fn node_id(&self) -> PublicKey { + self.get_our_node_id() + } + + fn first_hops(&self) -> Vec { + self.list_usable_channels() + } + + fn send_payment( + &self, route: &Route, payment_hash: PaymentHash, payment_secret: &Option + ) -> Result { + self.send_payment(route, payment_hash, payment_secret) + } + + fn retry_payment( + &self, route: &Route, payment_id: PaymentId + ) -> Result<(), PaymentSendFailure> { + self.retry_payment(route, payment_id) + } +} + #[cfg(test)] mod test { use {Currency, Description, InvoiceDescription}; use lightning::ln::PaymentHash; + use lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY; use lightning::ln::functional_test_utils::*; use lightning::ln::features::InitFeatures; use lightning::ln::msgs::ChannelMessageHandler; - use lightning::routing::router; + use lightning::routing::router::{Payee, RouteParameters, find_route}; + use lightning::routing::scorer::Scorer; use lightning::util::events::MessageSendEventsProvider; use lightning::util::test_utils; #[test] @@ -108,35 +169,30 @@ mod test { let _chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()); let invoice = ::utils::create_invoice_from_channelmanager(&nodes[1].node, nodes[1].keys_manager, Currency::BitcoinTestnet, Some(10_000), "test".to_string()).unwrap(); assert_eq!(invoice.amount_pico_btc(), Some(100_000)); - assert_eq!(invoice.min_final_cltv_expiry(), 9); + assert_eq!(invoice.min_final_cltv_expiry(), MIN_FINAL_CLTV_EXPIRY as u64); assert_eq!(invoice.description(), InvoiceDescription::Direct(&Description("test".to_string()))); - let mut route_hints = invoice.routes().clone(); - let mut last_hops = Vec::new(); - for hint in route_hints.drain(..) { - last_hops.push(hint[hint.len() - 1].clone()); - } - let amt_msat = invoice.amount_pico_btc().unwrap() / 10; - + let payee = Payee::new(invoice.recover_payee_pub_key()) + .with_features(invoice.features().unwrap().clone()) + .with_route_hints(invoice.route_hints()); + let params = RouteParameters { + payee, + final_value_msat: invoice.amount_milli_satoshis().unwrap(), + final_cltv_expiry_delta: invoice.min_final_cltv_expiry() as u32, + }; let first_hops = nodes[0].node.list_usable_channels(); - let network_graph = nodes[0].net_graph_msg_handler.network_graph.read().unwrap(); + let network_graph = &nodes[0].net_graph_msg_handler.network_graph; let logger = test_utils::TestLogger::new(); - let route = router::get_route( - &nodes[0].node.get_our_node_id(), - &network_graph, - &invoice.recover_payee_pub_key(), - Some(invoice.features().unwrap().clone()), - Some(&first_hops.iter().collect::>()), - &last_hops.iter().collect::>(), - amt_msat, - invoice.min_final_cltv_expiry() as u32, - &logger, + let scorer = Scorer::with_fixed_penalty(0); + let route = find_route( + &nodes[0].node.get_our_node_id(), ¶ms, network_graph, + Some(&first_hops.iter().collect::>()), &logger, &scorer, ).unwrap(); let payment_event = { let mut payment_hash = PaymentHash([0; 32]); payment_hash.0.copy_from_slice(&invoice.payment_hash().as_ref()[0..32]); - nodes[0].node.send_payment(&route, payment_hash, &Some(invoice.payment_secret().unwrap().clone())).unwrap(); + nodes[0].node.send_payment(&route, payment_hash, &Some(invoice.payment_secret().clone())).unwrap(); let mut added_monitors = nodes[0].chain_monitor.added_monitors.lock().unwrap(); assert_eq!(added_monitors.len(), 1); added_monitors.clear();