use lightning::ln::features::InvoiceFeatures;
#[cfg(any(doc, test))]
use lightning::routing::network_graph::RoutingFees;
-use lightning::routing::router::RouteHintHop;
+use lightning::routing::router::RouteHint;
use secp256k1::key::PublicKey;
use secp256k1::{Message, Secp256k1};
/// Default expiry time as defined by [BOLT 11].
///
/// [BOLT 11]: https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md
-const DEFAULT_EXPIRY_TIME: u64 = 3600;
+pub const DEFAULT_EXPIRY_TIME: u64 = 3600;
/// Default minimum final CLTV expiry as defined by [BOLT 11].
///
+/// Note that this is *not* the same value as rust-lightning's minimum CLTV expiry, which is
+/// provided in [`MIN_FINAL_CLTV_EXPIRY`].
+///
/// [BOLT 11]: https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md
-const DEFAULT_MIN_FINAL_CLTV_EXPIRY: u64 = 18;
+/// [`MIN_FINAL_CLTV_EXPIRY`]: lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY
+pub const DEFAULT_MIN_FINAL_CLTV_EXPIRY: u64 = 18;
/// This function is used as a static assert for the size of `SystemTime`. If the crate fails to
/// compile due to it this indicates that your system uses unexpected bounds for `SystemTime`. You
ExpiryTime(ExpiryTime),
MinFinalCltvExpiry(MinFinalCltvExpiry),
Fallback(Fallback),
- Route(RouteHint),
+ PrivateRoute(PrivateRoute),
PaymentSecret(PaymentSecret),
Features(InvoiceFeatures),
}
/// The encoded route has to be <1024 5bit characters long (<=639 bytes or <=12 hops)
///
#[derive(Eq, PartialEq, Debug, Clone)]
-pub struct RouteHint(Vec<RouteHintHop>);
+pub struct PrivateRoute(RouteHint);
/// Tag constants as specified in BOLT11
#[allow(missing_docs)]
pub const TAG_EXPIRY_TIME: u8 = 6;
pub const TAG_MIN_FINAL_CLTV_EXPIRY: u8 = 24;
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_FEATURES: u8 = 5;
}
}
/// Adds a private route.
- pub fn route(mut self, route: Vec<RouteHintHop>) -> Self {
- match RouteHint::new(route) {
- Ok(r) => self.tagged_fields.push(TaggedField::Route(r)),
+ pub fn private_route(mut self, hint: RouteHint) -> Self {
+ match PrivateRoute::new(hint) {
+ Ok(r) => self.tagged_fields.push(TaggedField::PrivateRoute(r)),
Err(e) => self.error = Some(e),
}
self
/// 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.
///
-/// The following example would extract the first
+/// The following example would extract the first B.
/// ```
/// use Enum::*
///
/// assert_eq!(find_extract!(elements.iter(), Enum::B(ref x), x), Some(3u16))
/// ```
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 {
$enm => Some($enm_var),
_ => None,
- }).next()
+ })
};
}
/// (C-not exported) as we don't support Vec<&NonOpaqueType>
pub fn fallbacks(&self) -> Vec<&Fallback> {
- self.known_tagged_fields().filter_map(|tf| match tf {
- &TaggedField::Fallback(ref f) => Some(f),
- _ => None,
- }).collect::<Vec<&Fallback>>()
+ find_all_extract!(self.known_tagged_fields(), TaggedField::Fallback(ref x), x).collect()
}
- pub fn routes(&self) -> Vec<&RouteHint> {
- self.known_tagged_fields().filter_map(|tf| match tf {
- &TaggedField::Route(ref r) => Some(r),
- _ => None,
- }).collect::<Vec<&RouteHint>>()
+ pub fn private_routes(&self) -> Vec<&PrivateRoute> {
+ find_all_extract!(self.known_tagged_fields(), TaggedField::PrivateRoute(ref x), x).collect()
}
pub fn amount_pico_btc(&self) -> Option<u64> {
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::*;
///
}
/// Returns a list of all routes included in the invoice
- pub fn routes(&self) -> Vec<&RouteHint> {
- self.signed_invoice.routes()
+ pub fn private_routes(&self) -> Vec<&PrivateRoute> {
+ 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
TaggedField::ExpiryTime(_) => constants::TAG_EXPIRY_TIME,
TaggedField::MinFinalCltvExpiry(_) => constants::TAG_MIN_FINAL_CLTV_EXPIRY,
TaggedField::Fallback(_) => constants::TAG_FALLBACK,
- TaggedField::Route(_) => constants::TAG_ROUTE,
+ TaggedField::PrivateRoute(_) => constants::TAG_PRIVATE_ROUTE,
TaggedField::PaymentSecret(_) => constants::TAG_PAYMENT_SECRET,
TaggedField::Features(_) => constants::TAG_FEATURES,
};
}
}
-impl RouteHint {
- /// Create a new (partial) route from a list of hops
- pub fn new(hops: Vec<RouteHintHop>) -> Result<RouteHint, CreationError> {
- if hops.len() <= 12 {
- Ok(RouteHint(hops))
+impl PrivateRoute {
+ /// Creates a new (partial) route from a list of hops
+ pub fn new(hops: RouteHint) -> Result<PrivateRoute, CreationError> {
+ if hops.0.len() <= 12 {
+ Ok(PrivateRoute(hops))
} else {
Err(CreationError::RouteTooLong)
}
}
- /// Returrn the underlying vector of hops
- pub fn into_inner(self) -> Vec<RouteHintHop> {
+ /// Returns the underlying list of hops
+ pub fn into_inner(self) -> RouteHint {
self.0
}
}
-impl Into<Vec<RouteHintHop>> for RouteHint {
- fn into(self) -> Vec<RouteHintHop> {
+impl Into<RouteHint> for PrivateRoute {
+ fn into(self) -> RouteHint {
self.into_inner()
}
}
-impl Deref for RouteHint {
- type Target = Vec<RouteHintHop>;
+impl Deref for PrivateRoute {
+ type Target = RouteHint;
- fn deref(&self) -> &Vec<RouteHintHop> {
+ fn deref(&self) -> &RouteHint {
&self.0
}
}
#[test]
fn test_builder_fail() {
use ::*;
+ use lightning::routing::router::RouteHintHop;
use std::iter::FromIterator;
use secp256k1::key::PublicKey;
htlc_minimum_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()
.description("Test".into())
- .route(too_long_route)
+ .private_route(too_long_route)
.build_raw();
assert_eq!(long_route_res, Err(CreationError::RouteTooLong));
#[test]
fn test_builder_ok() {
use ::*;
+ use lightning::routing::router::RouteHintHop;
use secp256k1::Secp256k1;
use secp256k1::key::{SecretKey, PublicKey};
use std::time::{UNIX_EPOCH, Duration};
).unwrap();
let public_key = PublicKey::from_secret_key(&secp_ctx, &private_key);
- let route_1 = vec![
+ let route_1 = RouteHint(vec![
RouteHintHop {
src_node_id: public_key.clone(),
short_channel_id: de::parse_int_be(&[123; 8], 256).expect("short chan ID slice too big?"),
htlc_minimum_msat: None,
htlc_maximum_msat: None,
}
- ];
+ ]);
- let route_2 = vec![
+ let route_2 = RouteHint(vec![
RouteHintHop {
src_node_id: public_key.clone(),
short_channel_id: 0,
htlc_minimum_msat: None,
htlc_maximum_msat: None,
}
- ];
+ ]);
let builder = InvoiceBuilder::new(Currency::BitcoinTestnet)
.amount_pico_btc(123)
.expiry_time(Duration::from_secs(54321))
.min_final_cltv_expiry(144)
.fallback(Fallback::PubKeyHash([0;20]))
- .route(route_1.clone())
- .route(route_2.clone())
+ .private_route(route_1.clone())
+ .private_route(route_2.clone())
.description_hash(sha256::Hash::from_slice(&[3;32][..]).unwrap())
.payment_hash(sha256::Hash::from_slice(&[21;32][..]).unwrap())
.payment_secret(PaymentSecret([42; 32]))
assert_eq!(invoice.expiry_time(), Duration::from_secs(54321));
assert_eq!(invoice.min_final_cltv_expiry(), 144);
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!(
invoice.description(),
InvoiceDescription::Hash(&Sha256(sha256::Hash::from_slice(&[3;32][..]).unwrap()))