X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Foffers%2Foffer.rs;h=66dca85cd94c97d6f5b6c594c24d07114d859860;hb=caafcedf3fc40fc6253261218c25b254dd955a82;hp=60621b9dc7491686fbf3207a532f0e2bc25a5aa5;hpb=989304ed3623a578dc9ad0d9aac0984da0d43584;p=rust-lightning diff --git a/lightning/src/offers/offer.rs b/lightning/src/offers/offer.rs index 60621b9d..66dca85c 100644 --- a/lightning/src/offers/offer.rs +++ b/lightning/src/offers/offer.rs @@ -13,6 +13,8 @@ //! published as a QR code to be scanned by a customer. The customer uses the offer to request an //! invoice from the merchant to be paid. //! +//! # Example +//! //! ``` //! extern crate bitcoin; //! extern crate core; @@ -65,6 +67,14 @@ //! # Ok(()) //! # } //! ``` +//! +//! # Note +//! +//! If constructing an [`Offer`] for use with a [`ChannelManager`], use +//! [`ChannelManager::create_offer_builder`] instead of [`OfferBuilder::new`]. +//! +//! [`ChannelManager`]: crate::ln::channelmanager::ChannelManager +//! [`ChannelManager::create_offer_builder`]: crate::ln::channelmanager::ChannelManager::create_offer_builder use bitcoin::blockdata::constants::ChainHash; use bitcoin::network::constants::Network; @@ -132,6 +142,14 @@ impl<'a> OfferBuilder<'a, ExplicitMetadata, secp256k1::SignOnly> { /// while the offer is valid. /// /// Use a different pubkey per offer to avoid correlating offers. + /// + /// # Note + /// + /// If constructing an [`Offer`] for use with a [`ChannelManager`], use + /// [`ChannelManager::create_offer_builder`] instead of [`OfferBuilder::new`]. + /// + /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager + /// [`ChannelManager::create_offer_builder`]: crate::ln::channelmanager::ChannelManager::create_offer_builder pub fn new(description: String, signing_pubkey: PublicKey) -> Self { OfferBuilder { offer: OfferContents { @@ -191,9 +209,18 @@ impl<'a, M: MetadataStrategy, T: secp256k1::Signing> OfferBuilder<'a, M, T> { /// See [`Offer::chains`] on how this relates to the payment currency. /// /// Successive calls to this method will add another chain hash. - pub fn chain(mut self, network: Network) -> Self { + pub fn chain(self, network: Network) -> Self { + self.chain_hash(ChainHash::using_genesis_block(network)) + } + + /// Adds the [`ChainHash`] to [`Offer::chains`]. If not called, the chain hash of + /// [`Network::Bitcoin`] is assumed to be the only one supported. + /// + /// See [`Offer::chains`] on how this relates to the payment currency. + /// + /// Successive calls to this method will add another chain hash. + pub(crate) fn chain_hash(mut self, chain: ChainHash) -> Self { let chains = self.offer.chains.get_or_insert_with(Vec::new); - let chain = ChainHash::using_genesis_block(network); if !chains.contains(&chain) { chains.push(chain); } @@ -441,6 +468,11 @@ impl Offer { self.contents.is_expired() } + /// Whether the offer has expired given the duration since the Unix epoch. + pub fn is_expired_no_std(&self, duration_since_epoch: Duration) -> bool { + self.contents.is_expired_no_std(duration_since_epoch) + } + /// Returns whether the given quantity is valid for the offer. pub fn is_valid_quantity(&self, quantity: u64) -> bool { self.contents.is_valid_quantity(quantity) @@ -582,13 +614,16 @@ impl OfferContents { #[cfg(feature = "std")] pub(super) fn is_expired(&self) -> bool { - match self.absolute_expiry { - Some(seconds_from_epoch) => match SystemTime::UNIX_EPOCH.elapsed() { - Ok(elapsed) => elapsed > seconds_from_epoch, - Err(_) => false, - }, - None => false, - } + SystemTime::UNIX_EPOCH + .elapsed() + .map(|duration_since_epoch| self.is_expired_no_std(duration_since_epoch)) + .unwrap_or(false) + } + + pub(super) fn is_expired_no_std(&self, duration_since_epoch: Duration) -> bool { + self.absolute_expiry + .map(|absolute_expiry| duration_since_epoch > absolute_expiry) + .unwrap_or(false) } pub fn issuer(&self) -> Option { @@ -1162,6 +1197,7 @@ mod tests { fn builds_offer_with_absolute_expiry() { let future_expiry = Duration::from_secs(u64::max_value()); let past_expiry = Duration::from_secs(0); + let now = future_expiry - Duration::from_secs(1_000); let offer = OfferBuilder::new("foo".into(), pubkey(42)) .absolute_expiry(future_expiry) @@ -1169,6 +1205,7 @@ mod tests { .unwrap(); #[cfg(feature = "std")] assert!(!offer.is_expired()); + assert!(!offer.is_expired_no_std(now)); assert_eq!(offer.absolute_expiry(), Some(future_expiry)); assert_eq!(offer.as_tlv_stream().absolute_expiry, Some(future_expiry.as_secs())); @@ -1179,6 +1216,7 @@ mod tests { .unwrap(); #[cfg(feature = "std")] assert!(offer.is_expired()); + assert!(offer.is_expired_no_std(now)); assert_eq!(offer.absolute_expiry(), Some(past_expiry)); assert_eq!(offer.as_tlv_stream().absolute_expiry, Some(past_expiry.as_secs())); }