]> git.bitcoin.ninja Git - rust-lightning/commitdiff
Adapt lightning-invoice to no_std
authorDevrandom <c1.devrandom@niftybox.net>
Wed, 22 Dec 2021 16:43:25 +0000 (17:43 +0100)
committerDevrandom <c1.devrandom@niftybox.net>
Wed, 5 Jan 2022 22:18:03 +0000 (23:18 +0100)
.github/workflows/build.yml
lightning-invoice/Cargo.toml
lightning-invoice/src/de.rs
lightning-invoice/src/lib.rs
lightning-invoice/src/payment.rs
lightning-invoice/src/ser.rs
lightning-invoice/src/sync.rs [new file with mode: 0644]
lightning-invoice/src/utils.rs
lightning-invoice/tests/ser_de.rs
lightning/src/ln/functional_test_utils.rs
lightning/src/util/test_utils.rs

index 20ca306b18dcd7e185a1cc629012a6ce1ec7da4c..5dcbb677e6d8a6d6f88e62b20e7307c862807c0e 100644 (file)
@@ -115,6 +115,11 @@ jobs:
           # check if there is a conflict between no-std and the default std feature
           cargo test --verbose --color always --features no-std
           cd ..
+          cd lightning-invoice
+          cargo test --verbose --color always --no-default-features --features no-std
+          # check if there is a conflict between no-std and the default std feature
+          cargo test --verbose --color always --features no-std
+          cd ..
       - name: Test on no-std builds Rust ${{ matrix.toolchain }} and full code-linking for coverage generation
         if: "matrix.build-no-std && matrix.coverage"
         run: |
index 71648b3c84d40ef70c7857ffa9918ccb51824dd7..129d0f23c3a733b1349b7986971f6ce9e70a163a 100644 (file)
@@ -8,13 +8,20 @@ license = "MIT OR Apache-2.0"
 keywords = [ "lightning", "bitcoin", "invoice", "BOLT11" ]
 readme = "README.md"
 
+[features]
+default = ["std"]
+no-std = ["hashbrown", "lightning/no-std", "core2/alloc"]
+std = ["bitcoin_hashes/std", "num-traits/std", "lightning/std"]
+
 [dependencies]
 bech32 = "0.8"
-lightning = { version = "0.0.104", path = "../lightning" }
-secp256k1 = { version = "0.20", features = ["recovery"] }
-num-traits = "0.2.8"
-bitcoin_hashes = "0.10"
+lightning = { version = "0.0.104", path = "../lightning", default-features = false }
+secp256k1 = { version = "0.20", default-features = false, features = ["recovery", "alloc"] }
+num-traits = { version = "0.2.8", default-features = false }
+bitcoin_hashes = { version = "0.10", default-features = false }
+hashbrown = { version = "0.11", optional = true }
+core2 = { version = "0.3.0", default-features = false, optional = true }
 
 [dev-dependencies]
+lightning = { version = "0.0.104", path = "../lightning", default-features = false, features = ["_test_utils"] }
 hex = "0.3"
-lightning = { version = "0.0.104", path = "../lightning", features = ["_test_utils"] }
index 777ac660f8e6b764d6ac5a191af3bcbb3636bc1d..53f6b83da5fdf00fdd33fcf51c4f0502b32d0fa2 100644 (file)
@@ -1,15 +1,17 @@
+#[cfg(feature = "std")]
 use std::error;
-use std::fmt;
-use std::fmt::{Display, Formatter};
-use std::num::ParseIntError;
-use std::str;
-use std::str::FromStr;
+use core::fmt;
+use core::fmt::{Display, Formatter};
+use core::num::ParseIntError;
+use core::str;
+use core::str::FromStr;
 
 use bech32;
 use bech32::{u5, FromBase32};
 
 use bitcoin_hashes::Hash;
 use bitcoin_hashes::sha256;
+use crate::prelude::*;
 use lightning::ln::PaymentSecret;
 use lightning::routing::network_graph::RoutingFees;
 use lightning::routing::router::{RouteHint, RouteHintHop};
@@ -28,7 +30,7 @@ use self::hrp_sm::parse_hrp;
 
 /// State machine to parse the hrp
 mod hrp_sm {
-       use std::ops::Range;
+       use core::ops::Range;
 
        #[derive(PartialEq, Eq, Debug)]
        enum States {
@@ -723,8 +725,10 @@ impl Display for ParseOrSemanticError {
        }
 }
 
+#[cfg(feature = "std")]
 impl error::Error for ParseError {}
 
+#[cfg(feature = "std")]
 impl error::Error for ParseOrSemanticError {}
 
 macro_rules! from_error {
index dd86c06f23f80d524f860aca5bc3c9355962c099..2164f1c530fccc6b30dbaa632a8087311a255fdd 100644 (file)
@@ -6,6 +6,7 @@
 #![deny(broken_intra_doc_links)]
 
 #![cfg_attr(feature = "strict", deny(warnings))]
+#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
 
 //! This crate provides data structures to represent
 //! [lightning BOLT11](https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md)
 //!   * For parsing use `str::parse::<Invoice>(&self)` (see the docs of `impl FromStr for Invoice`)
 //!   * For constructing invoices use the `InvoiceBuilder`
 //!   * For serializing invoices use the `Display`/`ToString` traits
+
+#[cfg(not(any(feature = "std", feature = "no-std")))]
+compile_error!("at least one of the `std` or `no-std` features must be enabled");
+
 pub mod payment;
 pub mod utils;
 
@@ -23,6 +28,12 @@ extern crate bitcoin_hashes;
 #[macro_use] extern crate lightning;
 extern crate num_traits;
 extern crate secp256k1;
+extern crate alloc;
+#[cfg(any(test, feature = "std"))]
+extern crate core;
+
+#[cfg(feature = "std")]
+use std::time::SystemTime;
 
 use bech32::u5;
 use bitcoin_hashes::Hash;
@@ -37,22 +48,47 @@ use secp256k1::key::PublicKey;
 use secp256k1::{Message, Secp256k1};
 use secp256k1::recovery::RecoverableSignature;
 
-use std::fmt::{Display, Formatter, self};
-use std::iter::FilterMap;
-use std::ops::Deref;
-use std::slice::Iter;
-use std::time::{SystemTime, Duration, UNIX_EPOCH};
+use core::fmt::{Display, Formatter, self};
+use core::iter::FilterMap;
+use core::ops::Deref;
+use core::slice::Iter;
+use core::time::Duration;
 
 mod de;
 mod ser;
 mod tb;
 
+mod prelude {
+       #[cfg(feature = "hashbrown")]
+       extern crate hashbrown;
+
+       pub use alloc::{vec, vec::Vec, string::String, collections::VecDeque, boxed::Box};
+       #[cfg(not(feature = "hashbrown"))]
+       pub use std::collections::{HashMap, HashSet, hash_map};
+       #[cfg(feature = "hashbrown")]
+       pub use self::hashbrown::{HashMap, HashSet, hash_map};
+
+       pub use alloc::string::ToString;
+}
+
+use prelude::*;
+
+/// Sync compat for std/no_std
+#[cfg(feature = "std")]
+mod sync {
+       pub use ::std::sync::{Mutex, MutexGuard};
+}
+
+/// Sync compat for std/no_std
+#[cfg(not(feature = "std"))]
+mod sync;
+
 pub use de::{ParseError, ParseOrSemanticError};
 
 // TODO: fix before 2037 (see rust PR #55527)
 /// Defines the maximum UNIX timestamp that can be represented as `SystemTime`. This is checked by
 /// one of the unit tests, please run them.
-const SYSTEM_TIME_MAX_UNIX_TIMESTAMP: u64 = std::i32::MAX as u64;
+const SYSTEM_TIME_MAX_UNIX_TIMESTAMP: u64 = core::i32::MAX as u64;
 
 /// Allow the expiry time to be up to one year. Since this reduces the range of possible timestamps
 /// it should be rather low as long as we still have to support 32bit time representations
@@ -77,10 +113,11 @@ pub const DEFAULT_MIN_FINAL_CLTV_EXPIRY: u64 = 18;
 /// can remove this functions and run the test `test_system_time_bounds_assumptions`. In any case,
 /// please open an issue. If all tests pass you should be able to use this library safely by just
 /// removing this function till we patch it accordingly.
+#[cfg(feature = "std")]
 fn __system_time_size_check() {
        // Use 2 * sizeof(u64) as expected size since the expected underlying implementation is storing
        // a `Duration` since `SystemTime::UNIX_EPOCH`.
-       unsafe { std::mem::transmute_copy::<SystemTime, [u8; 16]>(&UNIX_EPOCH); }
+       unsafe { core::mem::transmute_copy::<SystemTime, [u8; 16]>(&SystemTime::UNIX_EPOCH); }
 }
 
 
@@ -94,32 +131,41 @@ fn __system_time_size_check() {
 /// If this function fails this is considered a bug. Please open an issue describing your
 /// platform and stating your current system time.
 ///
+/// Note that this currently does nothing in `no_std` environments, because they don't have
+/// a `SystemTime` implementation.
+///
 /// # Panics
 /// If the check fails this function panics. By calling this function on startup you ensure that
 /// this wont happen at an arbitrary later point in time.
 pub fn check_platform() {
-    // The upper and lower bounds of `SystemTime` are not part of its public contract and are
-    // platform specific. That's why we have to test if our assumptions regarding these bounds
-    // hold on the target platform.
-    //
-    // If this test fails on your platform, please don't use the library and open an issue
-    // instead so we can resolve the situation. Currently this library is tested on:
-    //   * Linux (64bit)
-    let fail_date = UNIX_EPOCH + Duration::from_secs(SYSTEM_TIME_MAX_UNIX_TIMESTAMP);
-    let year = Duration::from_secs(60 * 60 * 24 * 365);
-
-    // Make sure that the library will keep working for another year
-    assert!(fail_date.duration_since(SystemTime::now()).unwrap() > year);
-
-    let max_ts = PositiveTimestamp::from_unix_timestamp(
-        SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME
-    ).unwrap();
-    let max_exp = ::ExpiryTime::from_seconds(MAX_EXPIRY_TIME).unwrap();
-
-    assert_eq!(
-        (*max_ts.as_time() + *max_exp.as_duration()).duration_since(UNIX_EPOCH).unwrap().as_secs(),
-        SYSTEM_TIME_MAX_UNIX_TIMESTAMP
-    );
+       #[cfg(feature = "std")]
+       check_system_time_bounds();
+}
+
+#[cfg(feature = "std")]
+fn check_system_time_bounds() {
+       // The upper and lower bounds of `SystemTime` are not part of its public contract and are
+       // platform specific. That's why we have to test if our assumptions regarding these bounds
+       // hold on the target platform.
+       //
+       // If this test fails on your platform, please don't use the library and open an issue
+       // instead so we can resolve the situation. Currently this library is tested on:
+       //   * Linux (64bit)
+       let fail_date = SystemTime::UNIX_EPOCH + Duration::from_secs(SYSTEM_TIME_MAX_UNIX_TIMESTAMP);
+       let year = Duration::from_secs(60 * 60 * 24 * 365);
+
+       // Make sure that the library will keep working for another year
+       assert!(fail_date.duration_since(SystemTime::now()).unwrap() > year);
+
+       let max_ts = PositiveTimestamp::from_unix_timestamp(
+               SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME
+       ).unwrap();
+       let max_exp = ::ExpiryTime::from_seconds(MAX_EXPIRY_TIME).unwrap();
+
+       assert_eq!(
+               (max_ts.as_time() + *max_exp.as_duration()).duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs(),
+               SYSTEM_TIME_MAX_UNIX_TIMESTAMP
+       );
 }
 
 
@@ -142,6 +188,9 @@ pub fn check_platform() {
 ///
 /// use lightning_invoice::{Currency, InvoiceBuilder};
 ///
+/// # #[cfg(not(feature = "std"))]
+/// # fn main() {}
+/// # #[cfg(feature = "std")]
 /// # fn main() {
 /// let private_key = SecretKey::from_slice(
 ///            &[
@@ -186,11 +235,11 @@ pub struct InvoiceBuilder<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, S:
        tagged_fields: Vec<TaggedField>,
        error: Option<CreationError>,
 
-       phantom_d: std::marker::PhantomData<D>,
-       phantom_h: std::marker::PhantomData<H>,
-       phantom_t: std::marker::PhantomData<T>,
-       phantom_c: std::marker::PhantomData<C>,
-       phantom_s: std::marker::PhantomData<S>,
+       phantom_d: core::marker::PhantomData<D>,
+       phantom_h: core::marker::PhantomData<H>,
+       phantom_t: core::marker::PhantomData<T>,
+       phantom_c: core::marker::PhantomData<C>,
+       phantom_s: core::marker::PhantomData<S>,
 }
 
 /// Represents a syntactically and semantically correct lightning BOLT11 invoice.
@@ -285,9 +334,9 @@ pub struct RawDataPart {
 ///
 /// # Invariants
 /// The UNIX timestamp representing the stored time has to be positive and small enough so that
-/// a `EpiryTime` can be added to it without an overflow.
+/// a `ExpiryTime` can be added to it without an overflow.
 #[derive(Eq, PartialEq, Debug, Clone)]
-pub struct PositiveTimestamp(SystemTime);
+pub struct PositiveTimestamp(Duration);
 
 /// SI prefixes for the human readable part
 #[derive(Eq, PartialEq, Debug, Clone, Copy)]
@@ -459,11 +508,11 @@ impl InvoiceBuilder<tb::False, tb::False, tb::False, tb::False, tb::False> {
                        tagged_fields: Vec::new(),
                        error: None,
 
-                       phantom_d: std::marker::PhantomData,
-                       phantom_h: std::marker::PhantomData,
-                       phantom_t: std::marker::PhantomData,
-                       phantom_c: std::marker::PhantomData,
-                       phantom_s: std::marker::PhantomData,
+                       phantom_d: core::marker::PhantomData,
+                       phantom_h: core::marker::PhantomData,
+                       phantom_t: core::marker::PhantomData,
+                       phantom_c: core::marker::PhantomData,
+                       phantom_s: core::marker::PhantomData,
                }
        }
 }
@@ -479,11 +528,11 @@ impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool> InvoiceBui
                        tagged_fields: self.tagged_fields,
                        error: self.error,
 
-                       phantom_d: std::marker::PhantomData,
-                       phantom_h: std::marker::PhantomData,
-                       phantom_t: std::marker::PhantomData,
-                       phantom_c: std::marker::PhantomData,
-                       phantom_s: std::marker::PhantomData,
+                       phantom_d: core::marker::PhantomData,
+                       phantom_h: core::marker::PhantomData,
+                       phantom_t: core::marker::PhantomData,
+                       phantom_c: core::marker::PhantomData,
+                       phantom_s: core::marker::PhantomData,
                }
        }
 
@@ -589,7 +638,8 @@ impl<D: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool> InvoiceBuilder<D, tb::F
 }
 
 impl<D: tb::Bool, H: tb::Bool, C: tb::Bool, S: tb::Bool> InvoiceBuilder<D, H, tb::False, C, S> {
-       /// Sets the timestamp.
+       /// Sets the timestamp to a specific [`SystemTime`].
+       #[cfg(feature = "std")]
        pub fn timestamp(mut self, time: SystemTime) -> InvoiceBuilder<D, H, tb::True, C, S> {
                match PositiveTimestamp::from_system_time(time) {
                        Ok(t) => self.timestamp = Some(t),
@@ -599,7 +649,18 @@ impl<D: tb::Bool, H: tb::Bool, C: tb::Bool, S: tb::Bool> InvoiceBuilder<D, H, tb
                self.set_flags()
        }
 
-       /// Sets the timestamp to the current UNIX timestamp.
+       /// Sets the timestamp to a duration since the UNIX epoch.
+       pub fn duration_since_epoch(mut self, time: Duration) -> InvoiceBuilder<D, H, tb::True, C, S> {
+               match PositiveTimestamp::from_duration_since_epoch(time) {
+                       Ok(t) => self.timestamp = Some(t),
+                       Err(e) => self.error = Some(e),
+               }
+
+               self.set_flags()
+       }
+
+       /// Sets the timestamp to the current system time.
+       #[cfg(feature = "std")]
        pub fn current_timestamp(mut self) -> InvoiceBuilder<D, H, tb::True, C, S> {
                let now = PositiveTimestamp::from_system_time(SystemTime::now());
                self.timestamp = Some(now.expect("for the foreseeable future this shouldn't happen"));
@@ -776,7 +837,7 @@ impl SignedRawInvoice {
 macro_rules! find_extract {
        ($iter:expr, $enm:pat, $enm_var:ident) => {
                find_all_extract!($iter, $enm, $enm_var).next()
-    };
+       };
 }
 
 /// Finds the all elements of an enum stream of a given variant and extracts one member of the
@@ -799,11 +860,11 @@ macro_rules! find_extract {
 /// ```
 macro_rules! find_all_extract {
        ($iter:expr, $enm:pat, $enm_var:ident) => {
-       $iter.filter_map(|tf| match *tf {
+               $iter.filter_map(|tf| match *tf {
                        $enm => Some($enm_var),
                        _ => None,
                })
-    };
+       };
 }
 
 #[allow(missing_docs)]
@@ -949,49 +1010,52 @@ impl PositiveTimestamp {
                if unix_seconds > SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME {
                        Err(CreationError::TimestampOutOfBounds)
                } else {
-                       Ok(PositiveTimestamp(UNIX_EPOCH + Duration::from_secs(unix_seconds)))
+                       Ok(PositiveTimestamp(Duration::from_secs(unix_seconds)))
                }
        }
 
        /// Create a new `PositiveTimestamp` from a `SystemTime` with a corresponding unix timestamp in
-       /// the Range `0...SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME`, otherwise return a
+       /// the range `0...SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME`, otherwise return a
        /// `CreationError::TimestampOutOfBounds`.
+       #[cfg(feature = "std")]
        pub fn from_system_time(time: SystemTime) -> Result<Self, CreationError> {
-               if time
-                       .duration_since(UNIX_EPOCH)
-                       .map(|t| t.as_secs() <= SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME)
-                       .unwrap_or(true)
-                       {
-                               Ok(PositiveTimestamp(time))
-                       } else {
+               time.duration_since(SystemTime::UNIX_EPOCH)
+                       .map(Self::from_duration_since_epoch)
+                       .unwrap_or(Err(CreationError::TimestampOutOfBounds))
+       }
+
+       /// Create a new `PositiveTimestamp` from a `Duration` since the UNIX epoch in
+       /// the range `0...SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME`, otherwise return a
+       /// `CreationError::TimestampOutOfBounds`.
+       pub fn from_duration_since_epoch(duration: Duration) -> Result<Self, CreationError> {
+               if duration.as_secs() <= SYSTEM_TIME_MAX_UNIX_TIMESTAMP - MAX_EXPIRY_TIME {
+                       Ok(PositiveTimestamp(duration))
+               } else {
                        Err(CreationError::TimestampOutOfBounds)
                }
        }
 
        /// Returns the UNIX timestamp representing the stored time
        pub fn as_unix_timestamp(&self) -> u64 {
-               self.0.duration_since(UNIX_EPOCH)
-                       .expect("ensured by type contract/constructors")
-                       .as_secs()
+               self.0.as_secs()
        }
 
-       /// Returns a reference to the internal `SystemTime` time representation
-       pub fn as_time(&self) -> &SystemTime {
-               &self.0
+       /// Returns the duration of the stored time since the UNIX epoch
+       pub fn as_duration_since_epoch(&self) -> Duration {
+               self.0
        }
-}
 
-impl Into<SystemTime> for PositiveTimestamp {
-       fn into(self) -> SystemTime {
-               self.0
+       /// Returns the `SystemTime` representing the stored time
+       #[cfg(feature = "std")]
+       pub fn as_time(&self) -> SystemTime {
+               SystemTime::UNIX_EPOCH + self.0
        }
 }
 
-impl Deref for PositiveTimestamp {
-       type Target = SystemTime;
-
-       fn deref(&self) -> &Self::Target {
-               &self.0
+#[cfg(feature = "std")]
+impl Into<SystemTime> for PositiveTimestamp {
+       fn into(self) -> SystemTime {
+               SystemTime::UNIX_EPOCH + self.0
        }
 }
 
@@ -1132,11 +1196,17 @@ impl Invoice {
                Ok(invoice)
        }
 
-       /// Returns the `Invoice`'s timestamp (should equal it's creation time)
-       pub fn timestamp(&self) -> &SystemTime {
+       /// Returns the `Invoice`'s timestamp (should equal its creation time)
+       #[cfg(feature = "std")]
+       pub fn timestamp(&self) -> SystemTime {
                self.signed_invoice.raw_invoice().data.timestamp.as_time()
        }
 
+       /// Returns the `Invoice`'s timestamp as a duration since the UNIX epoch
+       pub fn duration_since_epoch(&self) -> Duration {
+               self.signed_invoice.raw_invoice().data.timestamp.0
+       }
+
        /// Returns an iterator over all tagged fields of this Invoice.
        ///
        /// (C-not exported) As there is not yet a manual mapping for a FilterMap
@@ -1190,11 +1260,13 @@ impl Invoice {
        }
 
        /// Returns whether the invoice has expired.
+       #[cfg(feature = "std")]
        pub fn is_expired(&self) -> bool {
-               Self::is_expired_from_epoch(self.timestamp(), self.expiry_time())
+               Self::is_expired_from_epoch(&self.timestamp(), self.expiry_time())
        }
 
        /// Returns whether the expiry time from the given epoch has passed.
+       #[cfg(feature = "std")]
        pub(crate) fn is_expired_from_epoch(epoch: &SystemTime, expiry_time: Duration) -> bool {
                match epoch.elapsed() {
                        Ok(elapsed) => elapsed > expiry_time,
@@ -1202,6 +1274,12 @@ impl Invoice {
                }
        }
 
+       /// Returns whether the expiry time would pass at the given point in time.
+       /// `at_time` is the timestamp as a duration since the UNIX epoch.
+       pub fn would_expire(&self, at_time: Duration) -> bool {
+               self.duration_since_epoch() + self.expiry_time() < at_time
+       }
+
        /// Returns the invoice's `min_final_cltv_expiry` time, if present, otherwise
        /// [`DEFAULT_MIN_FINAL_CLTV_EXPIRY`].
        pub fn min_final_cltv_expiry(&self) -> u64 {
@@ -1430,6 +1508,7 @@ impl Display for CreationError {
        }
 }
 
+#[cfg(feature = "std")]
 impl std::error::Error for CreationError { }
 
 /// Errors that may occur when converting a `RawInvoice` to an `Invoice`. They relate to the
@@ -1485,6 +1564,7 @@ impl Display for SemanticError {
        }
 }
 
+#[cfg(feature = "std")]
 impl std::error::Error for SemanticError { }
 
 /// When signing using a fallible method either an user-supplied `SignError` or a `CreationError`
@@ -1516,15 +1596,15 @@ mod test {
        fn test_system_time_bounds_assumptions() {
                ::check_platform();
 
-        assert_eq!(
-            ::PositiveTimestamp::from_unix_timestamp(::SYSTEM_TIME_MAX_UNIX_TIMESTAMP + 1),
-            Err(::CreationError::TimestampOutOfBounds)
-        );
+               assert_eq!(
+                       ::PositiveTimestamp::from_unix_timestamp(::SYSTEM_TIME_MAX_UNIX_TIMESTAMP + 1),
+                       Err(::CreationError::TimestampOutOfBounds)
+               );
 
-        assert_eq!(
-            ::ExpiryTime::from_seconds(::MAX_EXPIRY_TIME + 1),
-            Err(::CreationError::ExpiryTimeOutOfBounds)
-        );
+               assert_eq!(
+                       ::ExpiryTime::from_seconds(::MAX_EXPIRY_TIME + 1),
+                       Err(::CreationError::ExpiryTimeOutOfBounds)
+               );
        }
 
        #[test]
@@ -1727,7 +1807,7 @@ mod test {
                let builder = InvoiceBuilder::new(Currency::Bitcoin)
                        .description("Test".into())
                        .payment_hash(sha256::Hash::from_slice(&[0;32][..]).unwrap())
-                       .current_timestamp();
+                       .duration_since_epoch(Duration::from_secs(1234567));
 
                let invoice = builder.clone()
                        .amount_milli_satoshis(1500)
@@ -1756,7 +1836,7 @@ mod test {
 
                let builder = InvoiceBuilder::new(Currency::Bitcoin)
                        .payment_hash(sha256::Hash::from_slice(&[0;32][..]).unwrap())
-                       .current_timestamp()
+                       .duration_since_epoch(Duration::from_secs(1234567))
                        .min_final_cltv_expiry(144);
 
                let too_long_string = String::from_iter(
@@ -1872,7 +1952,7 @@ mod test {
 
                let builder = InvoiceBuilder::new(Currency::BitcoinTestnet)
                        .amount_milli_satoshis(123)
-                       .timestamp(UNIX_EPOCH + Duration::from_secs(1234567))
+                       .duration_since_epoch(Duration::from_secs(1234567))
                        .payee_pub_key(public_key.clone())
                        .expiry_time(Duration::from_secs(54321))
                        .min_final_cltv_expiry(144)
@@ -1894,6 +1974,7 @@ mod test {
                assert_eq!(invoice.amount_milli_satoshis(), Some(123));
                assert_eq!(invoice.amount_pico_btc(), Some(1230));
                assert_eq!(invoice.currency(), Currency::BitcoinTestnet);
+               #[cfg(feature = "std")]
                assert_eq!(
                        invoice.timestamp().duration_since(UNIX_EPOCH).unwrap().as_secs(),
                        1234567
@@ -1925,7 +2006,7 @@ mod test {
                        .description("Test".into())
                        .payment_hash(sha256::Hash::from_slice(&[0;32][..]).unwrap())
                        .payment_secret(PaymentSecret([0; 32]))
-                       .current_timestamp()
+                       .duration_since_epoch(Duration::from_secs(1234567))
                        .build_raw()
                        .unwrap()
                        .sign::<_, ()>(|hash| {
@@ -1938,7 +2019,7 @@ mod test {
 
                assert_eq!(invoice.min_final_cltv_expiry(), DEFAULT_MIN_FINAL_CLTV_EXPIRY);
                assert_eq!(invoice.expiry_time(), Duration::from_secs(DEFAULT_EXPIRY_TIME));
-               assert!(!invoice.is_expired());
+               assert!(!invoice.would_expire(Duration::from_secs(1234568)));
        }
 
        #[test]
@@ -1947,14 +2028,11 @@ mod test {
                use secp256k1::Secp256k1;
                use secp256k1::key::SecretKey;
 
-               let timestamp = SystemTime::now()
-                       .checked_sub(Duration::from_secs(DEFAULT_EXPIRY_TIME * 2))
-                       .unwrap();
                let signed_invoice = InvoiceBuilder::new(Currency::Bitcoin)
                        .description("Test".into())
                        .payment_hash(sha256::Hash::from_slice(&[0;32][..]).unwrap())
                        .payment_secret(PaymentSecret([0; 32]))
-                       .timestamp(timestamp)
+                       .duration_since_epoch(Duration::from_secs(1234567))
                        .build_raw()
                        .unwrap()
                        .sign::<_, ()>(|hash| {
@@ -1965,6 +2043,6 @@ mod test {
                        .unwrap();
                let invoice = Invoice::from_signed(signed_invoice).unwrap();
 
-               assert!(invoice.is_expired());
+               assert!(invoice.would_expire(Duration::from_secs(1234567 + DEFAULT_EXPIRY_TIME + 1)));
        }
 }
index 4e249a85c3f09d238a59cd09c1e55e6b920eea66..d73ca538981d9e203d2614f68acab93e1a6caf46 100644 (file)
@@ -32,6 +32,9 @@
 //! # extern crate lightning_invoice;
 //! # extern crate secp256k1;
 //! #
+//! # #[cfg(feature = "no-std")]
+//! # extern crate core2;
+//! #
 //! # use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
 //! # use lightning::ln::channelmanager::{ChannelDetails, PaymentId, PaymentSendFailure};
 //! # use lightning::ln::msgs::LightningError;
 //! # use std::cell::RefCell;
 //! # use std::ops::Deref;
 //! #
+//! # #[cfg(not(feature = "std"))]
+//! # use core2::io;
+//! # #[cfg(feature = "std")]
+//! # use std::io;
+//! #
 //! # struct FakeEventProvider {}
 //! # impl EventsProvider for FakeEventProvider {
 //! #     fn process_pending_events<H: Deref>(&self, handler: H) where H::Target: EventHandler {}
@@ -78,7 +86,7 @@
 //! #
 //! # struct FakeScorer {}
 //! # impl Writeable for FakeScorer {
-//! #     fn write<W: Writer>(&self, w: &mut W) -> Result<(), std::io::Error> { unimplemented!(); }
+//! #     fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> { unimplemented!(); }
 //! # }
 //! # impl Score for FakeScorer {
 //! #     fn channel_penalty_msat(
@@ -130,6 +138,7 @@ use crate::Invoice;
 use bitcoin_hashes::Hash;
 use bitcoin_hashes::sha256::Hash as Sha256;
 
+use crate::prelude::*;
 use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
 use lightning::ln::channelmanager::{ChannelDetails, PaymentId, PaymentSendFailure};
 use lightning::ln::msgs::LightningError;
@@ -137,13 +146,14 @@ use lightning::routing::scoring::{LockableScore, Score};
 use lightning::routing::router::{Payee, Route, RouteParameters};
 use lightning::util::events::{Event, EventHandler};
 use lightning::util::logger::Logger;
+use crate::sync::Mutex;
 
 use secp256k1::key::PublicKey;
 
-use std::collections::hash_map::{self, HashMap};
-use std::ops::Deref;
-use std::sync::Mutex;
-use std::time::{Duration, SystemTime};
+use core::ops::Deref;
+use core::time::Duration;
+#[cfg(feature = "std")]
+use std::time::SystemTime;
 
 /// A utility for paying [`Invoice`]s and sending spontaneous payments.
 ///
@@ -336,9 +346,11 @@ where
        fn pay_internal<F: FnOnce(&Route) -> Result<PaymentId, PaymentSendFailure> + Copy>(
                &self, params: &RouteParameters, payment_hash: PaymentHash, send_payment: F,
        ) -> Result<PaymentId, PaymentError> {
-               if has_expired(params) {
-                       log_trace!(self.logger, "Invoice expired prior to send for payment {}", log_bytes!(payment_hash.0));
-                       return Err(PaymentError::Invoice("Invoice expired prior to send"));
+               #[cfg(feature = "std")] {
+                       if has_expired(params) {
+                               log_trace!(self.logger, "Invoice expired prior to send for payment {}", log_bytes!(payment_hash.0));
+                               return Err(PaymentError::Invoice("Invoice expired prior to send"));
+                       }
                }
 
                let payer = self.payer.node_id();
@@ -360,7 +372,7 @@ where
                                                Err(e)
                                        } else {
                                                *retry_count += 1;
-                                               std::mem::drop(payment_cache);
+                                               core::mem::drop(payment_cache);
                                                Ok(self.pay_internal(params, payment_hash, send_payment)?)
                                        }
                                },
@@ -398,9 +410,11 @@ where
                        return Err(());
                }
 
-               if has_expired(params) {
-                       log_trace!(self.logger, "Invoice expired for payment {}; not retrying (attempts: {})", log_bytes!(payment_hash.0), attempts);
-                       return Err(());
+               #[cfg(feature = "std")] {
+                       if has_expired(params) {
+                               log_trace!(self.logger, "Invoice expired for payment {}; not retrying (attempts: {})", log_bytes!(payment_hash.0), attempts);
+                               return Err(());
+                       }
                }
 
                let payer = self.payer.node_id();
@@ -444,9 +458,10 @@ where
 }
 
 fn expiry_time_from_unix_epoch(invoice: &Invoice) -> Duration {
-       invoice.timestamp().duration_since(SystemTime::UNIX_EPOCH).unwrap() + invoice.expiry_time()
+       invoice.signed_invoice.raw_invoice.data.timestamp.0 + invoice.expiry_time()
 }
 
+#[cfg(feature = "std")]
 fn has_expired(params: &RouteParameters) -> bool {
        if let Some(expiry_time) = params.payee.expiry_time {
                Invoice::is_expired_from_epoch(&SystemTime::UNIX_EPOCH, Duration::from_secs(expiry_time))
@@ -510,8 +525,8 @@ where
 #[cfg(test)]
 mod tests {
        use super::*;
-       use crate::{DEFAULT_EXPIRY_TIME, InvoiceBuilder, Currency};
-       use utils::create_invoice_from_channelmanager;
+       use crate::{InvoiceBuilder, Currency};
+       use utils::create_invoice_from_channelmanager_and_duration_since_epoch;
        use bitcoin_hashes::sha256::Hash as Sha256;
        use lightning::ln::PaymentPreimage;
        use lightning::ln::features::{ChannelFeatures, NodeFeatures, InitFeatures};
@@ -526,15 +541,17 @@ mod tests {
        use std::cell::RefCell;
        use std::collections::VecDeque;
        use std::time::{SystemTime, Duration};
+       use DEFAULT_EXPIRY_TIME;
 
        fn invoice(payment_preimage: PaymentPreimage) -> Invoice {
                let payment_hash = Sha256::hash(&payment_preimage.0);
                let private_key = SecretKey::from_slice(&[42; 32]).unwrap();
+
                InvoiceBuilder::new(Currency::Bitcoin)
                        .description("test".into())
                        .payment_hash(payment_hash)
                        .payment_secret(PaymentSecret([0; 32]))
-                       .current_timestamp()
+                       .duration_since_epoch(duration_since_epoch())
                        .min_final_cltv_expiry(144)
                        .amount_milli_satoshis(128)
                        .build_signed(|hash| {
@@ -543,14 +560,24 @@ mod tests {
                        .unwrap()
        }
 
+       fn duration_since_epoch() -> Duration {
+               #[cfg(feature = "std")]
+                       let duration_since_epoch =
+                       SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
+               #[cfg(not(feature = "std"))]
+                       let duration_since_epoch = Duration::from_secs(1234567);
+               duration_since_epoch
+       }
+
        fn zero_value_invoice(payment_preimage: PaymentPreimage) -> Invoice {
                let payment_hash = Sha256::hash(&payment_preimage.0);
                let private_key = SecretKey::from_slice(&[42; 32]).unwrap();
+
                InvoiceBuilder::new(Currency::Bitcoin)
                        .description("test".into())
                        .payment_hash(payment_hash)
                        .payment_secret(PaymentSecret([0; 32]))
-                       .current_timestamp()
+                       .duration_since_epoch(duration_since_epoch())
                        .min_final_cltv_expiry(144)
                        .build_signed(|hash| {
                                Secp256k1::new().sign_recoverable(hash, &private_key)
@@ -558,17 +585,18 @@ mod tests {
                        .unwrap()
        }
 
+       #[cfg(feature = "std")]
        fn expired_invoice(payment_preimage: PaymentPreimage) -> Invoice {
                let payment_hash = Sha256::hash(&payment_preimage.0);
                let private_key = SecretKey::from_slice(&[42; 32]).unwrap();
-               let timestamp = SystemTime::now()
+               let duration = duration_since_epoch()
                        .checked_sub(Duration::from_secs(DEFAULT_EXPIRY_TIME * 2))
                        .unwrap();
                InvoiceBuilder::new(Currency::Bitcoin)
                        .description("test".into())
                        .payment_hash(payment_hash)
                        .payment_secret(PaymentSecret([0; 32]))
-                       .timestamp(timestamp)
+                       .duration_since_epoch(duration)
                        .min_final_cltv_expiry(144)
                        .amount_milli_satoshis(128)
                        .build_signed(|hash| {
@@ -811,6 +839,8 @@ mod tests {
                assert_eq!(*payer.attempts.borrow(), 1);
        }
 
+       // Expiration is checked only in an std environment
+       #[cfg(feature = "std")]
        #[test]
        fn fails_paying_invoice_after_expiration() {
                let event_handled = core::cell::RefCell::new(false);
@@ -830,6 +860,8 @@ mod tests {
                } else { panic!("Expected Invoice Error"); }
        }
 
+       // Expiration is checked only in an std environment
+       #[cfg(feature = "std")]
        #[test]
        fn fails_retrying_invoice_after_expiration() {
                let event_handled = core::cell::RefCell::new(false);
@@ -1524,8 +1556,9 @@ mod tests {
                let scorer = RefCell::new(TestScorer::new());
                let invoice_payer = InvoicePayer::new(nodes[0].node, router, &scorer, nodes[0].logger, event_handler, RetryAttempts(1));
 
-               assert!(invoice_payer.pay_invoice(&create_invoice_from_channelmanager(
-                       &nodes[1].node, nodes[1].keys_manager, Currency::Bitcoin, Some(100_010_000), "Invoice".to_string()).unwrap())
+               assert!(invoice_payer.pay_invoice(&create_invoice_from_channelmanager_and_duration_since_epoch(
+                       &nodes[1].node, nodes[1].keys_manager, Currency::Bitcoin, Some(100_010_000), "Invoice".to_string(),
+                       duration_since_epoch()).unwrap())
                        .is_ok());
                let htlc_msgs = nodes[0].node.get_and_clear_pending_msg_events();
                assert_eq!(htlc_msgs.len(), 2);
@@ -1569,8 +1602,9 @@ mod tests {
                let scorer = RefCell::new(TestScorer::new());
                let invoice_payer = InvoicePayer::new(nodes[0].node, router, &scorer, nodes[0].logger, event_handler, RetryAttempts(1));
 
-               assert!(invoice_payer.pay_invoice(&create_invoice_from_channelmanager(
-                       &nodes[1].node, nodes[1].keys_manager, Currency::Bitcoin, Some(100_010_000), "Invoice".to_string()).unwrap())
+               assert!(invoice_payer.pay_invoice(&create_invoice_from_channelmanager_and_duration_since_epoch(
+                       &nodes[1].node, nodes[1].keys_manager, Currency::Bitcoin, Some(100_010_000), "Invoice".to_string(),
+                       duration_since_epoch()).unwrap())
                        .is_ok());
                let htlc_msgs = nodes[0].node.get_and_clear_pending_msg_events();
                assert_eq!(htlc_msgs.len(), 2);
@@ -1650,8 +1684,9 @@ mod tests {
                let scorer = RefCell::new(TestScorer::new());
                let invoice_payer = InvoicePayer::new(nodes[0].node, router, &scorer, nodes[0].logger, event_handler, RetryAttempts(1));
 
-               assert!(invoice_payer.pay_invoice(&create_invoice_from_channelmanager(
-                       &nodes[1].node, nodes[1].keys_manager, Currency::Bitcoin, Some(100_010_000), "Invoice".to_string()).unwrap())
+               assert!(invoice_payer.pay_invoice(&create_invoice_from_channelmanager_and_duration_since_epoch(
+                       &nodes[1].node, nodes[1].keys_manager, Currency::Bitcoin, Some(100_010_000), "Invoice".to_string(),
+                       duration_since_epoch()).unwrap())
                        .is_ok());
                let htlc_updates = SendEvent::from_node(&nodes[0]);
                check_added_monitors!(nodes[0], 1);
index 7d9ca9eb895cbd7a5f0566afa94553ac8448133e..f921a5b0f6959a832c0eea01c915635ba1820859 100644 (file)
@@ -1,6 +1,7 @@
-use std::fmt;
-use std::fmt::{Display, Formatter};
+use core::fmt;
+use core::fmt::{Display, Formatter};
 use bech32::{ToBase32, u5, WriteBase32, Base32Len};
+use crate::prelude::*;
 
 use super::{Invoice, Sha256, TaggedField, ExpiryTime, MinFinalCltvExpiry, Fallback, PayeePubKey, InvoiceSignature, PositiveTimestamp,
        PrivateRoute, Description, RawTaggedField, Currency, RawHrp, SiPrefix, constants, SignedRawInvoice, RawDataPart};
@@ -64,7 +65,7 @@ impl<'a, W: WriteBase32> BytesToBase32<'a, W> {
 
        pub fn finalize(mut self) ->  Result<(), W::Err> {
                self.inner_finalize()?;
-               std::mem::forget(self);
+               core::mem::forget(self);
                Ok(())
        }
 
diff --git a/lightning-invoice/src/sync.rs b/lightning-invoice/src/sync.rs
new file mode 100644 (file)
index 0000000..fae923f
--- /dev/null
@@ -0,0 +1,37 @@
+use core::cell::{RefCell, RefMut};
+use core::ops::{Deref, DerefMut};
+
+pub type LockResult<Guard> = Result<Guard, ()>;
+
+pub struct Mutex<T: ?Sized> {
+       inner: RefCell<T>
+}
+
+#[must_use = "if unused the Mutex will immediately unlock"]
+pub struct MutexGuard<'a, T: ?Sized + 'a> {
+       lock: RefMut<'a, T>,
+}
+
+impl<T: ?Sized> Deref for MutexGuard<'_, T> {
+       type Target = T;
+
+       fn deref(&self) -> &T {
+               &self.lock.deref()
+       }
+}
+
+impl<T: ?Sized> DerefMut for MutexGuard<'_, T> {
+       fn deref_mut(&mut self) -> &mut T {
+               self.lock.deref_mut()
+       }
+}
+
+impl<T> Mutex<T> {
+       pub fn new(inner: T) -> Mutex<T> {
+               Mutex { inner: RefCell::new(inner) }
+       }
+
+       pub fn lock<'a>(&'a self) -> LockResult<MutexGuard<'a, T>> {
+               Ok(MutexGuard { lock: self.inner.borrow_mut() })
+       }
+}
index 53fdc13f2fc2255f7102a3225252f4139e887efc..ffa84c98ef6191045a719a1d25aa7215ecabd186 100644 (file)
@@ -5,6 +5,7 @@ use payment::{Payer, Router};
 
 use bech32::ToBase32;
 use bitcoin_hashes::Hash;
+use crate::prelude::*;
 use lightning::chain;
 use lightning::chain::chaininterface::{BroadcasterInterface, FeeEstimator};
 use lightning::chain::keysinterface::{Sign, KeysInterface};
@@ -16,9 +17,11 @@ use lightning::routing::network_graph::{NetworkGraph, RoutingFees};
 use lightning::routing::router::{Route, RouteHint, RouteHintHop, RouteParameters, find_route};
 use lightning::util::logger::Logger;
 use secp256k1::key::PublicKey;
-use std::convert::TryInto;
-use std::ops::Deref;
+use core::convert::TryInto;
+use core::ops::Deref;
+use core::time::Duration;
 
+#[cfg(feature = "std")]
 /// Utility to construct an invoice. Generally, unless you want to do something like a custom
 /// cltv_expiry, this is what you should be using to create an invoice. The reason being, this
 /// method stores the invoice's payment secret and preimage in `ChannelManager`, so (a) the user
@@ -28,6 +31,33 @@ pub fn create_invoice_from_channelmanager<Signer: Sign, M: Deref, T: Deref, K: D
        channelmanager: &ChannelManager<Signer, M, T, K, F, L>, keys_manager: K, network: Currency,
        amt_msat: Option<u64>, description: String
 ) -> Result<Invoice, SignOrCreationError<()>>
+where
+       M::Target: chain::Watch<Signer>,
+       T::Target: BroadcasterInterface,
+       K::Target: KeysInterface<Signer = Signer>,
+       F::Target: FeeEstimator,
+       L::Target: Logger,
+{
+       use std::time::SystemTime;
+       let duration = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)
+               .expect("for the foreseeable future this shouldn't happen");
+       create_invoice_from_channelmanager_and_duration_since_epoch(
+               channelmanager,
+               keys_manager,
+               network,
+               amt_msat,
+               description,
+               duration
+       )
+}
+
+/// See [`create_invoice_from_channelmanager`]
+/// This version can be used in a `no_std` environment, where [`std::time::SystemTime`] is not
+/// available and the current time is supplied by the caller.
+pub fn create_invoice_from_channelmanager_and_duration_since_epoch<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(
+       channelmanager: &ChannelManager<Signer, M, T, K, F, L>, keys_manager: K, network: Currency,
+       amt_msat: Option<u64>, description: String, duration_since_epoch: Duration,
+) -> Result<Invoice, SignOrCreationError<()>>
 where
        M::Target: chain::Watch<Signer>,
        T::Target: BroadcasterInterface,
@@ -68,7 +98,7 @@ where
        let our_node_pubkey = channelmanager.get_our_node_id();
        let mut invoice = InvoiceBuilder::new(network)
                .description(description)
-               .current_timestamp()
+               .duration_since_epoch(duration_since_epoch)
                .payee_pub_key(our_node_pubkey)
                .payment_hash(Hash::from_slice(&payment_hash.0).unwrap())
                .payment_secret(payment_secret)
@@ -161,6 +191,7 @@ where
 
 #[cfg(test)]
 mod test {
+       use core::time::Duration;
        use {Currency, Description, InvoiceDescription};
        use lightning::ln::PaymentHash;
        use lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY;
@@ -170,6 +201,8 @@ mod test {
        use lightning::routing::router::{Payee, RouteParameters, find_route};
        use lightning::util::events::MessageSendEventsProvider;
        use lightning::util::test_utils;
+       use utils::create_invoice_from_channelmanager_and_duration_since_epoch;
+
        #[test]
        fn test_from_channelmanager() {
                let chanmon_cfgs = create_chanmon_cfgs(2);
@@ -177,7 +210,9 @@ mod test {
                let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
                let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
                let _chan = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
-               let invoice = ::utils::create_invoice_from_channelmanager(&nodes[1].node, nodes[1].keys_manager, Currency::BitcoinTestnet, Some(10_000), "test".to_string()).unwrap();
+               let invoice = create_invoice_from_channelmanager_and_duration_since_epoch(
+                       &nodes[1].node, nodes[1].keys_manager, Currency::BitcoinTestnet, Some(10_000), "test".to_string(),
+                       Duration::from_secs(1234567)).unwrap();
                assert_eq!(invoice.amount_pico_btc(), Some(100_000));
                assert_eq!(invoice.min_final_cltv_expiry(), MIN_FINAL_CLTV_EXPIRY as u64);
                assert_eq!(invoice.description(), InvoiceDescription::Direct(&Description("test".to_string())));
index a2cc0e2e2b62f70aa883946e45fcc123a510dc9e..1eaeb31378513065e74a7c4958e9b8e0c8befa8e 100644 (file)
@@ -15,7 +15,7 @@ use lightning_invoice::*;
 use secp256k1::PublicKey;
 use secp256k1::recovery::{RecoverableSignature, RecoveryId};
 use std::collections::HashSet;
-use std::time::{Duration, UNIX_EPOCH};
+use std::time::Duration;
 use std::str::FromStr;
 
 fn get_test_tuples() -> Vec<(String, SignedRawInvoice, bool, bool)> {
@@ -23,7 +23,7 @@ fn get_test_tuples() -> Vec<(String, SignedRawInvoice, bool, bool)> {
                (
                        "lnbc1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq9qrsgq357wnc5r2ueh7ck6q93dj32dlqnls087fxdwk8qakdyafkq3yap9us6v52vjjsrvywa6rt52cm9r9zqt8r2t7mlcwspyetp5h2tztugp9lfyql".to_owned(),
                        InvoiceBuilder::new(Currency::Bitcoin)
-                               .timestamp(UNIX_EPOCH + Duration::from_secs(1496314658))
+                               .duration_since_epoch(Duration::from_secs(1496314658))
                                .payment_secret(PaymentSecret([0x11; 32]))
                                .payment_hash(sha256::Hash::from_hex(
                                                "0001020304050607080900010203040506070809000102030405060708090102"
@@ -44,7 +44,7 @@ fn get_test_tuples() -> Vec<(String, SignedRawInvoice, bool, bool)> {
                        "lnbc2500u1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpu9qrsgquk0rl77nj30yxdy8j9vdx85fkpmdla2087ne0xh8nhedh8w27kyke0lp53ut353s06fv3qfegext0eh0ymjpf39tuven09sam30g4vgpfna3rh".to_owned(),
                        InvoiceBuilder::new(Currency::Bitcoin)
                                .amount_milli_satoshis(250_000_000)
-                               .timestamp(UNIX_EPOCH + Duration::from_secs(1496314658))
+                               .duration_since_epoch(Duration::from_secs(1496314658))
                                .payment_secret(PaymentSecret([0x11; 32]))
                                .payment_hash(sha256::Hash::from_hex(
                                        "0001020304050607080900010203040506070809000102030405060708090102"
@@ -66,7 +66,7 @@ fn get_test_tuples() -> Vec<(String, SignedRawInvoice, bool, bool)> {
                        "lnbc2500u1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpu9qrsgqhtjpauu9ur7fw2thcl4y9vfvh4m9wlfyz2gem29g5ghe2aak2pm3ps8fdhtceqsaagty2vph7utlgj48u0ged6a337aewvraedendscp573dxr".to_owned(),
                        InvoiceBuilder::new(Currency::Bitcoin)
                                .amount_milli_satoshis(250_000_000)
-                               .timestamp(UNIX_EPOCH + Duration::from_secs(1496314658))
+                               .duration_since_epoch(Duration::from_secs(1496314658))
                                .payment_secret(PaymentSecret([0x11; 32]))
                                .payment_hash(sha256::Hash::from_hex(
                                        "0001020304050607080900010203040506070809000102030405060708090102"
@@ -88,7 +88,7 @@ fn get_test_tuples() -> Vec<(String, SignedRawInvoice, bool, bool)> {
                        "lnbc20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qrsgq7ea976txfraylvgzuxs8kgcw23ezlrszfnh8r6qtfpr6cxga50aj6txm9rxrydzd06dfeawfk6swupvz4erwnyutnjq7x39ymw6j38gp7ynn44".to_owned(),
                        InvoiceBuilder::new(Currency::Bitcoin)
                                .amount_milli_satoshis(2_000_000_000)
-                               .timestamp(UNIX_EPOCH + Duration::from_secs(1496314658))
+                               .duration_since_epoch(Duration::from_secs(1496314658))
                                .description_hash(sha256::Hash::hash(b"One piece of chocolate cake, one icecream cone, one pickle, one slice of swiss cheese, one slice of salami, one lollypop, one piece of cherry pie, one sausage, one cupcake, and one slice of watermelon"))
                                .payment_secret(PaymentSecret([0x11; 32]))
                                .payment_hash(sha256::Hash::from_hex(
@@ -109,7 +109,7 @@ fn get_test_tuples() -> Vec<(String, SignedRawInvoice, bool, bool)> {
                        "lntb20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygshp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqfpp3x9et2e20v6pu37c5d9vax37wxq72un989qrsgqdj545axuxtnfemtpwkc45hx9d2ft7x04mt8q7y6t0k2dge9e7h8kpy9p34ytyslj3yu569aalz2xdk8xkd7ltxqld94u8h2esmsmacgpghe9k8".to_owned(),
                        InvoiceBuilder::new(Currency::BitcoinTestnet)
                                .amount_milli_satoshis(2_000_000_000)
-                               .timestamp(UNIX_EPOCH + Duration::from_secs(1496314658))
+                               .duration_since_epoch(Duration::from_secs(1496314658))
                                .description_hash(sha256::Hash::hash(b"One piece of chocolate cake, one icecream cone, one pickle, one slice of swiss cheese, one slice of salami, one lollypop, one piece of cherry pie, one sausage, one cupcake, and one slice of watermelon"))
                                .payment_secret(PaymentSecret([0x11; 32]))
                                .payment_hash(sha256::Hash::from_hex(
@@ -131,7 +131,7 @@ fn get_test_tuples() -> Vec<(String, SignedRawInvoice, bool, bool)> {
                        "lnbc20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3qjmp7lwpagxun9pygexvgpjdc4jdj85fr9yq20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqafqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqgqqqqq7qqzq9qrsgqdfjcdk6w3ak5pca9hwfwfh63zrrz06wwfya0ydlzpgzxkn5xagsqz7x9j4jwe7yj7vaf2k9lqsdk45kts2fd0fkr28am0u4w95tt2nsq76cqw0".to_owned(),
                        InvoiceBuilder::new(Currency::Bitcoin)
                                .amount_milli_satoshis(2_000_000_000)
-                               .timestamp(UNIX_EPOCH + Duration::from_secs(1496314658))
+                               .duration_since_epoch(Duration::from_secs(1496314658))
                                .description_hash(sha256::Hash::hash(b"One piece of chocolate cake, one icecream cone, one pickle, one slice of swiss cheese, one slice of salami, one lollypop, one piece of cherry pie, one sausage, one cupcake, and one slice of watermelon"))
                                .payment_secret(PaymentSecret([0x11; 32]))
                                .payment_hash(sha256::Hash::from_hex(
@@ -170,7 +170,7 @@ fn get_test_tuples() -> Vec<(String, SignedRawInvoice, bool, bool)> {
                        "lnbc20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygshp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqfppj3a24vwu6r8ejrss3axul8rxldph2q7z99qrsgqz6qsgww34xlatfj6e3sngrwfy3ytkt29d2qttr8qz2mnedfqysuqypgqex4haa2h8fx3wnypranf3pdwyluftwe680jjcfp438u82xqphf75ym".to_owned(),
                        InvoiceBuilder::new(Currency::Bitcoin)
                                .amount_milli_satoshis(2_000_000_000)
-                               .timestamp(UNIX_EPOCH + Duration::from_secs(1496314658))
+                               .duration_since_epoch(Duration::from_secs(1496314658))
                                .description_hash(sha256::Hash::hash(b"One piece of chocolate cake, one icecream cone, one pickle, one slice of swiss cheese, one slice of salami, one lollypop, one piece of cherry pie, one sausage, one cupcake, and one slice of watermelon"))
                                .payment_secret(PaymentSecret([0x11; 32]))
                                .payment_hash(sha256::Hash::from_hex(
@@ -192,7 +192,7 @@ fn get_test_tuples() -> Vec<(String, SignedRawInvoice, bool, bool)> {
                        "lnbc20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygshp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqfppqw508d6qejxtdg4y5r3zarvary0c5xw7k9qrsgqt29a0wturnys2hhxpner2e3plp6jyj8qx7548zr2z7ptgjjc7hljm98xhjym0dg52sdrvqamxdezkmqg4gdrvwwnf0kv2jdfnl4xatsqmrnsse".to_owned(),
                        InvoiceBuilder::new(Currency::Bitcoin)
                                .amount_milli_satoshis(2_000_000_000)
-                               .timestamp(UNIX_EPOCH + Duration::from_secs(1496314658))
+                               .duration_since_epoch(Duration::from_secs(1496314658))
                                .description_hash(sha256::Hash::hash(b"One piece of chocolate cake, one icecream cone, one pickle, one slice of swiss cheese, one slice of salami, one lollypop, one piece of cherry pie, one sausage, one cupcake, and one slice of watermelon"))
                                .payment_secret(PaymentSecret([0x11; 32]))
                                .payment_hash(sha256::Hash::from_hex(
@@ -216,7 +216,7 @@ fn get_test_tuples() -> Vec<(String, SignedRawInvoice, bool, bool)> {
                        "lnbc20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygshp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqfp4qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q9qrsgq9vlvyj8cqvq6ggvpwd53jncp9nwc47xlrsnenq2zp70fq83qlgesn4u3uyf4tesfkkwwfg3qs54qe426hp3tz7z6sweqdjg05axsrjqp9yrrwc".to_owned(),
                        InvoiceBuilder::new(Currency::Bitcoin)
                                .amount_milli_satoshis(2_000_000_000)
-                               .timestamp(UNIX_EPOCH + Duration::from_secs(1496314658))
+                               .duration_since_epoch(Duration::from_secs(1496314658))
                                .description_hash(sha256::Hash::hash(b"One piece of chocolate cake, one icecream cone, one pickle, one slice of swiss cheese, one slice of salami, one lollypop, one piece of cherry pie, one sausage, one cupcake, and one slice of watermelon"))
                                .payment_secret(PaymentSecret([0x11; 32]))
                                .payment_hash(sha256::Hash::from_hex(
@@ -240,7 +240,7 @@ fn get_test_tuples() -> Vec<(String, SignedRawInvoice, bool, bool)> {
                        "lnbc9678785340p1pwmna7lpp5gc3xfm08u9qy06djf8dfflhugl6p7lgza6dsjxq454gxhj9t7a0sd8dgfkx7cmtwd68yetpd5s9xar0wfjn5gpc8qhrsdfq24f5ggrxdaezqsnvda3kkum5wfjkzmfqf3jkgem9wgsyuctwdus9xgrcyqcjcgpzgfskx6eqf9hzqnteypzxz7fzypfhg6trddjhygrcyqezcgpzfysywmm5ypxxjemgw3hxjmn8yptk7untd9hxwg3q2d6xjcmtv4ezq7pqxgsxzmnyyqcjqmt0wfjjq6t5v4khxsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsxqyjw5qcqp2rzjq0gxwkzc8w6323m55m4jyxcjwmy7stt9hwkwe2qxmy8zpsgg7jcuwz87fcqqeuqqqyqqqqlgqqqqn3qq9q9qrsgqrvgkpnmps664wgkp43l22qsgdw4ve24aca4nymnxddlnp8vh9v2sdxlu5ywdxefsfvm0fq3sesf08uf6q9a2ke0hc9j6z6wlxg5z5kqpu2v9wz".to_owned(),
                        InvoiceBuilder::new(Currency::Bitcoin)
                                .amount_milli_satoshis(967878534)
-                               .timestamp(UNIX_EPOCH + Duration::from_secs(1572468703))
+                               .duration_since_epoch(Duration::from_secs(1572468703))
                                .payment_secret(PaymentSecret([0x11; 32]))
                                .payment_hash(sha256::Hash::from_hex(
                                        "462264ede7e14047e9b249da94fefc47f41f7d02ee9b091815a5506bc8abf75f"
@@ -272,7 +272,7 @@ fn get_test_tuples() -> Vec<(String, SignedRawInvoice, bool, bool)> {
                        "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqqsgq2a25dxl5hrntdtn6zvydt7d66hyzsyhqs4wdynavys42xgl6sgx9c4g7me86a27t07mdtfry458rtjr0v92cnmswpsjscgt2vcse3sgpz3uapa".to_owned(),
                        InvoiceBuilder::new(Currency::Bitcoin)
                                .amount_milli_satoshis(2_500_000_000)
-                               .timestamp(UNIX_EPOCH + Duration::from_secs(1496314658))
+                               .duration_since_epoch(Duration::from_secs(1496314658))
                                .payment_secret(PaymentSecret([0x11; 32]))
                                .payment_hash(sha256::Hash::from_hex(
                                        "0001020304050607080900010203040506070809000102030405060708090102"
@@ -293,7 +293,7 @@ fn get_test_tuples() -> Vec<(String, SignedRawInvoice, bool, bool)> {
                        "LNBC25M1PVJLUEZPP5QQQSYQCYQ5RQWZQFQQQSYQCYQ5RQWZQFQQQSYQCYQ5RQWZQFQYPQDQ5VDHKVEN9V5SXYETPDEESSP5ZYG3ZYG3ZYG3ZYG3ZYG3ZYG3ZYG3ZYG3ZYG3ZYG3ZYG3ZYG3ZYGS9Q5SQQQQQQQQQQQQQQQQSGQ2A25DXL5HRNTDTN6ZVYDT7D66HYZSYHQS4WDYNAVYS42XGL6SGX9C4G7ME86A27T07MDTFRY458RTJR0V92CNMSWPSJSCGT2VCSE3SGPZ3UAPA".to_owned(),
                        InvoiceBuilder::new(Currency::Bitcoin)
                                .amount_milli_satoshis(2_500_000_000)
-                               .timestamp(UNIX_EPOCH + Duration::from_secs(1496314658))
+                               .duration_since_epoch(Duration::from_secs(1496314658))
                                .payment_secret(PaymentSecret([0x11; 32]))
                                .payment_hash(sha256::Hash::from_hex(
                                        "0001020304050607080900010203040506070809000102030405060708090102"
@@ -314,7 +314,7 @@ fn get_test_tuples() -> Vec<(String, SignedRawInvoice, bool, bool)> {
                        "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqqsgq2qrqqqfppnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqppnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpp4qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqhpnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqhp4qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqspnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsp4qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqnp5qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqnpkqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqz599y53s3ujmcfjp5xrdap68qxymkqphwsexhmhr8wdz5usdzkzrse33chw6dlp3jhuhge9ley7j2ayx36kawe7kmgg8sv5ugdyusdcqzn8z9x".to_owned(),
                        InvoiceBuilder::new(Currency::Bitcoin)
                                .amount_milli_satoshis(2_500_000_000)
-                               .timestamp(UNIX_EPOCH + Duration::from_secs(1496314658))
+                               .duration_since_epoch(Duration::from_secs(1496314658))
                                .payment_secret(PaymentSecret([0x11; 32]))
                                .payment_hash(sha256::Hash::from_hex(
                                        "0001020304050607080900010203040506070809000102030405060708090102"
index 8ff793ed08b723280c3f089eb2ce74cb7bd2ad53..8410cac9132dc66d844d71583873bb72cc517f64 100644 (file)
@@ -22,7 +22,7 @@ use ln::msgs;
 use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler};
 use util::enforcing_trait_impls::EnforcingSigner;
 use util::test_utils;
-use util::test_utils::TestChainMonitor;
+use util::test_utils::{panicking, TestChainMonitor};
 use util::events::{Event, MessageSendEvent, MessageSendEventsProvider, PaymentPurpose};
 use util::errors::APIError;
 use util::config::UserConfig;
@@ -40,7 +40,7 @@ use bitcoin::secp256k1::key::PublicKey;
 use io;
 use prelude::*;
 use core::cell::RefCell;
-use std::rc::Rc;
+use alloc::rc::Rc;
 use sync::{Arc, Mutex};
 use core::mem;
 
@@ -231,7 +231,7 @@ impl<'a, 'b, 'c> Node<'a, 'b, 'c> {
 
 impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> {
        fn drop(&mut self) {
-               if !::std::thread::panicking() {
+               if !panicking() {
                        // Check that we processed all pending events
                        assert!(self.node.get_and_clear_pending_msg_events().is_empty());
                        assert!(self.node.get_and_clear_pending_events().is_empty());
index 01c637b41ee6c0351f615c1b9bebc10be0ac11cb..5b3865eda04fca2a864933b978485cab46d800d2 100644 (file)
@@ -462,6 +462,7 @@ impl Logger for TestLogger {
        fn log(&self, record: &Record) {
                *self.lines.lock().unwrap().entry((record.module_path.to_string(), format!("{}", record.args))).or_insert(0) += 1;
                if record.level >= self.level {
+                       #[cfg(feature = "std")]
                        println!("{:<5} {} [{} : {}, {}] {}", record.level.to_string(), self.id, record.module_path, record.file, record.line, record.args);
                }
        }
@@ -571,9 +572,17 @@ impl TestKeysInterface {
        }
 }
 
+pub(crate) fn panicking() -> bool {
+       #[cfg(feature = "std")]
+       let panicking = ::std::thread::panicking();
+       #[cfg(not(feature = "std"))]
+       let panicking = false;
+       return panicking;
+}
+
 impl Drop for TestKeysInterface {
        fn drop(&mut self) {
-               if std::thread::panicking() {
+               if panicking() {
                        return;
                }
 
@@ -665,7 +674,7 @@ impl chain::Filter for TestChainSource {
 
 impl Drop for TestChainSource {
        fn drop(&mut self) {
-               if std::thread::panicking() {
+               if panicking() {
                        return;
                }