Skip to content
This repository was archived by the owner on Apr 13, 2021. It is now read-only.

Commit ab629bb

Browse files
committed
InvoiceBuilder: make setting timestamp explicit
Make setting the timestamp in the builder mandatory and don't automatically set the current one if none was defined.
1 parent 3a2639f commit ab629bb

File tree

1 file changed

+34
-17
lines changed

1 file changed

+34
-17
lines changed

src/lib.rs

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ pub use de::{ParseError, ParseOrSemanticError};
4545
/// let invoice = InvoiceBuilder::new(Currency::Bitcoin)
4646
/// .description("Coins pls!".into())
4747
/// .payment_hash([0u8; 32])
48+
/// .current_timestamp()
4849
/// .build_signed(|hash| {
4950
/// Secp256k1::new().sign_recoverable(hash, &private_key)
5051
/// })
@@ -59,8 +60,9 @@ pub use de::{ParseError, ParseOrSemanticError};
5960
/// given field:
6061
/// * `D`: exactly one `Description` or `DescriptionHash`
6162
/// * `H`: exactly one `PaymentHash`
63+
/// * `T`: the timestamp is set
6264
#[derive(Eq, PartialEq, Debug, Clone)]
63-
pub struct InvoiceBuilder<D: tb::Bool, H: tb::Bool> {
65+
pub struct InvoiceBuilder<D: tb::Bool, H: tb::Bool, T: tb::Bool> {
6466
currency: Currency,
6567
amount: Option<u64>,
6668
si_prefix: Option<SiPrefix>,
@@ -70,6 +72,7 @@ pub struct InvoiceBuilder<D: tb::Bool, H: tb::Bool> {
7072

7173
phantom_d: std::marker::PhantomData<D>,
7274
phantom_h: std::marker::PhantomData<H>,
75+
phantom_t: std::marker::PhantomData<T>,
7376
}
7477

7578
/// Represents a syntactically and semantically correct lightning BOLT11 invoice.
@@ -293,7 +296,7 @@ fn as_u5(tag: u8) -> u5 {
293296
u5::try_from_u8(tag).unwrap()
294297
}
295298

296-
impl InvoiceBuilder<tb::False, tb::False> {
299+
impl InvoiceBuilder<tb::False, tb::False, tb::False> {
297300
/// Construct new, empty `InvoiceBuilder`. All necessary fields have to be filled first before
298301
/// `InvoiceBuilder::build(self)` becomes available.
299302
pub fn new(currrency: Currency) -> Self {
@@ -307,14 +310,15 @@ impl InvoiceBuilder<tb::False, tb::False> {
307310

308311
phantom_d: std::marker::PhantomData,
309312
phantom_h: std::marker::PhantomData,
313+
phantom_t: std::marker::PhantomData,
310314
}
311315
}
312316
}
313317

314-
impl<D: tb::Bool, H: tb::Bool> InvoiceBuilder<D, H> {
318+
impl<D: tb::Bool, H: tb::Bool, T: tb::Bool> InvoiceBuilder<D, H, T> {
315319
/// Helper function to set the completeness flags.
316-
fn set_flags<DN: tb::Bool, HN: tb::Bool>(self) -> InvoiceBuilder<DN, HN> {
317-
InvoiceBuilder::<DN, HN> {
320+
fn set_flags<DN: tb::Bool, HN: tb::Bool, TN: tb::Bool>(self) -> InvoiceBuilder<DN, HN, TN> {
321+
InvoiceBuilder::<DN, HN, TN> {
318322
currency: self.currency,
319323
amount: self.amount,
320324
si_prefix: self.si_prefix,
@@ -324,6 +328,7 @@ impl<D: tb::Bool, H: tb::Bool> InvoiceBuilder<D, H> {
324328

325329
phantom_d: std::marker::PhantomData,
326330
phantom_h: std::marker::PhantomData,
331+
phantom_t: std::marker::PhantomData,
327332
}
328333
}
329334

@@ -338,12 +343,6 @@ impl<D: tb::Bool, H: tb::Bool> InvoiceBuilder<D, H> {
338343
self
339344
}
340345

341-
/// Sets the timestamp. `time` is a UNIX timestamp.
342-
pub fn timestamp(mut self, time: u64) -> Self {
343-
self.timestamp = Some(time);
344-
self
345-
}
346-
347346
/// Sets the payee's public key.
348347
pub fn payee_pub_key(mut self, pub_key: PublicKey) -> Self {
349348
self.tagged_fields.push(TaggedField::PayeePubKey(PayeePubKey(pub_key)));
@@ -415,9 +414,9 @@ impl<D: tb::Bool, H: tb::Bool> InvoiceBuilder<D, H> {
415414
}
416415
}
417416

418-
impl<H: tb::Bool> InvoiceBuilder<tb::False, H> {
417+
impl<H: tb::Bool, T: tb::Bool> InvoiceBuilder<tb::False, H, T> {
419418
/// Set the description. This function is only available if no description (hash) was set.
420-
pub fn description(mut self, description: String) -> InvoiceBuilder<tb::True, H> {
419+
pub fn description(mut self, description: String) -> InvoiceBuilder<tb::True, H, T> {
421420
match Description::new(description) {
422421
Ok(d) => self.tagged_fields.push(TaggedField::Description(d)),
423422
Err(e) => self.error = Some(e),
@@ -426,21 +425,38 @@ impl<H: tb::Bool> InvoiceBuilder<tb::False, H> {
426425
}
427426

428427
/// Set the description hash. This function is only available if no description (hash) was set.
429-
pub fn description_hash(mut self, description_hash: [u8; 32]) -> InvoiceBuilder<tb::True, H> {
428+
pub fn description_hash(mut self, description_hash: [u8; 32]) -> InvoiceBuilder<tb::True, H, T> {
430429
self.tagged_fields.push(TaggedField::DescriptionHash(Sha256(description_hash)));
431430
self.set_flags()
432431
}
433432
}
434433

435-
impl<D: tb::Bool> InvoiceBuilder<D, tb::False> {
434+
impl<D: tb::Bool, T: tb::Bool> InvoiceBuilder<D, tb::False, T> {
436435
/// Set the payment hash. This function is only available if no payment hash was set.
437-
pub fn payment_hash(mut self, hash: [u8; 32]) -> InvoiceBuilder<D, tb::True> {
436+
pub fn payment_hash(mut self, hash: [u8; 32]) -> InvoiceBuilder<D, tb::True, T> {
438437
self.tagged_fields.push(TaggedField::PaymentHash(Sha256(hash)));
439438
self.set_flags()
440439
}
441440
}
442441

443-
impl InvoiceBuilder<tb::True, tb::True> {
442+
impl<D: tb::Bool, H: tb::Bool> InvoiceBuilder<D, H, tb::False> {
443+
/// Sets the timestamp. `time` is a UNIX timestamp.
444+
pub fn timestamp(mut self, time: u64) -> InvoiceBuilder<D, H, tb::True> {
445+
self.timestamp = Some(time);
446+
self.set_flags()
447+
}
448+
449+
/// Sets the timestamp to the current UNIX timestamp.
450+
pub fn current_timestamp(mut self) -> InvoiceBuilder<D, H, tb::True> {
451+
use std::time::{SystemTime, UNIX_EPOCH};
452+
let now = SystemTime::now();
453+
let since_unix_epoch = now.duration_since(UNIX_EPOCH).expect("it won't be 1970 ever again");
454+
self.timestamp = Some(since_unix_epoch.as_secs() as u64);
455+
self.set_flags()
456+
}
457+
}
458+
459+
impl InvoiceBuilder<tb::True, tb::True, tb::True> {
444460
/// Builds and signs an invoice using the supplied `sign_function`. This function MAY NOT fail
445461
/// and MUST produce a recoverable signature valid for the given hash and if applicable also for
446462
/// the included payee public key.
@@ -1150,6 +1166,7 @@ mod test {
11501166

11511167
let sign_error_res = builder.clone()
11521168
.description("Test".into())
1169+
.current_timestamp()
11531170
.try_build_signed(|_| {
11541171
Err("ImaginaryError")
11551172
});

0 commit comments

Comments
 (0)