X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning-invoice%2Fsrc%2Flib.rs;h=20eaf7a82d27a7970872883536f7edce1da55c69;hb=ae4c35c3e05d918607104dce74e4a54060712023;hp=d953795cf8e061157f1c69e9c5bc5eae2b743ca6;hpb=2c51080449d647339b3a1ef80e386e8cc7b59fae;p=rust-lightning diff --git a/lightning-invoice/src/lib.rs b/lightning-invoice/src/lib.rs index d953795c..20eaf7a8 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)] @@ -31,9 +30,7 @@ pub mod payment; pub mod utils; extern crate bech32; -extern crate bitcoin_hashes; #[macro_use] extern crate lightning; -extern crate num_traits; extern crate secp256k1; extern crate alloc; #[cfg(any(test, feature = "std"))] @@ -46,8 +43,8 @@ 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 bitcoin::address::{Payload, WitnessProgram, WitnessVersion}; +use bitcoin::hashes::{Hash, sha256}; use lightning::ln::features::Bolt11InvoiceFeatures; use lightning::util::invoice::construct_invoice_preimage; @@ -73,36 +70,21 @@ pub use lightning::ln::PaymentSecret; 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}; - #[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::{vec, vec::Vec, string::String}; pub use alloc::string::ToString; } 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)] @@ -172,10 +154,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; @@ -269,6 +251,15 @@ pub enum Bolt11InvoiceDescription<'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. /// @@ -403,6 +394,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 + }, } } } @@ -470,8 +465,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)] @@ -547,7 +542,7 @@ impl InvoiceBuilder InvoiceBui pub fn invoice_description(self, description: Bolt11InvoiceDescription) -> InvoiceBuilder { match description { Bolt11InvoiceDescription::Direct(desc) => { - self.description(desc.clone().into_inner()) + self.description(desc.clone().into_inner().0) } Bolt11InvoiceDescription::Hash(hash) => { self.description_hash(hash.0) @@ -1136,6 +1131,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 { @@ -1346,6 +1347,15 @@ impl Bolt11Invoice { self.signed_invoice.recover_payee_pub_key().expect("was checked by constructor").0 } + /// Recover the payee's public key if one was included in the invoice, otherwise return the + /// recovered public key from the signature + pub fn get_payee_pub_key(&self) -> PublicKey { + match self.payee_pub_key() { + Some(pk) => *pk, + None => self.recover_payee_pub_key() + } + } + /// Returns the Duration since the Unix epoch at which the invoice expires. /// Returning None if overflow occurred. pub fn expires_at(&self) -> Option { @@ -1413,10 +1423,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) @@ -1426,7 +1439,7 @@ impl Bolt11Invoice { } }; - Address { payload, network: self.network() } + Some(Address::new(self.network(), payload)) }).collect() } @@ -1502,27 +1515,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) } } @@ -1747,9 +1752,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() { @@ -1773,7 +1778,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( @@ -1811,7 +1816,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( @@ -1867,7 +1872,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(); @@ -1881,7 +1886,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( @@ -2042,7 +2047,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(); @@ -2058,7 +2063,7 @@ mod test { let route_1 = RouteHint(vec![ RouteHintHop { src_node_id: public_key, - short_channel_id: de::parse_int_be(&[123; 8], 256).expect("short chan ID slice too big?"), + short_channel_id: u64::from_be_bytes([123; 8]), fees: RoutingFees { base_msat: 2, proportional_millionths: 1, @@ -2069,7 +2074,7 @@ mod test { }, RouteHintHop { src_node_id: public_key, - short_channel_id: de::parse_int_be(&[42; 8], 256).expect("short chan ID slice too big?"), + short_channel_id: u64::from_be_bytes([42; 8]), fees: RoutingFees { base_msat: 3, proportional_millionths: 2, @@ -2094,7 +2099,7 @@ mod test { }, RouteHintHop { src_node_id: public_key, - short_channel_id: de::parse_int_be(&[1; 8], 256).expect("short chan ID slice too big?"), + short_channel_id: u64::from_be_bytes([1; 8]), fees: RoutingFees { base_msat: 5, proportional_millionths: 4, @@ -2131,14 +2136,14 @@ 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!(