mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-02-25 07:17:40 +01:00
Merge pull request #946 from jkczyz/2021-06-get-route-interface
Align get_route's interface with ChannelManager and Invoice
This commit is contained in:
commit
7b4b753010
6 changed files with 123 additions and 97 deletions
|
@ -16,7 +16,7 @@ use lightning::chain::transaction::OutPoint;
|
||||||
use lightning::ln::channelmanager::ChannelDetails;
|
use lightning::ln::channelmanager::ChannelDetails;
|
||||||
use lightning::ln::features::InitFeatures;
|
use lightning::ln::features::InitFeatures;
|
||||||
use lightning::ln::msgs;
|
use lightning::ln::msgs;
|
||||||
use lightning::routing::router::{get_route, RouteHintHop};
|
use lightning::routing::router::{get_route, RouteHint, RouteHintHop};
|
||||||
use lightning::util::logger::Logger;
|
use lightning::util::logger::Logger;
|
||||||
use lightning::util::ser::Readable;
|
use lightning::util::ser::Readable;
|
||||||
use lightning::routing::network_graph::{NetworkGraph, RoutingFees};
|
use lightning::routing::network_graph::{NetworkGraph, RoutingFees};
|
||||||
|
@ -225,13 +225,13 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
|
||||||
Some(&first_hops_vec[..])
|
Some(&first_hops_vec[..])
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let mut last_hops_vec = Vec::new();
|
let mut last_hops = Vec::new();
|
||||||
{
|
{
|
||||||
let count = get_slice!(1)[0];
|
let count = get_slice!(1)[0];
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
scid += 1;
|
scid += 1;
|
||||||
let rnid = node_pks.iter().skip(slice_to_be16(get_slice!(2))as usize % node_pks.len()).next().unwrap();
|
let rnid = node_pks.iter().skip(slice_to_be16(get_slice!(2))as usize % node_pks.len()).next().unwrap();
|
||||||
last_hops_vec.push(RouteHintHop {
|
last_hops.push(RouteHint(vec![RouteHintHop {
|
||||||
src_node_id: *rnid,
|
src_node_id: *rnid,
|
||||||
short_channel_id: scid,
|
short_channel_id: scid,
|
||||||
fees: RoutingFees {
|
fees: RoutingFees {
|
||||||
|
@ -241,10 +241,9 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
|
||||||
cltv_expiry_delta: slice_to_be16(get_slice!(2)),
|
cltv_expiry_delta: slice_to_be16(get_slice!(2)),
|
||||||
htlc_minimum_msat: Some(slice_to_be64(get_slice!(8))),
|
htlc_minimum_msat: Some(slice_to_be64(get_slice!(8))),
|
||||||
htlc_maximum_msat: None,
|
htlc_maximum_msat: None,
|
||||||
});
|
}]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let last_hops = &last_hops_vec[..];
|
|
||||||
for target in node_pks.iter() {
|
for target in node_pks.iter() {
|
||||||
let _ = get_route(&our_pubkey, &net_graph, target, None,
|
let _ = get_route(&our_pubkey, &net_graph, target, None,
|
||||||
first_hops.map(|c| c.iter().collect::<Vec<_>>()).as_ref().map(|a| a.as_slice()),
|
first_hops.map(|c| c.iter().collect::<Vec<_>>()).as_ref().map(|a| a.as_slice()),
|
||||||
|
|
|
@ -12,7 +12,7 @@ use bitcoin_hashes::Hash;
|
||||||
use bitcoin_hashes::sha256;
|
use bitcoin_hashes::sha256;
|
||||||
use lightning::ln::PaymentSecret;
|
use lightning::ln::PaymentSecret;
|
||||||
use lightning::routing::network_graph::RoutingFees;
|
use lightning::routing::network_graph::RoutingFees;
|
||||||
use lightning::routing::router::RouteHintHop;
|
use lightning::routing::router::{RouteHint, RouteHintHop};
|
||||||
|
|
||||||
use num_traits::{CheckedAdd, CheckedMul};
|
use num_traits::{CheckedAdd, CheckedMul};
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ use secp256k1::recovery::{RecoveryId, RecoverableSignature};
|
||||||
use secp256k1::key::PublicKey;
|
use secp256k1::key::PublicKey;
|
||||||
|
|
||||||
use super::{Invoice, Sha256, TaggedField, ExpiryTime, MinFinalCltvExpiry, Fallback, PayeePubKey, InvoiceSignature, PositiveTimestamp,
|
use super::{Invoice, Sha256, TaggedField, ExpiryTime, MinFinalCltvExpiry, Fallback, PayeePubKey, InvoiceSignature, PositiveTimestamp,
|
||||||
SemanticError, RouteHint, Description, RawTaggedField, Currency, RawHrp, SiPrefix, RawInvoice, constants, SignedRawInvoice,
|
SemanticError, PrivateRoute, Description, RawTaggedField, Currency, RawHrp, SiPrefix, RawInvoice, constants, SignedRawInvoice,
|
||||||
RawDataPart, CreationError, InvoiceFeatures};
|
RawDataPart, CreationError, InvoiceFeatures};
|
||||||
|
|
||||||
use self::hrp_sm::parse_hrp;
|
use self::hrp_sm::parse_hrp;
|
||||||
|
@ -433,8 +433,8 @@ impl FromBase32 for TaggedField {
|
||||||
Ok(TaggedField::MinFinalCltvExpiry(MinFinalCltvExpiry::from_base32(field_data)?)),
|
Ok(TaggedField::MinFinalCltvExpiry(MinFinalCltvExpiry::from_base32(field_data)?)),
|
||||||
constants::TAG_FALLBACK =>
|
constants::TAG_FALLBACK =>
|
||||||
Ok(TaggedField::Fallback(Fallback::from_base32(field_data)?)),
|
Ok(TaggedField::Fallback(Fallback::from_base32(field_data)?)),
|
||||||
constants::TAG_ROUTE =>
|
constants::TAG_PRIVATE_ROUTE =>
|
||||||
Ok(TaggedField::Route(RouteHint::from_base32(field_data)?)),
|
Ok(TaggedField::PrivateRoute(PrivateRoute::from_base32(field_data)?)),
|
||||||
constants::TAG_PAYMENT_SECRET =>
|
constants::TAG_PAYMENT_SECRET =>
|
||||||
Ok(TaggedField::PaymentSecret(PaymentSecret::from_base32(field_data)?)),
|
Ok(TaggedField::PaymentSecret(PaymentSecret::from_base32(field_data)?)),
|
||||||
constants::TAG_FEATURES =>
|
constants::TAG_FEATURES =>
|
||||||
|
@ -558,10 +558,10 @@ impl FromBase32 for Fallback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromBase32 for RouteHint {
|
impl FromBase32 for PrivateRoute {
|
||||||
type Err = ParseError;
|
type Err = ParseError;
|
||||||
|
|
||||||
fn from_base32(field_data: &[u5]) -> Result<RouteHint, ParseError> {
|
fn from_base32(field_data: &[u5]) -> Result<PrivateRoute, ParseError> {
|
||||||
let bytes = Vec::<u8>::from_base32(field_data)?;
|
let bytes = Vec::<u8>::from_base32(field_data)?;
|
||||||
|
|
||||||
if bytes.len() % 51 != 0 {
|
if bytes.len() % 51 != 0 {
|
||||||
|
@ -593,7 +593,7 @@ impl FromBase32 for RouteHint {
|
||||||
route_hops.push(hop);
|
route_hops.push(hop);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(RouteHint(route_hops))
|
Ok(PrivateRoute(RouteHint(route_hops)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -930,8 +930,8 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_route() {
|
fn test_parse_route() {
|
||||||
use lightning::routing::network_graph::RoutingFees;
|
use lightning::routing::network_graph::RoutingFees;
|
||||||
use lightning::routing::router::RouteHintHop;
|
use lightning::routing::router::{RouteHint, RouteHintHop};
|
||||||
use ::RouteHint;
|
use ::PrivateRoute;
|
||||||
use bech32::FromBase32;
|
use bech32::FromBase32;
|
||||||
use de::parse_int_be;
|
use de::parse_int_be;
|
||||||
|
|
||||||
|
@ -976,10 +976,10 @@ mod test {
|
||||||
htlc_maximum_msat: None
|
htlc_maximum_msat: None
|
||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(RouteHint::from_base32(&input), Ok(RouteHint(expected)));
|
assert_eq!(PrivateRoute::from_base32(&input), Ok(PrivateRoute(RouteHint(expected))));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
RouteHint::from_base32(&[u5::try_from_u8(0).unwrap(); 40][..]),
|
PrivateRoute::from_base32(&[u5::try_from_u8(0).unwrap(); 40][..]),
|
||||||
Err(ParseError::UnexpectedEndOfTaggedFields)
|
Err(ParseError::UnexpectedEndOfTaggedFields)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ use lightning::ln::PaymentSecret;
|
||||||
use lightning::ln::features::InvoiceFeatures;
|
use lightning::ln::features::InvoiceFeatures;
|
||||||
#[cfg(any(doc, test))]
|
#[cfg(any(doc, test))]
|
||||||
use lightning::routing::network_graph::RoutingFees;
|
use lightning::routing::network_graph::RoutingFees;
|
||||||
use lightning::routing::router::RouteHintHop;
|
use lightning::routing::router::RouteHint;
|
||||||
|
|
||||||
use secp256k1::key::PublicKey;
|
use secp256k1::key::PublicKey;
|
||||||
use secp256k1::{Message, Secp256k1};
|
use secp256k1::{Message, Secp256k1};
|
||||||
|
@ -362,7 +362,7 @@ pub enum TaggedField {
|
||||||
ExpiryTime(ExpiryTime),
|
ExpiryTime(ExpiryTime),
|
||||||
MinFinalCltvExpiry(MinFinalCltvExpiry),
|
MinFinalCltvExpiry(MinFinalCltvExpiry),
|
||||||
Fallback(Fallback),
|
Fallback(Fallback),
|
||||||
Route(RouteHint),
|
PrivateRoute(PrivateRoute),
|
||||||
PaymentSecret(PaymentSecret),
|
PaymentSecret(PaymentSecret),
|
||||||
Features(InvoiceFeatures),
|
Features(InvoiceFeatures),
|
||||||
}
|
}
|
||||||
|
@ -419,7 +419,7 @@ pub struct InvoiceSignature(pub RecoverableSignature);
|
||||||
/// The encoded route has to be <1024 5bit characters long (<=639 bytes or <=12 hops)
|
/// The encoded route has to be <1024 5bit characters long (<=639 bytes or <=12 hops)
|
||||||
///
|
///
|
||||||
#[derive(Eq, PartialEq, Debug, Clone)]
|
#[derive(Eq, PartialEq, Debug, Clone)]
|
||||||
pub struct RouteHint(Vec<RouteHintHop>);
|
pub struct PrivateRoute(RouteHint);
|
||||||
|
|
||||||
/// Tag constants as specified in BOLT11
|
/// Tag constants as specified in BOLT11
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
|
@ -431,7 +431,7 @@ pub mod constants {
|
||||||
pub const TAG_EXPIRY_TIME: u8 = 6;
|
pub const TAG_EXPIRY_TIME: u8 = 6;
|
||||||
pub const TAG_MIN_FINAL_CLTV_EXPIRY: u8 = 24;
|
pub const TAG_MIN_FINAL_CLTV_EXPIRY: u8 = 24;
|
||||||
pub const TAG_FALLBACK: u8 = 9;
|
pub const TAG_FALLBACK: u8 = 9;
|
||||||
pub const TAG_ROUTE: u8 = 3;
|
pub const TAG_PRIVATE_ROUTE: u8 = 3;
|
||||||
pub const TAG_PAYMENT_SECRET: u8 = 16;
|
pub const TAG_PAYMENT_SECRET: u8 = 16;
|
||||||
pub const TAG_FEATURES: u8 = 5;
|
pub const TAG_FEATURES: u8 = 5;
|
||||||
}
|
}
|
||||||
|
@ -509,9 +509,9 @@ impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool> InvoiceBui
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a private route.
|
/// Adds a private route.
|
||||||
pub fn route(mut self, route: Vec<RouteHintHop>) -> Self {
|
pub fn private_route(mut self, hint: RouteHint) -> Self {
|
||||||
match RouteHint::new(route) {
|
match PrivateRoute::new(hint) {
|
||||||
Ok(r) => self.tagged_fields.push(TaggedField::Route(r)),
|
Ok(r) => self.tagged_fields.push(TaggedField::PrivateRoute(r)),
|
||||||
Err(e) => self.error = Some(e),
|
Err(e) => self.error = Some(e),
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
|
@ -747,7 +747,7 @@ impl SignedRawInvoice {
|
||||||
/// Finds the first element of an enum stream of a given variant and extracts one member of the
|
/// Finds the first element of an enum stream of a given variant and extracts one member of the
|
||||||
/// variant. If no element was found `None` gets returned.
|
/// variant. If no element was found `None` gets returned.
|
||||||
///
|
///
|
||||||
/// The following example would extract the first
|
/// The following example would extract the first B.
|
||||||
/// ```
|
/// ```
|
||||||
/// use Enum::*
|
/// use Enum::*
|
||||||
///
|
///
|
||||||
|
@ -761,11 +761,35 @@ impl SignedRawInvoice {
|
||||||
/// assert_eq!(find_extract!(elements.iter(), Enum::B(ref x), x), Some(3u16))
|
/// assert_eq!(find_extract!(elements.iter(), Enum::B(ref x), x), Some(3u16))
|
||||||
/// ```
|
/// ```
|
||||||
macro_rules! find_extract {
|
macro_rules! find_extract {
|
||||||
($iter:expr, $enm:pat, $enm_var:ident) => {
|
($iter:expr, $enm:pat, $enm_var:ident) => {
|
||||||
|
find_all_extract!($iter, $enm, $enm_var).next()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finds the all elements of an enum stream of a given variant and extracts one member of the
|
||||||
|
/// variant through an iterator.
|
||||||
|
///
|
||||||
|
/// The following example would extract all A.
|
||||||
|
/// ```
|
||||||
|
/// use Enum::*
|
||||||
|
///
|
||||||
|
/// enum Enum {
|
||||||
|
/// A(u8),
|
||||||
|
/// B(u16)
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let elements = vec![A(1), A(2), B(3), A(4)]
|
||||||
|
///
|
||||||
|
/// assert_eq!(
|
||||||
|
/// find_all_extract!(elements.iter(), Enum::A(ref x), x).collect::<Vec<u8>>(),
|
||||||
|
/// vec![1u8, 2u8, 4u8])
|
||||||
|
/// ```
|
||||||
|
macro_rules! find_all_extract {
|
||||||
|
($iter:expr, $enm:pat, $enm_var:ident) => {
|
||||||
$iter.filter_map(|tf| match *tf {
|
$iter.filter_map(|tf| match *tf {
|
||||||
$enm => Some($enm_var),
|
$enm => Some($enm_var),
|
||||||
_ => None,
|
_ => None,
|
||||||
}).next()
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -886,17 +910,11 @@ impl RawInvoice {
|
||||||
|
|
||||||
/// (C-not exported) as we don't support Vec<&NonOpaqueType>
|
/// (C-not exported) as we don't support Vec<&NonOpaqueType>
|
||||||
pub fn fallbacks(&self) -> Vec<&Fallback> {
|
pub fn fallbacks(&self) -> Vec<&Fallback> {
|
||||||
self.known_tagged_fields().filter_map(|tf| match tf {
|
find_all_extract!(self.known_tagged_fields(), TaggedField::Fallback(ref x), x).collect()
|
||||||
&TaggedField::Fallback(ref f) => Some(f),
|
|
||||||
_ => None,
|
|
||||||
}).collect::<Vec<&Fallback>>()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn routes(&self) -> Vec<&RouteHint> {
|
pub fn private_routes(&self) -> Vec<&PrivateRoute> {
|
||||||
self.known_tagged_fields().filter_map(|tf| match tf {
|
find_all_extract!(self.known_tagged_fields(), TaggedField::PrivateRoute(ref x), x).collect()
|
||||||
&TaggedField::Route(ref r) => Some(r),
|
|
||||||
_ => None,
|
|
||||||
}).collect::<Vec<&RouteHint>>()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn amount_pico_btc(&self) -> Option<u64> {
|
pub fn amount_pico_btc(&self) -> Option<u64> {
|
||||||
|
@ -1048,7 +1066,7 @@ impl Invoice {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs an `Invoice` from a `SignedInvoice` by checking all its invariants.
|
/// Constructs an `Invoice` from a `SignedRawInvoice` by checking all its invariants.
|
||||||
/// ```
|
/// ```
|
||||||
/// use lightning_invoice::*;
|
/// use lightning_invoice::*;
|
||||||
///
|
///
|
||||||
|
@ -1145,8 +1163,15 @@ impl Invoice {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a list of all routes included in the invoice
|
/// Returns a list of all routes included in the invoice
|
||||||
pub fn routes(&self) -> Vec<&RouteHint> {
|
pub fn private_routes(&self) -> Vec<&PrivateRoute> {
|
||||||
self.signed_invoice.routes()
|
self.signed_invoice.private_routes()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a list of all routes included in the invoice as the underlying hints
|
||||||
|
pub fn route_hints(&self) -> Vec<&RouteHint> {
|
||||||
|
find_all_extract!(
|
||||||
|
self.signed_invoice.known_tagged_fields(), TaggedField::PrivateRoute(ref x), x
|
||||||
|
).map(|route| &**route).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the currency for which the invoice was issued
|
/// Returns the currency for which the invoice was issued
|
||||||
|
@ -1177,7 +1202,7 @@ impl TaggedField {
|
||||||
TaggedField::ExpiryTime(_) => constants::TAG_EXPIRY_TIME,
|
TaggedField::ExpiryTime(_) => constants::TAG_EXPIRY_TIME,
|
||||||
TaggedField::MinFinalCltvExpiry(_) => constants::TAG_MIN_FINAL_CLTV_EXPIRY,
|
TaggedField::MinFinalCltvExpiry(_) => constants::TAG_MIN_FINAL_CLTV_EXPIRY,
|
||||||
TaggedField::Fallback(_) => constants::TAG_FALLBACK,
|
TaggedField::Fallback(_) => constants::TAG_FALLBACK,
|
||||||
TaggedField::Route(_) => constants::TAG_ROUTE,
|
TaggedField::PrivateRoute(_) => constants::TAG_PRIVATE_ROUTE,
|
||||||
TaggedField::PaymentSecret(_) => constants::TAG_PAYMENT_SECRET,
|
TaggedField::PaymentSecret(_) => constants::TAG_PAYMENT_SECRET,
|
||||||
TaggedField::Features(_) => constants::TAG_FEATURES,
|
TaggedField::Features(_) => constants::TAG_FEATURES,
|
||||||
};
|
};
|
||||||
|
@ -1268,32 +1293,32 @@ impl ExpiryTime {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RouteHint {
|
impl PrivateRoute {
|
||||||
/// Create a new (partial) route from a list of hops
|
/// Creates a new (partial) route from a list of hops
|
||||||
pub fn new(hops: Vec<RouteHintHop>) -> Result<RouteHint, CreationError> {
|
pub fn new(hops: RouteHint) -> Result<PrivateRoute, CreationError> {
|
||||||
if hops.len() <= 12 {
|
if hops.0.len() <= 12 {
|
||||||
Ok(RouteHint(hops))
|
Ok(PrivateRoute(hops))
|
||||||
} else {
|
} else {
|
||||||
Err(CreationError::RouteTooLong)
|
Err(CreationError::RouteTooLong)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returrn the underlying vector of hops
|
/// Returns the underlying list of hops
|
||||||
pub fn into_inner(self) -> Vec<RouteHintHop> {
|
pub fn into_inner(self) -> RouteHint {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<Vec<RouteHintHop>> for RouteHint {
|
impl Into<RouteHint> for PrivateRoute {
|
||||||
fn into(self) -> Vec<RouteHintHop> {
|
fn into(self) -> RouteHint {
|
||||||
self.into_inner()
|
self.into_inner()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for RouteHint {
|
impl Deref for PrivateRoute {
|
||||||
type Target = Vec<RouteHintHop>;
|
type Target = RouteHint;
|
||||||
|
|
||||||
fn deref(&self) -> &Vec<RouteHintHop> {
|
fn deref(&self) -> &RouteHint {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1652,6 +1677,7 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_builder_fail() {
|
fn test_builder_fail() {
|
||||||
use ::*;
|
use ::*;
|
||||||
|
use lightning::routing::router::RouteHintHop;
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
use secp256k1::key::PublicKey;
|
use secp256k1::key::PublicKey;
|
||||||
|
|
||||||
|
@ -1686,10 +1712,10 @@ mod test {
|
||||||
htlc_minimum_msat: None,
|
htlc_minimum_msat: None,
|
||||||
htlc_maximum_msat: None,
|
htlc_maximum_msat: None,
|
||||||
};
|
};
|
||||||
let too_long_route = vec![route_hop; 13];
|
let too_long_route = RouteHint(vec![route_hop; 13]);
|
||||||
let long_route_res = builder.clone()
|
let long_route_res = builder.clone()
|
||||||
.description("Test".into())
|
.description("Test".into())
|
||||||
.route(too_long_route)
|
.private_route(too_long_route)
|
||||||
.build_raw();
|
.build_raw();
|
||||||
assert_eq!(long_route_res, Err(CreationError::RouteTooLong));
|
assert_eq!(long_route_res, Err(CreationError::RouteTooLong));
|
||||||
|
|
||||||
|
@ -1704,6 +1730,7 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_builder_ok() {
|
fn test_builder_ok() {
|
||||||
use ::*;
|
use ::*;
|
||||||
|
use lightning::routing::router::RouteHintHop;
|
||||||
use secp256k1::Secp256k1;
|
use secp256k1::Secp256k1;
|
||||||
use secp256k1::key::{SecretKey, PublicKey};
|
use secp256k1::key::{SecretKey, PublicKey};
|
||||||
use std::time::{UNIX_EPOCH, Duration};
|
use std::time::{UNIX_EPOCH, Duration};
|
||||||
|
@ -1719,7 +1746,7 @@ mod test {
|
||||||
).unwrap();
|
).unwrap();
|
||||||
let public_key = PublicKey::from_secret_key(&secp_ctx, &private_key);
|
let public_key = PublicKey::from_secret_key(&secp_ctx, &private_key);
|
||||||
|
|
||||||
let route_1 = vec![
|
let route_1 = RouteHint(vec![
|
||||||
RouteHintHop {
|
RouteHintHop {
|
||||||
src_node_id: public_key.clone(),
|
src_node_id: public_key.clone(),
|
||||||
short_channel_id: de::parse_int_be(&[123; 8], 256).expect("short chan ID slice too big?"),
|
short_channel_id: de::parse_int_be(&[123; 8], 256).expect("short chan ID slice too big?"),
|
||||||
|
@ -1742,9 +1769,9 @@ mod test {
|
||||||
htlc_minimum_msat: None,
|
htlc_minimum_msat: None,
|
||||||
htlc_maximum_msat: None,
|
htlc_maximum_msat: None,
|
||||||
}
|
}
|
||||||
];
|
]);
|
||||||
|
|
||||||
let route_2 = vec![
|
let route_2 = RouteHint(vec![
|
||||||
RouteHintHop {
|
RouteHintHop {
|
||||||
src_node_id: public_key.clone(),
|
src_node_id: public_key.clone(),
|
||||||
short_channel_id: 0,
|
short_channel_id: 0,
|
||||||
|
@ -1767,7 +1794,7 @@ mod test {
|
||||||
htlc_minimum_msat: None,
|
htlc_minimum_msat: None,
|
||||||
htlc_maximum_msat: None,
|
htlc_maximum_msat: None,
|
||||||
}
|
}
|
||||||
];
|
]);
|
||||||
|
|
||||||
let builder = InvoiceBuilder::new(Currency::BitcoinTestnet)
|
let builder = InvoiceBuilder::new(Currency::BitcoinTestnet)
|
||||||
.amount_pico_btc(123)
|
.amount_pico_btc(123)
|
||||||
|
@ -1776,8 +1803,8 @@ mod test {
|
||||||
.expiry_time(Duration::from_secs(54321))
|
.expiry_time(Duration::from_secs(54321))
|
||||||
.min_final_cltv_expiry(144)
|
.min_final_cltv_expiry(144)
|
||||||
.fallback(Fallback::PubKeyHash([0;20]))
|
.fallback(Fallback::PubKeyHash([0;20]))
|
||||||
.route(route_1.clone())
|
.private_route(route_1.clone())
|
||||||
.route(route_2.clone())
|
.private_route(route_2.clone())
|
||||||
.description_hash(sha256::Hash::from_slice(&[3;32][..]).unwrap())
|
.description_hash(sha256::Hash::from_slice(&[3;32][..]).unwrap())
|
||||||
.payment_hash(sha256::Hash::from_slice(&[21;32][..]).unwrap())
|
.payment_hash(sha256::Hash::from_slice(&[21;32][..]).unwrap())
|
||||||
.payment_secret(PaymentSecret([42; 32]))
|
.payment_secret(PaymentSecret([42; 32]))
|
||||||
|
@ -1800,7 +1827,7 @@ mod test {
|
||||||
assert_eq!(invoice.expiry_time(), Duration::from_secs(54321));
|
assert_eq!(invoice.expiry_time(), Duration::from_secs(54321));
|
||||||
assert_eq!(invoice.min_final_cltv_expiry(), 144);
|
assert_eq!(invoice.min_final_cltv_expiry(), 144);
|
||||||
assert_eq!(invoice.fallbacks(), vec![&Fallback::PubKeyHash([0;20])]);
|
assert_eq!(invoice.fallbacks(), vec![&Fallback::PubKeyHash([0;20])]);
|
||||||
assert_eq!(invoice.routes(), vec![&RouteHint(route_1), &RouteHint(route_2)]);
|
assert_eq!(invoice.private_routes(), vec![&PrivateRoute(route_1), &PrivateRoute(route_2)]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
invoice.description(),
|
invoice.description(),
|
||||||
InvoiceDescription::Hash(&Sha256(sha256::Hash::from_slice(&[3;32][..]).unwrap()))
|
InvoiceDescription::Hash(&Sha256(sha256::Hash::from_slice(&[3;32][..]).unwrap()))
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::fmt::{Display, Formatter};
|
||||||
use bech32::{ToBase32, u5, WriteBase32, Base32Len};
|
use bech32::{ToBase32, u5, WriteBase32, Base32Len};
|
||||||
|
|
||||||
use super::{Invoice, Sha256, TaggedField, ExpiryTime, MinFinalCltvExpiry, Fallback, PayeePubKey, InvoiceSignature, PositiveTimestamp,
|
use super::{Invoice, Sha256, TaggedField, ExpiryTime, MinFinalCltvExpiry, Fallback, PayeePubKey, InvoiceSignature, PositiveTimestamp,
|
||||||
RouteHint, Description, RawTaggedField, Currency, RawHrp, SiPrefix, constants, SignedRawInvoice, RawDataPart};
|
PrivateRoute, Description, RawTaggedField, Currency, RawHrp, SiPrefix, constants, SignedRawInvoice, RawDataPart};
|
||||||
|
|
||||||
/// Converts a stream of bytes written to it to base32. On finalization the according padding will
|
/// Converts a stream of bytes written to it to base32. On finalization the according padding will
|
||||||
/// be applied. That means the results of writing two data blocks with one or two `BytesToBase32`
|
/// be applied. That means the results of writing two data blocks with one or two `BytesToBase32`
|
||||||
|
@ -356,11 +356,11 @@ impl Base32Len for Fallback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToBase32 for RouteHint {
|
impl ToBase32 for PrivateRoute {
|
||||||
fn write_base32<W: WriteBase32>(&self, writer: &mut W) -> Result<(), <W as WriteBase32>::Err> {
|
fn write_base32<W: WriteBase32>(&self, writer: &mut W) -> Result<(), <W as WriteBase32>::Err> {
|
||||||
let mut converter = BytesToBase32::new(writer);
|
let mut converter = BytesToBase32::new(writer);
|
||||||
|
|
||||||
for hop in self.iter() {
|
for hop in (self.0).0.iter() {
|
||||||
converter.append(&hop.src_node_id.serialize()[..])?;
|
converter.append(&hop.src_node_id.serialize()[..])?;
|
||||||
let short_channel_id = try_stretch(
|
let short_channel_id = try_stretch(
|
||||||
encode_int_be_base256(hop.short_channel_id),
|
encode_int_be_base256(hop.short_channel_id),
|
||||||
|
@ -392,9 +392,9 @@ impl ToBase32 for RouteHint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Base32Len for RouteHint {
|
impl Base32Len for PrivateRoute {
|
||||||
fn base32_len(&self) -> usize {
|
fn base32_len(&self) -> usize {
|
||||||
bytes_size_to_base32_size(self.0.len() * 51)
|
bytes_size_to_base32_size((self.0).0.len() * 51)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,8 +439,8 @@ impl ToBase32 for TaggedField {
|
||||||
TaggedField::Fallback(ref fallback_address) => {
|
TaggedField::Fallback(ref fallback_address) => {
|
||||||
write_tagged_field(writer, constants::TAG_FALLBACK, fallback_address)
|
write_tagged_field(writer, constants::TAG_FALLBACK, fallback_address)
|
||||||
},
|
},
|
||||||
TaggedField::Route(ref route_hops) => {
|
TaggedField::PrivateRoute(ref route_hops) => {
|
||||||
write_tagged_field(writer, constants::TAG_ROUTE, route_hops)
|
write_tagged_field(writer, constants::TAG_PRIVATE_ROUTE, route_hops)
|
||||||
},
|
},
|
||||||
TaggedField::PaymentSecret(ref payment_secret) => {
|
TaggedField::PaymentSecret(ref payment_secret) => {
|
||||||
write_tagged_field(writer, constants::TAG_PAYMENT_SECRET, payment_secret)
|
write_tagged_field(writer, constants::TAG_PAYMENT_SECRET, payment_secret)
|
||||||
|
|
|
@ -7,7 +7,7 @@ use lightning::chain::chaininterface::{BroadcasterInterface, FeeEstimator};
|
||||||
use lightning::chain::keysinterface::{Sign, KeysInterface};
|
use lightning::chain::keysinterface::{Sign, KeysInterface};
|
||||||
use lightning::ln::channelmanager::{ChannelManager, MIN_FINAL_CLTV_EXPIRY};
|
use lightning::ln::channelmanager::{ChannelManager, MIN_FINAL_CLTV_EXPIRY};
|
||||||
use lightning::routing::network_graph::RoutingFees;
|
use lightning::routing::network_graph::RoutingFees;
|
||||||
use lightning::routing::router::RouteHintHop;
|
use lightning::routing::router::{RouteHint, RouteHintHop};
|
||||||
use lightning::util::logger::Logger;
|
use lightning::util::logger::Logger;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
@ -40,7 +40,7 @@ where
|
||||||
Some(info) => info,
|
Some(info) => info,
|
||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
route_hints.push(vec![RouteHintHop {
|
route_hints.push(RouteHint(vec![RouteHintHop {
|
||||||
src_node_id: channel.remote_network_id,
|
src_node_id: channel.remote_network_id,
|
||||||
short_channel_id,
|
short_channel_id,
|
||||||
fees: RoutingFees {
|
fees: RoutingFees {
|
||||||
|
@ -50,7 +50,7 @@ where
|
||||||
cltv_expiry_delta: forwarding_info.cltv_expiry_delta,
|
cltv_expiry_delta: forwarding_info.cltv_expiry_delta,
|
||||||
htlc_minimum_msat: None,
|
htlc_minimum_msat: None,
|
||||||
htlc_maximum_msat: None,
|
htlc_maximum_msat: None,
|
||||||
}]);
|
}]));
|
||||||
}
|
}
|
||||||
|
|
||||||
let (payment_hash, payment_secret) = channelmanager.create_inbound_payment(
|
let (payment_hash, payment_secret) = channelmanager.create_inbound_payment(
|
||||||
|
@ -70,8 +70,8 @@ where
|
||||||
if let Some(amt) = amt_msat {
|
if let Some(amt) = amt_msat {
|
||||||
invoice = invoice.amount_pico_btc(amt * 10);
|
invoice = invoice.amount_pico_btc(amt * 10);
|
||||||
}
|
}
|
||||||
for hint in route_hints.drain(..) {
|
for hint in route_hints {
|
||||||
invoice = invoice.route(hint);
|
invoice = invoice.private_route(hint);
|
||||||
}
|
}
|
||||||
|
|
||||||
let raw_invoice = match invoice.build_raw() {
|
let raw_invoice = match invoice.build_raw() {
|
||||||
|
@ -112,14 +112,9 @@ mod test {
|
||||||
assert_eq!(invoice.min_final_cltv_expiry(), MIN_FINAL_CLTV_EXPIRY as u64);
|
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.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 amt_msat = invoice.amount_pico_btc().unwrap() / 10;
|
||||||
|
|
||||||
let first_hops = nodes[0].node.list_usable_channels();
|
let first_hops = nodes[0].node.list_usable_channels();
|
||||||
|
let last_hops = invoice.route_hints();
|
||||||
let network_graph = nodes[0].net_graph_msg_handler.network_graph.read().unwrap();
|
let network_graph = nodes[0].net_graph_msg_handler.network_graph.read().unwrap();
|
||||||
let logger = test_utils::TestLogger::new();
|
let logger = test_utils::TestLogger::new();
|
||||||
let route = router::get_route(
|
let route = router::get_route(
|
||||||
|
@ -128,7 +123,7 @@ mod test {
|
||||||
&invoice.recover_payee_pub_key(),
|
&invoice.recover_payee_pub_key(),
|
||||||
Some(invoice.features().unwrap().clone()),
|
Some(invoice.features().unwrap().clone()),
|
||||||
Some(&first_hops.iter().collect::<Vec<_>>()),
|
Some(&first_hops.iter().collect::<Vec<_>>()),
|
||||||
&last_hops.iter().collect::<Vec<_>>(),
|
&last_hops,
|
||||||
amt_msat,
|
amt_msat,
|
||||||
invoice.min_final_cltv_expiry() as u32,
|
invoice.min_final_cltv_expiry() as u32,
|
||||||
&logger,
|
&logger,
|
||||||
|
|
|
@ -107,7 +107,11 @@ impl Readable for Route {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A channel descriptor which provides a last-hop route to get_route
|
/// A list of hops along a payment path terminating with a channel to the recipient.
|
||||||
|
#[derive(Eq, PartialEq, Debug, Clone)]
|
||||||
|
pub struct RouteHint(pub Vec<RouteHintHop>);
|
||||||
|
|
||||||
|
/// A channel descriptor for a hop along a payment path.
|
||||||
#[derive(Eq, PartialEq, Debug, Clone)]
|
#[derive(Eq, PartialEq, Debug, Clone)]
|
||||||
pub struct RouteHintHop {
|
pub struct RouteHintHop {
|
||||||
/// The node_id of the non-target end of the route
|
/// The node_id of the non-target end of the route
|
||||||
|
@ -329,8 +333,8 @@ fn compute_fees(amount_msat: u64, channel_fees: RoutingFees) -> Option<u64> {
|
||||||
/// If the payee provided features in their invoice, they should be provided via payee_features.
|
/// If the payee provided features in their invoice, they should be provided via payee_features.
|
||||||
/// Without this, MPP will only be used if the payee's features are available in the network graph.
|
/// Without this, MPP will only be used if the payee's features are available in the network graph.
|
||||||
///
|
///
|
||||||
/// Extra routing hops between known nodes and the target will be used if they are included in
|
/// Private routing paths between a public node and the target may be included in `last_hops`.
|
||||||
/// last_hops.
|
/// Currently, only the last hop in each path is considered.
|
||||||
///
|
///
|
||||||
/// If some channels aren't announced, it may be useful to fill in a first_hops with the
|
/// If some channels aren't announced, it may be useful to fill in a first_hops with the
|
||||||
/// results from a local ChannelManager::list_usable_channels() call. If it is filled in, our
|
/// results from a local ChannelManager::list_usable_channels() call. If it is filled in, our
|
||||||
|
@ -344,7 +348,7 @@ fn compute_fees(amount_msat: u64, channel_fees: RoutingFees) -> Option<u64> {
|
||||||
/// equal), however the enabled/disabled bit on such channels as well as the
|
/// equal), however the enabled/disabled bit on such channels as well as the
|
||||||
/// htlc_minimum_msat/htlc_maximum_msat *are* checked as they may change based on the receiving node.
|
/// htlc_minimum_msat/htlc_maximum_msat *are* checked as they may change based on the receiving node.
|
||||||
pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, payee: &PublicKey, payee_features: Option<InvoiceFeatures>, first_hops: Option<&[&ChannelDetails]>,
|
pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, payee: &PublicKey, payee_features: Option<InvoiceFeatures>, first_hops: Option<&[&ChannelDetails]>,
|
||||||
last_hops: &[&RouteHintHop], final_value_msat: u64, final_cltv: u32, logger: L) -> Result<Route, LightningError> where L::Target: Logger {
|
last_hops: &[&RouteHint], final_value_msat: u64, final_cltv: u32, logger: L) -> Result<Route, LightningError> where L::Target: Logger {
|
||||||
// TODO: Obviously *only* using total fee cost sucks. We should consider weighting by
|
// TODO: Obviously *only* using total fee cost sucks. We should consider weighting by
|
||||||
// uptime/success in using a node in the past.
|
// uptime/success in using a node in the past.
|
||||||
if *payee == *our_node_id {
|
if *payee == *our_node_id {
|
||||||
|
@ -359,7 +363,8 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
|
||||||
return Err(LightningError{err: "Cannot send a payment of 0 msat".to_owned(), action: ErrorAction::IgnoreError});
|
return Err(LightningError{err: "Cannot send a payment of 0 msat".to_owned(), action: ErrorAction::IgnoreError});
|
||||||
}
|
}
|
||||||
|
|
||||||
for last_hop in last_hops {
|
let last_hops = last_hops.iter().filter_map(|hops| hops.0.last()).collect::<Vec<_>>();
|
||||||
|
for last_hop in last_hops.iter() {
|
||||||
if last_hop.src_node_id == *payee {
|
if last_hop.src_node_id == *payee {
|
||||||
return Err(LightningError{err: "Last hop cannot have a payee as a source.".to_owned(), action: ErrorAction::IgnoreError});
|
return Err(LightningError{err: "Last hop cannot have a payee as a source.".to_owned(), action: ErrorAction::IgnoreError});
|
||||||
}
|
}
|
||||||
|
@ -1154,7 +1159,7 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use routing::router::{get_route, RouteHintHop, RoutingFees};
|
use routing::router::{get_route, RouteHint, RouteHintHop, RoutingFees};
|
||||||
use routing::network_graph::{NetworkGraph, NetGraphMsgHandler};
|
use routing::network_graph::{NetworkGraph, NetGraphMsgHandler};
|
||||||
use chain::transaction::OutPoint;
|
use chain::transaction::OutPoint;
|
||||||
use ln::features::{ChannelFeatures, InitFeatures, InvoiceFeatures, NodeFeatures};
|
use ln::features::{ChannelFeatures, InitFeatures, InvoiceFeatures, NodeFeatures};
|
||||||
|
@ -2085,19 +2090,19 @@ mod tests {
|
||||||
assert_eq!(route.paths[0][1].channel_features.le_flags(), &id_to_feature_flags(13));
|
assert_eq!(route.paths[0][1].channel_features.le_flags(), &id_to_feature_flags(13));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn last_hops(nodes: &Vec<PublicKey>) -> Vec<RouteHintHop> {
|
fn last_hops(nodes: &Vec<PublicKey>) -> Vec<RouteHint> {
|
||||||
let zero_fees = RoutingFees {
|
let zero_fees = RoutingFees {
|
||||||
base_msat: 0,
|
base_msat: 0,
|
||||||
proportional_millionths: 0,
|
proportional_millionths: 0,
|
||||||
};
|
};
|
||||||
vec!(RouteHintHop {
|
vec![RouteHint(vec![RouteHintHop {
|
||||||
src_node_id: nodes[3].clone(),
|
src_node_id: nodes[3].clone(),
|
||||||
short_channel_id: 8,
|
short_channel_id: 8,
|
||||||
fees: zero_fees,
|
fees: zero_fees,
|
||||||
cltv_expiry_delta: (8 << 8) | 1,
|
cltv_expiry_delta: (8 << 8) | 1,
|
||||||
htlc_minimum_msat: None,
|
htlc_minimum_msat: None,
|
||||||
htlc_maximum_msat: None,
|
htlc_maximum_msat: None,
|
||||||
}, RouteHintHop {
|
}]), RouteHint(vec![RouteHintHop {
|
||||||
src_node_id: nodes[4].clone(),
|
src_node_id: nodes[4].clone(),
|
||||||
short_channel_id: 9,
|
short_channel_id: 9,
|
||||||
fees: RoutingFees {
|
fees: RoutingFees {
|
||||||
|
@ -2107,14 +2112,14 @@ mod tests {
|
||||||
cltv_expiry_delta: (9 << 8) | 1,
|
cltv_expiry_delta: (9 << 8) | 1,
|
||||||
htlc_minimum_msat: None,
|
htlc_minimum_msat: None,
|
||||||
htlc_maximum_msat: None,
|
htlc_maximum_msat: None,
|
||||||
}, RouteHintHop {
|
}]), RouteHint(vec![RouteHintHop {
|
||||||
src_node_id: nodes[5].clone(),
|
src_node_id: nodes[5].clone(),
|
||||||
short_channel_id: 10,
|
short_channel_id: 10,
|
||||||
fees: zero_fees,
|
fees: zero_fees,
|
||||||
cltv_expiry_delta: (10 << 8) | 1,
|
cltv_expiry_delta: (10 << 8) | 1,
|
||||||
htlc_minimum_msat: None,
|
htlc_minimum_msat: None,
|
||||||
htlc_maximum_msat: None,
|
htlc_maximum_msat: None,
|
||||||
})
|
}])]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -2124,8 +2129,8 @@ mod tests {
|
||||||
|
|
||||||
// Simple test across 2, 3, 5, and 4 via a last_hop channel
|
// Simple test across 2, 3, 5, and 4 via a last_hop channel
|
||||||
|
|
||||||
// First check that lst hop can't have its source as the payee.
|
// First check that last hop can't have its source as the payee.
|
||||||
let invalid_last_hop = RouteHintHop {
|
let invalid_last_hop = RouteHint(vec![RouteHintHop {
|
||||||
src_node_id: nodes[6],
|
src_node_id: nodes[6],
|
||||||
short_channel_id: 8,
|
short_channel_id: 8,
|
||||||
fees: RoutingFees {
|
fees: RoutingFees {
|
||||||
|
@ -2135,7 +2140,7 @@ mod tests {
|
||||||
cltv_expiry_delta: (8 << 8) | 1,
|
cltv_expiry_delta: (8 << 8) | 1,
|
||||||
htlc_minimum_msat: None,
|
htlc_minimum_msat: None,
|
||||||
htlc_maximum_msat: None,
|
htlc_maximum_msat: None,
|
||||||
};
|
}]);
|
||||||
|
|
||||||
let mut invalid_last_hops = last_hops(&nodes);
|
let mut invalid_last_hops = last_hops(&nodes);
|
||||||
invalid_last_hops.push(invalid_last_hop);
|
invalid_last_hops.push(invalid_last_hop);
|
||||||
|
@ -2224,7 +2229,7 @@ mod tests {
|
||||||
assert_eq!(route.paths[0][1].node_features.le_flags(), &Vec::<u8>::new()); // We dont pass flags in from invoices yet
|
assert_eq!(route.paths[0][1].node_features.le_flags(), &Vec::<u8>::new()); // We dont pass flags in from invoices yet
|
||||||
assert_eq!(route.paths[0][1].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly
|
assert_eq!(route.paths[0][1].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly
|
||||||
|
|
||||||
last_hops[0].fees.base_msat = 1000;
|
last_hops[0].0[0].fees.base_msat = 1000;
|
||||||
|
|
||||||
// Revert to via 6 as the fee on 8 goes up
|
// Revert to via 6 as the fee on 8 goes up
|
||||||
let route = get_route(&our_id, &net_graph_msg_handler.network_graph.read().unwrap(), &nodes[6], None, None, &last_hops.iter().collect::<Vec<_>>(), 100, 42, Arc::clone(&logger)).unwrap();
|
let route = get_route(&our_id, &net_graph_msg_handler.network_graph.read().unwrap(), &nodes[6], None, None, &last_hops.iter().collect::<Vec<_>>(), 100, 42, Arc::clone(&logger)).unwrap();
|
||||||
|
@ -2312,7 +2317,7 @@ mod tests {
|
||||||
let target_node_id = PublicKey::from_secret_key(&Secp256k1::new(), &SecretKey::from_slice(&hex::decode(format!("{:02}", 43).repeat(32)).unwrap()[..]).unwrap());
|
let target_node_id = PublicKey::from_secret_key(&Secp256k1::new(), &SecretKey::from_slice(&hex::decode(format!("{:02}", 43).repeat(32)).unwrap()[..]).unwrap());
|
||||||
|
|
||||||
// If we specify a channel to a middle hop, that overrides our local channel view and that gets used
|
// If we specify a channel to a middle hop, that overrides our local channel view and that gets used
|
||||||
let last_hops = vec![RouteHintHop {
|
let last_hops = RouteHint(vec![RouteHintHop {
|
||||||
src_node_id: middle_node_id,
|
src_node_id: middle_node_id,
|
||||||
short_channel_id: 8,
|
short_channel_id: 8,
|
||||||
fees: RoutingFees {
|
fees: RoutingFees {
|
||||||
|
@ -2322,7 +2327,7 @@ mod tests {
|
||||||
cltv_expiry_delta: (8 << 8) | 1,
|
cltv_expiry_delta: (8 << 8) | 1,
|
||||||
htlc_minimum_msat: None,
|
htlc_minimum_msat: None,
|
||||||
htlc_maximum_msat: None,
|
htlc_maximum_msat: None,
|
||||||
}];
|
}]);
|
||||||
let our_chans = vec![channelmanager::ChannelDetails {
|
let our_chans = vec![channelmanager::ChannelDetails {
|
||||||
channel_id: [0; 32],
|
channel_id: [0; 32],
|
||||||
funding_txo: Some(OutPoint { txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0 }),
|
funding_txo: Some(OutPoint { txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0 }),
|
||||||
|
@ -2337,7 +2342,7 @@ mod tests {
|
||||||
is_usable: true, is_public: true,
|
is_usable: true, is_public: true,
|
||||||
counterparty_forwarding_info: None,
|
counterparty_forwarding_info: None,
|
||||||
}];
|
}];
|
||||||
let route = get_route(&source_node_id, &NetworkGraph::new(genesis_block(Network::Testnet).header.block_hash()), &target_node_id, None, Some(&our_chans.iter().collect::<Vec<_>>()), &last_hops.iter().collect::<Vec<_>>(), 100, 42, Arc::new(test_utils::TestLogger::new())).unwrap();
|
let route = get_route(&source_node_id, &NetworkGraph::new(genesis_block(Network::Testnet).header.block_hash()), &target_node_id, None, Some(&our_chans.iter().collect::<Vec<_>>()), &vec![&last_hops], 100, 42, Arc::new(test_utils::TestLogger::new())).unwrap();
|
||||||
|
|
||||||
assert_eq!(route.paths[0].len(), 2);
|
assert_eq!(route.paths[0].len(), 2);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue