Skip to content

Commit 9c9e5f8

Browse files
authored
Merge pull request #2730 from benthecarman/invoice-utils
Add some public utilities to `lightning_invoice`
2 parents fb670c8 + e80e8c8 commit 9c9e5f8

File tree

4 files changed

+35
-26
lines changed

4 files changed

+35
-26
lines changed

lightning-invoice/src/lib.rs

+26-18
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ pub use lightning::ln::PaymentSecret;
7373
pub use lightning::routing::router::{RouteHint, RouteHintHop};
7474
#[doc(no_inline)]
7575
pub use lightning::routing::gossip::RoutingFees;
76+
use lightning::util::string::UntrustedString;
7677

7778
mod de;
7879
mod ser;
@@ -269,6 +270,15 @@ pub enum Bolt11InvoiceDescription<'f> {
269270
Hash(&'f Sha256),
270271
}
271272

273+
impl<'f> Display for Bolt11InvoiceDescription<'f> {
274+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
275+
match self {
276+
Bolt11InvoiceDescription::Direct(desc) => write!(f, "{}", desc.0),
277+
Bolt11InvoiceDescription::Hash(hash) => write!(f, "{}", hash.0),
278+
}
279+
}
280+
}
281+
272282
/// Represents a signed [`RawBolt11Invoice`] with cached hash. The signature is not checked and may be
273283
/// invalid.
274284
///
@@ -470,8 +480,8 @@ impl Sha256 {
470480
///
471481
/// # Invariants
472482
/// The description can be at most 639 __bytes__ long
473-
#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
474-
pub struct Description(String);
483+
#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Default)]
484+
pub struct Description(UntrustedString);
475485

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

525535
/// Tag constants as specified in BOLT11
526536
#[allow(missing_docs)]
@@ -675,7 +685,7 @@ impl<H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool, M: tb::Bool> InvoiceBui
675685
pub fn invoice_description(self, description: Bolt11InvoiceDescription) -> InvoiceBuilder<tb::True, H, T, C, S, M> {
676686
match description {
677687
Bolt11InvoiceDescription::Direct(desc) => {
678-
self.description(desc.clone().into_inner())
688+
self.description(desc.clone().into_inner().0)
679689
}
680690
Bolt11InvoiceDescription::Hash(hash) => {
681691
self.description_hash(hash.0)
@@ -1136,6 +1146,12 @@ impl PositiveTimestamp {
11361146
}
11371147
}
11381148

1149+
impl From<PositiveTimestamp> for Duration {
1150+
fn from(val: PositiveTimestamp) -> Self {
1151+
val.0
1152+
}
1153+
}
1154+
11391155
#[cfg(feature = "std")]
11401156
impl From<PositiveTimestamp> for SystemTime {
11411157
fn from(val: PositiveTimestamp) -> Self {
@@ -1502,27 +1518,19 @@ impl Description {
15021518
if description.len() > 639 {
15031519
Err(CreationError::DescriptionTooLong)
15041520
} else {
1505-
Ok(Description(description))
1521+
Ok(Description(UntrustedString(description)))
15061522
}
15071523
}
15081524

1509-
/// Returns the underlying description [`String`]
1510-
pub fn into_inner(self) -> String {
1525+
/// Returns the underlying description [`UntrustedString`]
1526+
pub fn into_inner(self) -> UntrustedString {
15111527
self.0
15121528
}
15131529
}
15141530

1515-
impl From<Description> for String {
1516-
fn from(val: Description) -> Self {
1517-
val.into_inner()
1518-
}
1519-
}
1520-
1521-
impl Deref for Description {
1522-
type Target = str;
1523-
1524-
fn deref(&self) -> &str {
1525-
&self.0
1531+
impl Display for Description {
1532+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1533+
write!(f, "{}", self.0)
15261534
}
15271535
}
15281536

lightning-invoice/src/ser.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -279,13 +279,13 @@ impl Base32Len for Sha256 {
279279

280280
impl ToBase32 for Description {
281281
fn write_base32<W: WriteBase32>(&self, writer: &mut W) -> Result<(), <W as WriteBase32>::Err> {
282-
self.as_bytes().write_base32(writer)
282+
self.0.0.as_bytes().write_base32(writer)
283283
}
284284
}
285285

286286
impl Base32Len for Description {
287287
fn base32_len(&self) -> usize {
288-
self.0.as_bytes().base32_len()
288+
self.0.0.as_bytes().base32_len()
289289
}
290290
}
291291

lightning-invoice/src/utils.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ where
158158

159159
let invoice = match description {
160160
Bolt11InvoiceDescription::Direct(description) => {
161-
InvoiceBuilder::new(network).description(description.0.clone())
161+
InvoiceBuilder::new(network).description(description.0.0.clone())
162162
}
163163
Bolt11InvoiceDescription::Hash(hash) => InvoiceBuilder::new(network).description_hash(hash.0),
164164
};
@@ -538,7 +538,7 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_has
538538

539539
let invoice = match description {
540540
Bolt11InvoiceDescription::Direct(description) => {
541-
InvoiceBuilder::new(network).description(description.0.clone())
541+
InvoiceBuilder::new(network).description(description.0.0.clone())
542542
}
543543
Bolt11InvoiceDescription::Hash(hash) => InvoiceBuilder::new(network).description_hash(hash.0),
544544
};
@@ -808,6 +808,7 @@ mod test {
808808
use lightning::util::config::UserConfig;
809809
use crate::utils::{create_invoice_from_channelmanager_and_duration_since_epoch, rotate_through_iterators};
810810
use std::collections::HashSet;
811+
use lightning::util::string::UntrustedString;
811812

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

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

@@ -1315,7 +1316,7 @@ mod test {
13151316
};
13161317

13171318
assert_eq!(invoice.min_final_cltv_expiry_delta(), MIN_FINAL_CLTV_EXPIRY_DELTA as u64);
1318-
assert_eq!(invoice.description(), Bolt11InvoiceDescription::Direct(&Description("test".to_string())));
1319+
assert_eq!(invoice.description(), Bolt11InvoiceDescription::Direct(&Description(UntrustedString("test".to_string()))));
13191320
assert_eq!(invoice.route_hints().len(), 2);
13201321
assert_eq!(invoice.expiry_time(), Duration::from_secs(non_default_invoice_expiry_secs.into()));
13211322
assert!(!invoice.features().unwrap().supports_basic_mpp());

lightning/src/util/string.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::ln::msgs;
1616
use crate::util::ser::{Writeable, Writer, Readable};
1717

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

2222
impl Writeable for UntrustedString {

0 commit comments

Comments
 (0)