X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Foffers%2Foffer.rs;h=dd58c75cec27e600e803122d72d92036665b0976;hb=bf28957f6d488d1258a1e6f21af29344b18e2b75;hp=6df9b30a4efa4d9d351ca06d1fa0a10e3a5bc47e;hpb=33b9ba558c6b651e8d282052867e701f1543cec6;p=rust-lightning diff --git a/lightning/src/offers/offer.rs b/lightning/src/offers/offer.rs index 6df9b30a..dd58c75c 100644 --- a/lightning/src/offers/offer.rs +++ b/lightning/src/offers/offer.rs @@ -24,7 +24,7 @@ //! use core::num::NonZeroU64; //! use core::time::Duration; //! -//! use bitcoin::secp256k1::{KeyPair, PublicKey, Secp256k1, SecretKey}; +//! use bitcoin::secp256k1::{Keypair, PublicKey, Secp256k1, SecretKey}; //! use lightning::offers::offer::{Offer, OfferBuilder, Quantity}; //! use lightning::offers::parse::Bolt12ParseError; //! use lightning::util::ser::{Readable, Writeable}; @@ -39,7 +39,7 @@ //! # #[cfg(feature = "std")] //! # fn build() -> Result<(), Bolt12ParseError> { //! let secp_ctx = Secp256k1::new(); -//! let keys = KeyPair::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()); +//! let keys = Keypair::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()); //! let pubkey = PublicKey::from(keys); //! //! let expiration = SystemTime::now() + Duration::from_secs(24 * 60 * 60); @@ -78,8 +78,8 @@ //! [`ChannelManager::create_offer_builder`]: crate::ln::channelmanager::ChannelManager::create_offer_builder use bitcoin::blockdata::constants::ChainHash; -use bitcoin::network::constants::Network; -use bitcoin::secp256k1::{KeyPair, PublicKey, Secp256k1, self}; +use bitcoin::network::Network; +use bitcoin::secp256k1::{Keypair, PublicKey, Secp256k1, self}; use core::hash::{Hash, Hasher}; use core::num::NonZeroU64; use core::ops::Deref; @@ -163,10 +163,9 @@ pub struct OfferBuilder<'a, M: MetadataStrategy, T: secp256k1::Signing> { /// /// See [module-level documentation] for usage. /// -/// This is not exported to bindings users as builder patterns don't map outside of move semantics. -/// /// [module-level documentation]: self #[cfg(c_bindings)] +#[derive(Clone)] pub struct OfferWithExplicitMetadataBuilder<'a> { offer: OfferContents, metadata_strategy: core::marker::PhantomData, @@ -177,10 +176,9 @@ pub struct OfferWithExplicitMetadataBuilder<'a> { /// /// See [module-level documentation] for usage. /// -/// This is not exported to bindings users as builder patterns don't map outside of move semantics. -/// /// [module-level documentation]: self #[cfg(c_bindings)] +#[derive(Clone)] pub struct OfferWithDerivedMetadataBuilder<'a> { offer: OfferContents, metadata_strategy: core::marker::PhantomData, @@ -582,7 +580,7 @@ macro_rules! offer_accessors { ($self: ident, $contents: expr) => { } /// The minimum amount required for a successful payment of a single item. - pub fn amount(&$self) -> Option<&$crate::offers::offer::Amount> { + pub fn amount(&$self) -> Option<$crate::offers::offer::Amount> { $contents.amount() } @@ -666,6 +664,12 @@ impl Offer { pub fn expects_quantity(&self) -> bool { self.contents.expects_quantity() } + + pub(super) fn verify( + &self, key: &ExpandedKey, secp_ctx: &Secp256k1 + ) -> Result<(OfferId, Option), ()> { + self.contents.verify(&self.bytes, key, secp_ctx) + } } macro_rules! request_invoice_derived_payer_id { ($self: ident, $builder: ty) => { @@ -808,8 +812,8 @@ impl OfferContents { self.metadata.as_ref().and_then(|metadata| metadata.as_bytes()) } - pub fn amount(&self) -> Option<&Amount> { - self.amount.as_ref() + pub fn amount(&self) -> Option { + self.amount } pub fn description(&self) -> Option { @@ -911,7 +915,7 @@ impl OfferContents { /// Verifies that the offer metadata was produced from the offer in the TLV stream. pub(super) fn verify( &self, bytes: &[u8], key: &ExpandedKey, secp_ctx: &Secp256k1 - ) -> Result<(OfferId, Option), ()> { + ) -> Result<(OfferId, Option), ()> { match self.metadata() { Some(metadata) => { let tlv_stream = TlvStream::new(bytes).range(OFFER_TYPES).filter(|record| { @@ -968,6 +972,13 @@ impl OfferContents { } } +impl Readable for Offer { + fn read(reader: &mut R) -> Result { + let bytes: WithoutLength> = Readable::read(reader)?; + Self::try_from(bytes.0).map_err(|_| DecodeError::InvalidValue) + } +} + impl Writeable for Offer { fn write(&self, writer: &mut W) -> Result<(), io::Error> { WithoutLength(&self.bytes).write(writer) @@ -982,7 +993,7 @@ impl Writeable for OfferContents { /// The minimum amount required for an item in an [`Offer`], denominated in either bitcoin or /// another currency. -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum Amount { /// An amount of bitcoin. Bitcoin { @@ -1142,7 +1153,7 @@ mod tests { }; use bitcoin::blockdata::constants::ChainHash; - use bitcoin::network::constants::Network; + use bitcoin::network::Network; use bitcoin::secp256k1::Secp256k1; use core::num::NonZeroU64; use core::time::Duration; @@ -1176,6 +1187,7 @@ mod tests { assert_eq!(offer.paths(), &[]); assert_eq!(offer.issuer(), None); assert_eq!(offer.supported_quantity(), Quantity::One); + assert!(!offer.expects_quantity()); assert_eq!(offer.signing_pubkey(), Some(pubkey(42))); assert_eq!( @@ -1381,7 +1393,7 @@ mod tests { .build() .unwrap(); let tlv_stream = offer.as_tlv_stream(); - assert_eq!(offer.amount(), Some(&bitcoin_amount)); + assert_eq!(offer.amount(), Some(bitcoin_amount)); assert_eq!(tlv_stream.amount, Some(1000)); assert_eq!(tlv_stream.currency, None); @@ -1550,6 +1562,7 @@ mod tests { .build() .unwrap(); let tlv_stream = offer.as_tlv_stream(); + assert!(!offer.expects_quantity()); assert_eq!(offer.supported_quantity(), Quantity::One); assert_eq!(tlv_stream.quantity_max, None); @@ -1558,6 +1571,7 @@ mod tests { .build() .unwrap(); let tlv_stream = offer.as_tlv_stream(); + assert!(offer.expects_quantity()); assert_eq!(offer.supported_quantity(), Quantity::Unbounded); assert_eq!(tlv_stream.quantity_max, Some(0)); @@ -1566,6 +1580,7 @@ mod tests { .build() .unwrap(); let tlv_stream = offer.as_tlv_stream(); + assert!(offer.expects_quantity()); assert_eq!(offer.supported_quantity(), Quantity::Bounded(ten)); assert_eq!(tlv_stream.quantity_max, Some(10)); @@ -1574,6 +1589,7 @@ mod tests { .build() .unwrap(); let tlv_stream = offer.as_tlv_stream(); + assert!(offer.expects_quantity()); assert_eq!(offer.supported_quantity(), Quantity::Bounded(one)); assert_eq!(tlv_stream.quantity_max, Some(1)); @@ -1583,6 +1599,7 @@ mod tests { .build() .unwrap(); let tlv_stream = offer.as_tlv_stream(); + assert!(!offer.expects_quantity()); assert_eq!(offer.supported_quantity(), Quantity::One); assert_eq!(tlv_stream.quantity_max, None); } @@ -1862,6 +1879,9 @@ mod bolt12_tests { // with blinded path via Bob (0x424242...), blinding 020202... "lno1pgx9getnwss8vetrw3hhyucs5ypjgef743p5fzqq9nqxh0ah7y87rzv3ud0eleps9kl2d5348hq2k8qzqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgqpqqqqqqqqqqqqqqqqqqqqqqqqqqqzqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqqzq3zyg3zyg3zyg3vggzamrjghtt05kvkvpcp0a79gmy3nt6jsn98ad2xs8de6sl9qmgvcvs", + // ... and with sciddir introduction node + "lno1pgx9getnwss8vetrw3hhyucs3yqqqqqqqqqqqqp2qgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqqyqqqqqqqqqqqqqqqqqqqqqqqqqqqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqqgzyg3zyg3zyg3z93pqthvwfzadd7jejes8q9lhc4rvjxd022zv5l44g6qah82ru5rdpnpj", + // ... and with second blinded path via Carol (0x434343...), blinding 020202... "lno1pgx9getnwss8vetrw3hhyucsl5q5yqeyv5l2cs6y3qqzesrth7mlzrlp3xg7xhulusczm04x6g6nms9trspqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqqsqqqqqqqqqqqqqqqqqqqqqqqqqqpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqsqpqg3zyg3zyg3zygz0uc7h32x9s0aecdhxlk075kn046aafpuuyw8f5j652t3vha2yqrsyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqsqzqqqqqqqqqqqqqqqqqqqqqqqqqqqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqqyzyg3zyg3zyg3zzcss9mk8y3wkklfvevcrszlmu23kfrxh49px20665dqwmn4p72pksese",