# 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: |
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"] }
+#[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};
/// State machine to parse the hrp
mod hrp_sm {
- use std::ops::Range;
+ use core::ops::Range;
#[derive(PartialEq, Eq, Debug)]
enum States {
}
}
+#[cfg(feature = "std")]
impl error::Error for ParseError {}
+#[cfg(feature = "std")]
impl error::Error for ParseOrSemanticError {}
macro_rules! from_error {
#![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;
#[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;
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
/// 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); }
}
/// 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
+ );
}
///
/// use lightning_invoice::{Currency, InvoiceBuilder};
///
+/// # #[cfg(not(feature = "std"))]
+/// # fn main() {}
+/// # #[cfg(feature = "std")]
/// # fn main() {
/// let private_key = SecretKey::from_slice(
/// &[
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.
///
/// # 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)]
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,
}
}
}
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,
}
}
}
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),
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"));
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
/// ```
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)]
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
}
}
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
}
/// 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,
}
}
+ /// 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 {
}
}
+#[cfg(feature = "std")]
impl std::error::Error for CreationError { }
/// Errors that may occur when converting a `RawInvoice` to an `Invoice`. They relate to the
}
}
+#[cfg(feature = "std")]
impl std::error::Error for SemanticError { }
/// When signing using a fallible method either an user-supplied `SignError` or a `CreationError`
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]
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)
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(
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)
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
.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| {
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]
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| {
.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)));
}
}
//! # 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 {}
//! #
//! # 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(
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;
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.
///
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();
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)?)
}
},
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();
}
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))
#[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};
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| {
.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)
.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| {
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);
} 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);
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);
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);
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);
-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};
pub fn finalize(mut self) -> Result<(), W::Err> {
self.inner_finalize()?;
- std::mem::forget(self);
+ core::mem::forget(self);
Ok(())
}
--- /dev/null
+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() })
+ }
+}
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};
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
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,
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)
#[cfg(test)]
mod test {
+ use core::time::Duration;
use {Currency, Description, InvoiceDescription};
use lightning::ln::PaymentHash;
use lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY;
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);
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())));
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)> {
(
"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"
"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"
"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"
"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(
"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(
"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(
"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(
"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(
"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(
"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"
"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"
"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"
"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"
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;
use io;
use prelude::*;
use core::cell::RefCell;
-use std::rc::Rc;
+use alloc::rc::Rc;
use sync::{Arc, Mutex};
use core::mem;
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());
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);
}
}
}
}
+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;
}
impl Drop for TestChainSource {
fn drop(&mut self) {
- if std::thread::panicking() {
+ if panicking() {
return;
}