X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning-invoice%2Fsrc%2Flib.rs;h=df0412bfc5d3e0d3876b177200527e01fd272678;hb=51d9ee35e53534bb2d907fc105699114134736a5;hp=f26903a74babe637560bc35d151ea5f37c67052b;hpb=a28c90a1b37f5a3fe371ca91ea5e150f2653f320;p=rust-lightning diff --git a/lightning-invoice/src/lib.rs b/lightning-invoice/src/lib.rs index f26903a7..df0412bf 100644 --- a/lightning-invoice/src/lib.rs +++ b/lightning-invoice/src/lib.rs @@ -1,6 +1,5 @@ -// Prefix these with `rustdoc::` when we update our MSRV to be >= 1.52 to remove warnings. -#![deny(broken_intra_doc_links)] -#![deny(private_intra_doc_links)] +#![deny(rustdoc::broken_intra_doc_links)] +#![deny(rustdoc::private_intra_doc_links)] #![deny(missing_docs)] #![deny(non_upper_case_globals)] @@ -30,10 +29,7 @@ compile_error!("at least one of the `std` or `no-std` features must be enabled") pub mod payment; pub mod utils; -pub(crate) mod time_utils; - extern crate bech32; -extern crate bitcoin_hashes; #[macro_use] extern crate lightning; extern crate num_traits; extern crate secp256k1; @@ -48,13 +44,9 @@ use std::time::SystemTime; use bech32::u5; use bitcoin::{Address, Network, PubkeyHash, ScriptHash}; -use bitcoin::util::address::{Payload, WitnessVersion}; -use bitcoin_hashes::{Hash, sha256}; -use lightning::ln::PaymentSecret; +use bitcoin::address::{Payload, WitnessProgram, WitnessVersion}; +use bitcoin::hashes::{Hash, sha256}; use lightning::ln::features::Bolt11InvoiceFeatures; -#[cfg(any(doc, test))] -use lightning::routing::gossip::RoutingFees; -use lightning::routing::router::RouteHint; use lightning::util::invoice::construct_invoice_preimage; use secp256k1::PublicKey; @@ -73,17 +65,26 @@ use core::str; #[cfg(feature = "serde")] use serde::{Deserialize, Deserializer,Serialize, Serializer, de::Error}; +#[doc(no_inline)] +pub use lightning::ln::PaymentSecret; +#[doc(no_inline)] +pub use lightning::routing::router::{RouteHint, RouteHintHop}; +#[doc(no_inline)] +pub use lightning::routing::gossip::RoutingFees; +use lightning::util::string::UntrustedString; + mod de; mod ser; mod tb; +#[allow(unused_imports)] mod prelude { #[cfg(feature = "hashbrown")] extern crate hashbrown; - pub use alloc::{vec, vec::Vec, string::String, collections::VecDeque, boxed::Box}; + pub use alloc::{vec, vec::Vec, string::String}; #[cfg(not(feature = "hashbrown"))] - pub use std::collections::{HashMap, HashSet, hash_map}; + pub use std::collections::{HashMap, hash_map}; #[cfg(feature = "hashbrown")] pub use self::hashbrown::{HashMap, HashSet, hash_map}; @@ -92,16 +93,6 @@ mod prelude { use crate::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; - /// Errors that indicate what is wrong with the invoice. They have some granularity for debug /// reasons, but should generally result in an "invalid BOLT11 invoice" message for the user. #[allow(missing_docs)] @@ -171,10 +162,10 @@ pub const DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA: u64 = 18; /// extern crate secp256k1; /// extern crate lightning; /// extern crate lightning_invoice; -/// extern crate bitcoin_hashes; +/// extern crate bitcoin; /// -/// use bitcoin_hashes::Hash; -/// use bitcoin_hashes::sha256; +/// use bitcoin::hashes::Hash; +/// use bitcoin::hashes::sha256; /// /// use secp256k1::Secp256k1; /// use secp256k1::SecretKey; @@ -260,7 +251,7 @@ pub struct Bolt11Invoice { /// This is not exported to bindings users as we don't have a good way to map the reference lifetimes making this /// practically impossible to use safely in languages like C. #[derive(Eq, PartialEq, Debug, Clone, Ord, PartialOrd)] -pub enum InvoiceDescription<'f> { +pub enum Bolt11InvoiceDescription<'f> { /// Reference to the directly supplied description in the invoice Direct(&'f Description), @@ -268,6 +259,15 @@ pub enum InvoiceDescription<'f> { Hash(&'f Sha256), } +impl<'f> Display for Bolt11InvoiceDescription<'f> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + Bolt11InvoiceDescription::Direct(desc) => write!(f, "{}", desc.0), + Bolt11InvoiceDescription::Hash(hash) => write!(f, "{}", hash.0), + } + } +} + /// Represents a signed [`RawBolt11Invoice`] with cached hash. The signature is not checked and may be /// invalid. /// @@ -402,6 +402,10 @@ impl From for Currency { Network::Testnet => Currency::BitcoinTestnet, Network::Regtest => Currency::Regtest, Network::Signet => Currency::Signet, + _ => { + debug_assert!(false, "Need to handle new rust-bitcoin network type"); + Currency::Regtest + }, } } } @@ -469,8 +473,8 @@ impl Sha256 { /// /// # Invariants /// The description can be at most 639 __bytes__ long -#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] -pub struct Description(String); +#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Default)] +pub struct Description(UntrustedString); /// Payee public key #[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] @@ -503,7 +507,7 @@ pub struct Bolt11InvoiceSignature(pub RecoverableSignature); impl PartialOrd for Bolt11InvoiceSignature { fn partial_cmp(&self, other: &Self) -> Option { - self.0.serialize_compact().1.partial_cmp(&other.0.serialize_compact().1) + Some(self.cmp(other)) } } @@ -671,12 +675,12 @@ impl InvoiceBui } /// Set the description or description hash. This function is only available if no description (hash) was set. - pub fn invoice_description(self, description: InvoiceDescription) -> InvoiceBuilder { + pub fn invoice_description(self, description: Bolt11InvoiceDescription) -> InvoiceBuilder { match description { - InvoiceDescription::Direct(desc) => { - self.description(desc.clone().into_inner()) + Bolt11InvoiceDescription::Direct(desc) => { + self.description(desc.clone().into_inner().0) } - InvoiceDescription::Hash(hash) => { + Bolt11InvoiceDescription::Hash(hash) => { self.description_hash(hash.0) } } @@ -1135,6 +1139,12 @@ impl PositiveTimestamp { } } +impl From for Duration { + fn from(val: PositiveTimestamp) -> Self { + val.0 + } +} + #[cfg(feature = "std")] impl From for SystemTime { fn from(val: PositiveTimestamp) -> Self { @@ -1310,12 +1320,12 @@ impl Bolt11Invoice { /// Return the description or a hash of it for longer ones /// - /// This is not exported to bindings users because we don't yet export InvoiceDescription - pub fn description(&self) -> InvoiceDescription { + /// This is not exported to bindings users because we don't yet export Bolt11InvoiceDescription + pub fn description(&self) -> Bolt11InvoiceDescription { if let Some(direct) = self.signed_invoice.description() { - return InvoiceDescription::Direct(direct); + return Bolt11InvoiceDescription::Direct(direct); } else if let Some(hash) = self.signed_invoice.description_hash() { - return InvoiceDescription::Hash(hash); + return Bolt11InvoiceDescription::Hash(hash); } unreachable!("ensured by constructor"); } @@ -1412,10 +1422,13 @@ impl Bolt11Invoice { /// Returns a list of all fallback addresses as [`Address`]es pub fn fallback_addresses(&self) -> Vec
{ - self.fallbacks().iter().map(|fallback| { + self.fallbacks().iter().filter_map(|fallback| { let payload = match fallback { Fallback::SegWitProgram { version, program } => { - Payload::WitnessProgram { version: *version, program: program.to_vec() } + match WitnessProgram::new(*version, program.clone()) { + Ok(witness_program) => Payload::WitnessProgram(witness_program), + Err(_) => return None, + } } Fallback::PubKeyHash(pkh) => { Payload::PubkeyHash(*pkh) @@ -1425,7 +1438,7 @@ impl Bolt11Invoice { } }; - Address { payload, network: self.network() } + Some(Address::new(self.network(), payload)) }).collect() } @@ -1501,27 +1514,19 @@ impl Description { if description.len() > 639 { Err(CreationError::DescriptionTooLong) } else { - Ok(Description(description)) + Ok(Description(UntrustedString(description))) } } - /// Returns the underlying description [`String`] - pub fn into_inner(self) -> String { + /// Returns the underlying description [`UntrustedString`] + pub fn into_inner(self) -> UntrustedString { self.0 } } -impl From for String { - fn from(val: Description) -> Self { - val.into_inner() - } -} - -impl Deref for Description { - type Target = str; - - fn deref(&self) -> &str { - &self.0 +impl Display for Description { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) } } @@ -1746,9 +1751,9 @@ impl<'de> Deserialize<'de> for Bolt11Invoice { #[cfg(test)] mod test { - use bitcoin::Script; - use bitcoin_hashes::hex::FromHex; - use bitcoin_hashes::sha256; + use bitcoin::ScriptBuf; + use bitcoin::hashes::sha256; + use std::str::FromStr; #[test] fn test_system_time_bounds_assumptions() { @@ -1772,7 +1777,7 @@ mod test { data: RawDataPart { timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(), tagged_fields: vec![ - PaymentHash(crate::Sha256(sha256::Hash::from_hex( + PaymentHash(crate::Sha256(sha256::Hash::from_str( "0001020304050607080900010203040506070809000102030405060708090102" ).unwrap())).into(), Description(crate::Description::new( @@ -1810,7 +1815,7 @@ mod test { data: RawDataPart { timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(), tagged_fields: vec ! [ - PaymentHash(Sha256(sha256::Hash::from_hex( + PaymentHash(Sha256(sha256::Hash::from_str( "0001020304050607080900010203040506070809000102030405060708090102" ).unwrap())).into(), Description( @@ -1866,7 +1871,7 @@ mod test { use lightning::ln::features::Bolt11InvoiceFeatures; use secp256k1::Secp256k1; use secp256k1::SecretKey; - use crate::{Bolt11Invoice, RawBolt11Invoice, RawHrp, RawDataPart, Currency, Sha256, PositiveTimestamp, + use crate::{Bolt11Invoice, RawBolt11Invoice, RawHrp, RawDataPart, Currency, Sha256, PositiveTimestamp, Bolt11SemanticError}; let private_key = SecretKey::from_slice(&[42; 32]).unwrap(); @@ -1880,7 +1885,7 @@ mod test { data: RawDataPart { timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(), tagged_fields: vec ! [ - PaymentHash(Sha256(sha256::Hash::from_hex( + PaymentHash(Sha256(sha256::Hash::from_str( "0001020304050607080900010203040506070809000102030405060708090102" ).unwrap())).into(), Description( @@ -2041,7 +2046,7 @@ mod test { use lightning::routing::router::RouteHintHop; use secp256k1::Secp256k1; use secp256k1::{SecretKey, PublicKey}; - use std::time::{UNIX_EPOCH, Duration}; + use std::time::Duration; let secp_ctx = Secp256k1::new(); @@ -2130,19 +2135,19 @@ mod test { assert_eq!(invoice.currency(), Currency::BitcoinTestnet); #[cfg(feature = "std")] assert_eq!( - invoice.timestamp().duration_since(UNIX_EPOCH).unwrap().as_secs(), + invoice.timestamp().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs(), 1234567 ); assert_eq!(invoice.payee_pub_key(), Some(&public_key)); assert_eq!(invoice.expiry_time(), Duration::from_secs(54321)); assert_eq!(invoice.min_final_cltv_expiry_delta(), 144); assert_eq!(invoice.fallbacks(), vec![&Fallback::PubKeyHash(PubkeyHash::from_slice(&[0;20]).unwrap())]); - let address = Address::from_script(&Script::new_p2pkh(&PubkeyHash::from_slice(&[0;20]).unwrap()), Network::Testnet).unwrap(); + let address = Address::from_script(&ScriptBuf::new_p2pkh(&PubkeyHash::from_slice(&[0;20]).unwrap()), Network::Testnet).unwrap(); assert_eq!(invoice.fallback_addresses(), vec![address]); assert_eq!(invoice.private_routes(), vec![&PrivateRoute(route_1), &PrivateRoute(route_2)]); assert_eq!( invoice.description(), - InvoiceDescription::Hash(&Sha256(sha256::Hash::from_slice(&[3;32][..]).unwrap())) + Bolt11InvoiceDescription::Hash(&Sha256(sha256::Hash::from_slice(&[3;32][..]).unwrap())) ); assert_eq!(invoice.payment_hash(), &sha256::Hash::from_slice(&[21;32][..]).unwrap()); assert_eq!(invoice.payment_secret(), &PaymentSecret([42; 32]));