Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some public utilities to lightning_invoice #2730

Merged
merged 3 commits into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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)
benthecarman marked this conversation as resolved.
Show resolved Hide resolved
}
}

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