use bech32::u5;
use bitcoin_hashes::Hash;
use bitcoin_hashes::sha256;
+use lightning::ln::features::InvoiceFeatures;
#[cfg(any(doc, test))]
use lightning::routing::network_graph::RoutingFees;
-use lightning::routing::router::RouteHint;
+use lightning::routing::router::RouteHintHop;
use secp256k1::key::PublicKey;
use secp256k1::{Message, Secp256k1};
ExpiryTime(ExpiryTime),
MinFinalCltvExpiry(MinFinalCltvExpiry),
Fallback(Fallback),
- Route(Route),
+ Route(RouteHint),
PaymentSecret(PaymentSecret),
+ Features(InvoiceFeatures),
}
/// SHA-256 hash
/// The encoded route has to be <1024 5bit characters long (<=639 bytes or <=12 hops)
///
#[derive(Eq, PartialEq, Debug, Clone)]
-pub struct Route(Vec<RouteHint>);
+pub struct RouteHint(Vec<RouteHintHop>);
/// Tag constants as specified in BOLT11
#[allow(missing_docs)]
pub const TAG_FALLBACK: u8 = 9;
pub const TAG_ROUTE: u8 = 3;
pub const TAG_PAYMENT_SECRET: u8 = 16;
+ pub const TAG_FEATURES: u8 = 5;
}
impl InvoiceBuilder<tb::False, tb::False, tb::False> {
}
/// Adds a private route.
- pub fn route(mut self, route: Vec<RouteHint>) -> Self {
- match Route::new(route) {
+ pub fn route(mut self, route: Vec<RouteHintHop>) -> Self {
+ match RouteHint::new(route) {
Ok(r) => self.tagged_fields.push(TaggedField::Route(r)),
Err(e) => self.error = Some(e),
}
self
}
+
+ /// Adds a features field which indicates the set of supported protocol extensions which the
+ /// origin node supports.
+ pub fn features(mut self, features: InvoiceFeatures) -> Self {
+ self.tagged_fields.push(TaggedField::Features(features));
+ self
+ }
}
impl<D: tb::Bool, H: tb::Bool> InvoiceBuilder<D, H, tb::True> {
find_extract!(self.known_tagged_fields(), TaggedField::PaymentSecret(ref x), x)
}
+ pub fn features(&self) -> Option<&InvoiceFeatures> {
+ find_extract!(self.known_tagged_fields(), TaggedField::Features(ref x), x)
+ }
+
pub fn fallbacks(&self) -> Vec<&Fallback> {
self.known_tagged_fields().filter_map(|tf| match tf {
&TaggedField::Fallback(ref f) => Some(f),
}).collect::<Vec<&Fallback>>()
}
- pub fn routes(&self) -> Vec<&Route> {
+ pub fn routes(&self) -> Vec<&RouteHint> {
self.known_tagged_fields().filter_map(|tf| match tf {
&TaggedField::Route(ref r) => Some(r),
_ => None,
- }).collect::<Vec<&Route>>()
+ }).collect::<Vec<&RouteHint>>()
}
pub fn amount_pico_btc(&self) -> Option<u64> {
self.signed_invoice.payee_pub_key().map(|x| &x.0)
}
- /// Get the payment secret if one was included in the invoice
- pub fn payment_secret(&self) -> Option<&PaymentSecret> {
- self.signed_invoice.payment_secret()
- }
+ /// Get the payment secret if one was included in the invoice
+ pub fn payment_secret(&self) -> Option<&PaymentSecret> {
+ self.signed_invoice.payment_secret()
+ }
+
+ /// Get the invoice features if they were included in the invoice
+ pub fn features(&self) -> Option<&InvoiceFeatures> {
+ self.signed_invoice.features()
+ }
/// Recover the payee's public key (only to be used if none was included in the invoice)
pub fn recover_payee_pub_key(&self) -> PublicKey {
}
/// Returns the invoice's `min_cltv_expiry` time if present
- pub fn min_final_cltv_expiry(&self) -> Option<&u64> {
- self.signed_invoice.min_final_cltv_expiry().map(|x| &x.0)
+ pub fn min_final_cltv_expiry(&self) -> Option<u64> {
+ self.signed_invoice.min_final_cltv_expiry().map(|x| x.0)
}
/// Returns a list of all fallback addresses
}
/// Returns a list of all routes included in the invoice
- pub fn routes(&self) -> Vec<&Route> {
+ pub fn routes(&self) -> Vec<&RouteHint> {
self.signed_invoice.routes()
}
TaggedField::Fallback(_) => constants::TAG_FALLBACK,
TaggedField::Route(_) => constants::TAG_ROUTE,
TaggedField::PaymentSecret(_) => constants::TAG_PAYMENT_SECRET,
+ TaggedField::Features(_) => constants::TAG_FEATURES,
};
u5::try_from_u8(tag).expect("all tags defined are <32")
}
}
-impl Route {
+impl RouteHint {
/// Create a new (partial) route from a list of hops
- pub fn new(hops: Vec<RouteHint>) -> Result<Route, CreationError> {
+ pub fn new(hops: Vec<RouteHintHop>) -> Result<RouteHint, CreationError> {
if hops.len() <= 12 {
- Ok(Route(hops))
+ Ok(RouteHint(hops))
} else {
Err(CreationError::RouteTooLong)
}
}
/// Returrn the underlying vector of hops
- pub fn into_inner(self) -> Vec<RouteHint> {
+ pub fn into_inner(self) -> Vec<RouteHintHop> {
self.0
}
}
-impl Into<Vec<RouteHint>> for Route {
- fn into(self) -> Vec<RouteHint> {
+impl Into<Vec<RouteHintHop>> for RouteHint {
+ fn into(self) -> Vec<RouteHintHop> {
self.into_inner()
}
}
-impl Deref for Route {
- type Target = Vec<RouteHint>;
+impl Deref for RouteHint {
+ type Target = Vec<RouteHintHop>;
- fn deref(&self) -> &Vec<RouteHint> {
+ fn deref(&self) -> &Vec<RouteHintHop> {
&self.0
}
}
.build_raw();
assert_eq!(long_desc_res, Err(CreationError::DescriptionTooLong));
- let route_hop = RouteHint {
+ let route_hop = RouteHintHop {
src_node_id: PublicKey::from_slice(
&[
0x03, 0x9e, 0x03, 0xa9, 0x01, 0xb8, 0x55, 0x34, 0xff, 0x1e, 0x92, 0xc4,
let public_key = PublicKey::from_secret_key(&secp_ctx, &private_key);
let route_1 = vec![
- RouteHint {
+ RouteHintHop {
src_node_id: public_key.clone(),
short_channel_id: de::parse_int_be(&[123; 8], 256).expect("short chan ID slice too big?"),
fees: RoutingFees {
htlc_minimum_msat: None,
htlc_maximum_msat: None,
},
- RouteHint {
+ RouteHintHop {
src_node_id: public_key.clone(),
short_channel_id: de::parse_int_be(&[42; 8], 256).expect("short chan ID slice too big?"),
fees: RoutingFees {
];
let route_2 = vec![
- RouteHint {
+ RouteHintHop {
src_node_id: public_key.clone(),
short_channel_id: 0,
fees: RoutingFees {
htlc_minimum_msat: None,
htlc_maximum_msat: None,
},
- RouteHint {
+ RouteHintHop {
src_node_id: public_key.clone(),
short_channel_id: de::parse_int_be(&[1; 8], 256).expect("short chan ID slice too big?"),
fees: RoutingFees {
);
assert_eq!(invoice.payee_pub_key(), Some(&public_key));
assert_eq!(invoice.expiry_time(), Duration::from_secs(54321));
- assert_eq!(invoice.min_final_cltv_expiry(), Some(&144));
+ assert_eq!(invoice.min_final_cltv_expiry(), Some(144));
assert_eq!(invoice.fallbacks(), vec![&Fallback::PubKeyHash([0;20])]);
- assert_eq!(invoice.routes(), vec![&Route(route_1), &Route(route_2)]);
+ assert_eq!(invoice.routes(), vec![&RouteHint(route_1), &RouteHint(route_2)]);
assert_eq!(
invoice.description(),
InvoiceDescription::Hash(&Sha256(sha256::Hash::from_slice(&[3;32][..]).unwrap()))