Skip to content

Commit

Permalink
Merge pull request #2730 from benthecarman/invoice-utils
Browse files Browse the repository at this point in the history
Add some public utilities to `lightning_invoice`
  • Loading branch information
TheBlueMatt authored Nov 15, 2023
2 parents fb670c8 + e80e8c8 commit 9c9e5f8
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 26 deletions.
44 changes: 26 additions & 18 deletions lightning-invoice/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ pub use lightning::ln::PaymentSecret;
pub use lightning::routing::router::{RouteHint, RouteHintHop};
#[doc(no_inline)]
pub use lightning::routing::gossip::RoutingFees;
use lightning::util::string::UntrustedString;

mod de;
mod ser;
Expand Down Expand Up @@ -269,6 +270,15 @@ pub enum Bolt11InvoiceDescription<'f> {
Hash(&'f Sha256),
}

impl<'f> Display for Bolt11InvoiceDescription<'f> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Bolt11InvoiceDescription::Direct(desc) => write!(f, "{}", desc.0),
Bolt11InvoiceDescription::Hash(hash) => write!(f, "{}", hash.0),
}
}
}

/// Represents a signed [`RawBolt11Invoice`] with cached hash. The signature is not checked and may be
/// invalid.
///
Expand Down Expand Up @@ -470,8 +480,8 @@ impl Sha256 {
///
/// # Invariants
/// The description can be at most 639 __bytes__ long
#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub struct Description(String);
#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Default)]
pub struct Description(UntrustedString);

/// Payee public key
#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
Expand Down Expand Up @@ -520,7 +530,7 @@ impl Ord for Bolt11InvoiceSignature {
/// The encoded route has to be <1024 5bit characters long (<=639 bytes or <=12 hops)
///
#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub struct PrivateRoute(RouteHint);
pub struct PrivateRoute(pub RouteHint);

/// Tag constants as specified in BOLT11
#[allow(missing_docs)]
Expand Down Expand Up @@ -675,7 +685,7 @@ impl<H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool, M: tb::Bool> InvoiceBui
pub fn invoice_description(self, description: Bolt11InvoiceDescription) -> InvoiceBuilder<tb::True, H, T, C, S, M> {
match description {
Bolt11InvoiceDescription::Direct(desc) => {
self.description(desc.clone().into_inner())
self.description(desc.clone().into_inner().0)
}
Bolt11InvoiceDescription::Hash(hash) => {
self.description_hash(hash.0)
Expand Down Expand Up @@ -1136,6 +1146,12 @@ impl PositiveTimestamp {
}
}

impl From<PositiveTimestamp> for Duration {
fn from(val: PositiveTimestamp) -> Self {
val.0
}
}

#[cfg(feature = "std")]
impl From<PositiveTimestamp> for SystemTime {
fn from(val: PositiveTimestamp) -> Self {
Expand Down Expand Up @@ -1502,27 +1518,19 @@ impl Description {
if description.len() > 639 {
Err(CreationError::DescriptionTooLong)
} else {
Ok(Description(description))
Ok(Description(UntrustedString(description)))
}
}

/// Returns the underlying description [`String`]
pub fn into_inner(self) -> String {
/// Returns the underlying description [`UntrustedString`]
pub fn into_inner(self) -> UntrustedString {
self.0
}
}

impl From<Description> for String {
fn from(val: Description) -> Self {
val.into_inner()
}
}

impl Deref for Description {
type Target = str;

fn deref(&self) -> &str {
&self.0
impl Display for Description {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}

Expand Down
4 changes: 2 additions & 2 deletions lightning-invoice/src/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,13 +279,13 @@ impl Base32Len for Sha256 {

impl ToBase32 for Description {
fn write_base32<W: WriteBase32>(&self, writer: &mut W) -> Result<(), <W as WriteBase32>::Err> {
self.as_bytes().write_base32(writer)
self.0.0.as_bytes().write_base32(writer)
}
}

impl Base32Len for Description {
fn base32_len(&self) -> usize {
self.0.as_bytes().base32_len()
self.0.0.as_bytes().base32_len()
}
}

Expand Down
11 changes: 6 additions & 5 deletions lightning-invoice/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ where

let invoice = match description {
Bolt11InvoiceDescription::Direct(description) => {
InvoiceBuilder::new(network).description(description.0.clone())
InvoiceBuilder::new(network).description(description.0.0.clone())
}
Bolt11InvoiceDescription::Hash(hash) => InvoiceBuilder::new(network).description_hash(hash.0),
};
Expand Down Expand Up @@ -538,7 +538,7 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_has

let invoice = match description {
Bolt11InvoiceDescription::Direct(description) => {
InvoiceBuilder::new(network).description(description.0.clone())
InvoiceBuilder::new(network).description(description.0.0.clone())
}
Bolt11InvoiceDescription::Hash(hash) => InvoiceBuilder::new(network).description_hash(hash.0),
};
Expand Down Expand Up @@ -808,6 +808,7 @@ mod test {
use lightning::util::config::UserConfig;
use crate::utils::{create_invoice_from_channelmanager_and_duration_since_epoch, rotate_through_iterators};
use std::collections::HashSet;
use lightning::util::string::UntrustedString;

#[test]
fn test_prefer_current_channel() {
Expand Down Expand Up @@ -852,7 +853,7 @@ mod test {
assert_eq!(invoice.amount_pico_btc(), Some(100_000));
// If no `min_final_cltv_expiry_delta` is specified, then it should be `MIN_FINAL_CLTV_EXPIRY_DELTA`.
assert_eq!(invoice.min_final_cltv_expiry_delta(), MIN_FINAL_CLTV_EXPIRY_DELTA as u64);
assert_eq!(invoice.description(), Bolt11InvoiceDescription::Direct(&Description("test".to_string())));
assert_eq!(invoice.description(), Bolt11InvoiceDescription::Direct(&Description(UntrustedString("test".to_string()))));
assert_eq!(invoice.expiry_time(), Duration::from_secs(non_default_invoice_expiry_secs.into()));

// Invoice SCIDs should always use inbound SCID aliases over the real channel ID, if one is
Expand Down Expand Up @@ -963,7 +964,7 @@ mod test {
).unwrap();
assert_eq!(invoice.amount_pico_btc(), Some(100_000));
assert_eq!(invoice.min_final_cltv_expiry_delta(), MIN_FINAL_CLTV_EXPIRY_DELTA as u64);
assert_eq!(invoice.description(), Bolt11InvoiceDescription::Direct(&Description("test".to_string())));
assert_eq!(invoice.description(), Bolt11InvoiceDescription::Direct(&Description(UntrustedString("test".to_string()))));
assert_eq!(invoice.payment_hash(), &sha256::Hash::from_slice(&payment_hash.0[..]).unwrap());
}

Expand Down Expand Up @@ -1315,7 +1316,7 @@ mod test {
};

assert_eq!(invoice.min_final_cltv_expiry_delta(), MIN_FINAL_CLTV_EXPIRY_DELTA as u64);
assert_eq!(invoice.description(), Bolt11InvoiceDescription::Direct(&Description("test".to_string())));
assert_eq!(invoice.description(), Bolt11InvoiceDescription::Direct(&Description(UntrustedString("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());
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/util/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::ln::msgs;
use crate::util::ser::{Writeable, Writer, Readable};

/// Struct to `Display` fields in a safe way using `PrintableString`
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
pub struct UntrustedString(pub String);

impl Writeable for UntrustedString {
Expand Down

0 comments on commit 9c9e5f8

Please sign in to comment.