From: Devrandom Date: Wed, 22 Dec 2021 16:43:25 +0000 (+0100) Subject: Adapt lightning-invoice to no_std X-Git-Tag: v0.0.105~43^2 X-Git-Url: http://git.bitcoin.ninja/?a=commitdiff_plain;h=01915810d42506addbaef244b0cbb31e8b3856b5;p=rust-lightning Adapt lightning-invoice to no_std --- diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 20ca306b1..5dcbb677e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -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: | diff --git a/lightning-invoice/Cargo.toml b/lightning-invoice/Cargo.toml index 71648b3c8..129d0f23c 100644 --- a/lightning-invoice/Cargo.toml +++ b/lightning-invoice/Cargo.toml @@ -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"] } diff --git a/lightning-invoice/src/de.rs b/lightning-invoice/src/de.rs index 777ac660f..53f6b83da 100644 --- a/lightning-invoice/src/de.rs +++ b/lightning-invoice/src/de.rs @@ -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 { diff --git a/lightning-invoice/src/lib.rs b/lightning-invoice/src/lib.rs index dd86c06f2..2164f1c53 100644 --- a/lightning-invoice/src/lib.rs +++ b/lightning-invoice/src/lib.rs @@ -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) @@ -15,6 +16,10 @@ //! * For parsing use `str::parse::(&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::(&UNIX_EPOCH); } + unsafe { core::mem::transmute_copy::(&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, error: Option, - 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, } /// 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 { 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 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 InvoiceBuilder InvoiceBuilder { - /// Sets the timestamp. + /// Sets the timestamp to a specific [`SystemTime`]. + #[cfg(feature = "std")] pub fn timestamp(mut self, time: SystemTime) -> InvoiceBuilder { match PositiveTimestamp::from_system_time(time) { Ok(t) => self.timestamp = Some(t), @@ -599,7 +649,18 @@ impl InvoiceBuilder InvoiceBuilder { + 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 { 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 { - 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 { + 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 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 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))); } } diff --git a/lightning-invoice/src/payment.rs b/lightning-invoice/src/payment.rs index 4e249a85c..d73ca5389 100644 --- a/lightning-invoice/src/payment.rs +++ b/lightning-invoice/src/payment.rs @@ -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; @@ -47,6 +50,11 @@ //! # 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(&self, handler: H) where H::Target: EventHandler {} @@ -78,7 +86,7 @@ //! # //! # struct FakeScorer {} //! # impl Writeable for FakeScorer { -//! # fn write(&self, w: &mut W) -> Result<(), std::io::Error> { unimplemented!(); } +//! # fn write(&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 Result + Copy>( &self, params: &RouteParameters, payment_hash: PaymentHash, send_payment: F, ) -> Result { - 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); diff --git a/lightning-invoice/src/ser.rs b/lightning-invoice/src/ser.rs index 7d9ca9eb8..f921a5b0f 100644 --- a/lightning-invoice/src/ser.rs +++ b/lightning-invoice/src/ser.rs @@ -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 index 000000000..fae923feb --- /dev/null +++ b/lightning-invoice/src/sync.rs @@ -0,0 +1,37 @@ +use core::cell::{RefCell, RefMut}; +use core::ops::{Deref, DerefMut}; + +pub type LockResult = Result; + +pub struct Mutex { + inner: RefCell +} + +#[must_use = "if unused the Mutex will immediately unlock"] +pub struct MutexGuard<'a, T: ?Sized + 'a> { + lock: RefMut<'a, T>, +} + +impl Deref for MutexGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + &self.lock.deref() + } +} + +impl DerefMut for MutexGuard<'_, T> { + fn deref_mut(&mut self) -> &mut T { + self.lock.deref_mut() + } +} + +impl Mutex { + pub fn new(inner: T) -> Mutex { + Mutex { inner: RefCell::new(inner) } + } + + pub fn lock<'a>(&'a self) -> LockResult> { + Ok(MutexGuard { lock: self.inner.borrow_mut() }) + } +} diff --git a/lightning-invoice/src/utils.rs b/lightning-invoice/src/utils.rs index 53fdc13f2..ffa84c98e 100644 --- a/lightning-invoice/src/utils.rs +++ b/lightning-invoice/src/utils.rs @@ -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, keys_manager: K, network: Currency, amt_msat: Option, description: String ) -> Result> +where + M::Target: chain::Watch, + T::Target: BroadcasterInterface, + K::Target: KeysInterface, + 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( + channelmanager: &ChannelManager, keys_manager: K, network: Currency, + amt_msat: Option, description: String, duration_since_epoch: Duration, +) -> Result> where M::Target: chain::Watch, 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()))); diff --git a/lightning-invoice/tests/ser_de.rs b/lightning-invoice/tests/ser_de.rs index a2cc0e2e2..1eaeb3137 100644 --- a/lightning-invoice/tests/ser_de.rs +++ b/lightning-invoice/tests/ser_de.rs @@ -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" diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 8ff793ed0..8410cac91 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -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()); diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index 01c637b41..5b3865eda 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -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; }