Merge pull request #3234 from TheBlueMatt/2024-08-lightning-dep-inv

Swap the dep order between `lightning` and `lightning-invoice`
This commit is contained in:
Matt Corallo 2024-08-14 14:27:39 +00:00 committed by GitHub
commit 398314b720
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
34 changed files with 1874 additions and 1603 deletions

View file

@ -3,6 +3,7 @@ resolver = "2"
members = [
"lightning",
"lightning-types",
"lightning-block-sync",
"lightning-invoice",
"lightning-net-tokio",

View file

@ -56,7 +56,7 @@ use lightning::ln::msgs::{
self, ChannelMessageHandler, CommitmentUpdate, DecodeError, Init, UpdateAddHTLC,
};
use lightning::ln::script::ShutdownScript;
use lightning::ln::{ChannelId, PaymentHash, PaymentPreimage, PaymentSecret};
use lightning::ln::types::{ChannelId, PaymentHash, PaymentPreimage, PaymentSecret};
use lightning::offers::invoice::{BlindedPayInfo, UnsignedBolt12Invoice};
use lightning::offers::invoice_request::UnsignedInvoiceRequest;
use lightning::onion_message::messenger::{Destination, MessageRouter, OnionMessagePath};
@ -71,6 +71,8 @@ use lightning::util::logger::Logger;
use lightning::util::ser::{Readable, ReadableArgs, Writeable, Writer};
use lightning::util::test_channel_signer::{EnforcementState, TestChannelSigner};
use lightning_invoice::RawBolt11Invoice;
use crate::utils::test_logger::{self, Output};
use crate::utils::test_persister::TestPersister;
@ -79,7 +81,6 @@ use bitcoin::secp256k1::ecdsa::{RecoverableSignature, Signature};
use bitcoin::secp256k1::schnorr;
use bitcoin::secp256k1::{self, Message, PublicKey, Scalar, Secp256k1, SecretKey};
use bech32::u5;
use std::cmp::{self, Ordering};
use std::io::Cursor;
use std::mem;
@ -332,7 +333,7 @@ impl NodeSigner for KeyProvider {
}
fn sign_invoice(
&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient,
&self, _invoice: &RawBolt11Invoice, _recipient: Recipient,
) -> Result<RecoverableSignature, ()> {
unreachable!()
}

View file

@ -49,7 +49,7 @@ use lightning::ln::peer_handler::{
IgnoringMessageHandler, MessageHandler, PeerManager, SocketDescriptor,
};
use lightning::ln::script::ShutdownScript;
use lightning::ln::{ChannelId, PaymentHash, PaymentPreimage, PaymentSecret};
use lightning::ln::types::{ChannelId, PaymentHash, PaymentPreimage, PaymentSecret};
use lightning::offers::invoice::{BlindedPayInfo, UnsignedBolt12Invoice};
use lightning::offers::invoice_request::UnsignedInvoiceRequest;
use lightning::onion_message::messenger::{Destination, MessageRouter, OnionMessagePath};
@ -68,6 +68,8 @@ use lightning::util::logger::Logger;
use lightning::util::ser::{Readable, ReadableArgs, Writeable};
use lightning::util::test_channel_signer::{EnforcementState, TestChannelSigner};
use lightning_invoice::RawBolt11Invoice;
use crate::utils::test_logger;
use crate::utils::test_persister::TestPersister;
@ -76,7 +78,6 @@ use bitcoin::secp256k1::ecdsa::{RecoverableSignature, Signature};
use bitcoin::secp256k1::schnorr;
use bitcoin::secp256k1::{self, Message, PublicKey, Scalar, Secp256k1, SecretKey};
use bech32::u5;
use std::cell::RefCell;
use std::cmp;
use std::convert::TryInto;
@ -406,7 +407,7 @@ impl NodeSigner for KeyProvider {
}
fn sign_invoice(
&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient,
&self, _invoice: &RawBolt11Invoice, _recipient: Recipient,
) -> Result<RecoverableSignature, ()> {
unreachable!()
}

View file

@ -1,5 +1,4 @@
// Imports that need to be added manually
use bech32::u5;
use bitcoin::script::ScriptBuf;
use bitcoin::secp256k1::ecdh::SharedSecret;
use bitcoin::secp256k1::ecdsa::RecoverableSignature;
@ -27,6 +26,8 @@ use lightning::util::logger::Logger;
use lightning::util::ser::{Readable, Writeable, Writer};
use lightning::util::test_channel_signer::TestChannelSigner;
use lightning_invoice::RawBolt11Invoice;
use crate::utils::test_logger;
use std::io::{self, Cursor};
@ -225,7 +226,7 @@ impl NodeSigner for KeyProvider {
}
fn sign_invoice(
&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient,
&self, _invoice: &RawBolt11Invoice, _recipient: Recipient,
) -> Result<RecoverableSignature, ()> {
unreachable!()
}

View file

@ -18,7 +18,7 @@ use lightning::ln::channel_state::{ChannelCounterparty, ChannelDetails, ChannelS
use lightning::ln::channelmanager;
use lightning::ln::features::{BlindedHopFeatures, Bolt12InvoiceFeatures};
use lightning::ln::msgs;
use lightning::ln::ChannelId;
use lightning::ln::types::ChannelId;
use lightning::offers::invoice::BlindedPayInfo;
use lightning::routing::gossip::{NetworkGraph, RoutingFees};
use lightning::routing::router::{

View file

@ -16,18 +16,17 @@ rustdoc-args = ["--cfg", "docsrs"]
[features]
default = ["std"]
no-std = ["lightning/no-std"]
std = ["bitcoin/std", "lightning/std", "bech32/std"]
no-std = ["bitcoin/no-std"]
std = ["bitcoin/std", "bech32/std"]
[dependencies]
bech32 = { version = "0.9.1", default-features = false }
lightning = { version = "0.0.123-beta", path = "../lightning", default-features = false }
lightning-types = { version = "0.1", path = "../lightning-types", default-features = false }
secp256k1 = { version = "0.28.0", default-features = false, features = ["recovery", "alloc"] }
serde = { version = "1.0.118", optional = true }
bitcoin = { version = "0.31.2", default-features = false }
[dev-dependencies]
lightning = { version = "0.0.123-beta", path = "../lightning", default-features = false, features = ["_test_utils"] }
serde_json = { version = "1"}
hashbrown = { version = "0.13", default-features = false }

View file

@ -14,9 +14,8 @@ use bitcoin::{PubkeyHash, ScriptHash, WitnessVersion};
use bitcoin::hashes::Hash;
use bitcoin::hashes::sha256;
use crate::prelude::*;
use lightning::ln::types::PaymentSecret;
use lightning::routing::gossip::RoutingFees;
use lightning::routing::router::{RouteHint, RouteHintHop};
use lightning_types::payment::PaymentSecret;
use lightning_types::routing::{RoutingFees, RouteHint, RouteHintHop};
use secp256k1::ecdsa::{RecoveryId, RecoverableSignature};
use secp256k1::PublicKey;
@ -918,8 +917,7 @@ mod test {
#[test]
fn test_parse_route() {
use lightning::routing::gossip::RoutingFees;
use lightning::routing::router::{RouteHint, RouteHintHop};
use lightning_types::routing::{RoutingFees, RouteHint, RouteHintHop};
use crate::PrivateRoute;
use bech32::FromBase32;
@ -974,7 +972,7 @@ mod test {
#[test]
fn test_payment_secret_and_features_de_and_ser() {
use lightning::ln::features::Bolt11InvoiceFeatures;
use lightning_types::features::Bolt11InvoiceFeatures;
use secp256k1::ecdsa::{RecoveryId, RecoverableSignature};
use crate::TaggedField::*;
use crate::{SiPrefix, SignedRawBolt11Invoice, Bolt11InvoiceSignature, RawBolt11Invoice, RawHrp, RawDataPart,

View file

@ -25,11 +25,8 @@
#[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;
extern crate bech32;
#[macro_use] extern crate lightning;
extern crate lightning_types;
extern crate secp256k1;
extern crate alloc;
#[cfg(any(test, feature = "std"))]
@ -40,12 +37,11 @@ extern crate serde;
#[cfg(feature = "std")]
use std::time::SystemTime;
use bech32::u5;
use bech32::{FromBase32, u5};
use bitcoin::{Address, Network, PubkeyHash, ScriptHash, WitnessProgram, WitnessVersion};
use bitcoin::address::Payload;
use bitcoin::hashes::{Hash, sha256};
use lightning::ln::features::Bolt11InvoiceFeatures;
use lightning::util::invoice::construct_invoice_preimage;
use lightning_types::features::Bolt11InvoiceFeatures;
use secp256k1::PublicKey;
use secp256k1::{Message, Secp256k1};
@ -64,12 +60,10 @@ use core::str;
use serde::{Deserialize, Deserializer,Serialize, Serializer, de::Error};
#[doc(no_inline)]
pub use lightning::ln::types::PaymentSecret;
pub use lightning_types::payment::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;
pub use lightning_types::routing::{RoutingFees, RouteHint, RouteHintHop};
use lightning_types::string::UntrustedString;
mod de;
mod ser;
@ -139,11 +133,9 @@ pub const DEFAULT_EXPIRY_TIME: u64 = 3600;
/// Default minimum final CLTV expiry as defined by [BOLT 11].
///
/// Note that this is *not* the same value as rust-lightning's minimum CLTV expiry, which is
/// provided in [`MIN_FINAL_CLTV_EXPIRY_DELTA`].
/// Note that this is *not* the same value as rust-lightning's minimum CLTV expiry.
///
/// [BOLT 11]: https://github.com/lightning/bolts/blob/master/11-payment-encoding.md
/// [`MIN_FINAL_CLTV_EXPIRY_DELTA`]: lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA
pub const DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA: u64 = 18;
/// Builder for [`Bolt11Invoice`]s. It's the most convenient and advised way to use this library. It
@ -151,7 +143,6 @@ pub const DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA: u64 = 18;
///
/// ```
/// extern crate secp256k1;
/// extern crate lightning;
/// extern crate lightning_invoice;
/// extern crate bitcoin;
///
@ -161,7 +152,7 @@ pub const DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA: u64 = 18;
/// use secp256k1::Secp256k1;
/// use secp256k1::SecretKey;
///
/// use lightning::ln::types::PaymentSecret;
/// use lightning_types::payment::PaymentSecret;
///
/// use lightning_invoice::{Currency, InvoiceBuilder};
///
@ -970,7 +961,23 @@ macro_rules! find_all_extract {
impl RawBolt11Invoice {
/// Hash the HRP as bytes and signatureless data part.
fn hash_from_parts(hrp_bytes: &[u8], data_without_signature: &[u5]) -> [u8; 32] {
let preimage = construct_invoice_preimage(hrp_bytes, data_without_signature);
let mut preimage = Vec::<u8>::from(hrp_bytes);
let mut data_part = Vec::from(data_without_signature);
let overhang = (data_part.len() * 5) % 8;
if overhang > 0 {
// add padding if data does not end at a byte boundary
data_part.push(u5::try_from_u8(0).unwrap());
// if overhang is in (1..3) we need to add u5(0) padding two times
if overhang < 3 {
data_part.push(u5::try_from_u8(0).unwrap());
}
}
preimage.extend_from_slice(&Vec::<u8>::from_base32(&data_part)
.expect("No padding error may occur due to appended zero above."));
let mut hash: [u8; 32] = Default::default();
hash.copy_from_slice(&sha256::Hash::hash(&preimage)[..]);
hash
@ -1636,15 +1643,12 @@ pub enum CreationError {
/// The supplied millisatoshi amount was greater than the total bitcoin supply.
InvalidAmount,
/// Route hints were required for this invoice and were missing. Applies to
/// [phantom invoices].
///
/// [phantom invoices]: crate::utils::create_phantom_invoice
// TODO: These two errors are really errors with things in the `lightning` crate and thus
// shouldn't live here.
/// Route hints were required for this invoice and were missing.
MissingRouteHints,
/// The provided `min_final_cltv_expiry_delta` was less than [`MIN_FINAL_CLTV_EXPIRY_DELTA`].
///
/// [`MIN_FINAL_CLTV_EXPIRY_DELTA`]: lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA
/// The provided `min_final_cltv_expiry_delta` was less than rust-lightning's minimum.
MinFinalCltvExpiryDeltaTooShort,
}
@ -1877,14 +1881,14 @@ mod test {
#[test]
fn test_check_feature_bits() {
use crate::TaggedField::*;
use lightning::ln::features::Bolt11InvoiceFeatures;
use lightning_types::features::Bolt11InvoiceFeatures;
use secp256k1::Secp256k1;
use secp256k1::SecretKey;
use crate::{Bolt11Invoice, RawBolt11Invoice, RawHrp, RawDataPart, Currency, Sha256, PositiveTimestamp,
Bolt11SemanticError};
let private_key = SecretKey::from_slice(&[42; 32]).unwrap();
let payment_secret = lightning::ln::types::PaymentSecret([21; 32]);
let payment_secret = lightning_types::payment::PaymentSecret([21; 32]);
let invoice_template = RawBolt11Invoice {
hrp: RawHrp {
currency: Currency::Bitcoin,
@ -1998,7 +2002,7 @@ mod test {
#[test]
fn test_builder_fail() {
use crate::*;
use lightning::routing::router::RouteHintHop;
use lightning_types::routing::RouteHintHop;
use std::iter::FromIterator;
use secp256k1::PublicKey;
@ -2052,7 +2056,7 @@ mod test {
#[test]
fn test_builder_ok() {
use crate::*;
use lightning::routing::router::RouteHintHop;
use lightning_types::routing::RouteHintHop;
use secp256k1::Secp256k1;
use secp256k1::{SecretKey, PublicKey};
use std::time::Duration;

View file

@ -1,5 +1,4 @@
extern crate bech32;
extern crate lightning;
extern crate lightning_invoice;
extern crate secp256k1;

View file

@ -0,0 +1,25 @@
[package]
name = "lightning-types"
version = "0.1.0"
authors = ["Matt Corallo"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/lightningdevkit/rust-lightning/"
description = """
Basic types which are used in the lightning network
"""
edition = "2021"
[package.metadata.docs.rs]
rustdoc-args = ["--cfg", "docsrs"]
[features]
_test_utils = []
[dependencies]
bitcoin = { version = "0.31", default-features = false }
# TODO: Once we switch to bitcoin 0.32 drop this explicit dep:
hex-conservative = { version = "0.2", default-features = false }
bech32 = { version = "0.9", default-features = false }
[lints]
workspace = true

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,29 @@
// This file is Copyright its original authors, visible in version control
// history.
//
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
// You may not use this file except in accordance with one or both of these
// licenses.
#![crate_name = "lightning_types"]
//! Various types which are used in the lightning network.
//!
//! See the `lightning` crate for usage of these.
#![cfg_attr(not(test), no_std)]
#![deny(missing_docs)]
#![forbid(unsafe_code)]
#![deny(rustdoc::broken_intra_doc_links)]
#![deny(rustdoc::private_intra_doc_links)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
extern crate alloc;
extern crate core;
pub mod features;
pub mod payment;
pub mod routing;
pub mod string;

View file

@ -0,0 +1,112 @@
// This file is Copyright its original authors, visible in version control
// history.
//
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
// You may not use this file except in accordance with one or both of these
// licenses.
//! Types which describe payments in lightning.
use alloc::vec::Vec;
use core::borrow::Borrow;
use bitcoin::hashes::{sha256::Hash as Sha256, Hash as _};
// TODO: Once we switch to rust-bitcoin 0.32, import this as bitcoin::hex
use hex_conservative::display::impl_fmt_traits;
/// The payment hash is the hash of the [`PaymentPreimage`] which is the value used to lock funds
/// in HTLCs while they transit the lightning network.
///
/// This is not exported to bindings users as we just use [u8; 32] directly
#[derive(Hash, Copy, Clone, PartialEq, Eq, Ord, PartialOrd)]
pub struct PaymentHash(pub [u8; 32]);
impl Borrow<[u8]> for PaymentHash {
fn borrow(&self) -> &[u8] {
&self.0[..]
}
}
impl_fmt_traits! {
impl fmt_traits for PaymentHash {
const LENGTH: usize = 32;
}
}
/// The payment preimage is the "secret key" which is used to claim the funds of an HTLC on-chain
/// or in a lightning channel.
///
/// This is not exported to bindings users as we just use [u8; 32] directly
#[derive(Hash, Copy, Clone, PartialEq, Eq, Ord, PartialOrd)]
pub struct PaymentPreimage(pub [u8; 32]);
impl Borrow<[u8]> for PaymentPreimage {
fn borrow(&self) -> &[u8] {
&self.0[..]
}
}
impl_fmt_traits! {
impl fmt_traits for PaymentPreimage {
const LENGTH: usize = 32;
}
}
/// Converts a `PaymentPreimage` into a `PaymentHash` by hashing the preimage with SHA256.
impl From<PaymentPreimage> for PaymentHash {
fn from(value: PaymentPreimage) -> Self {
PaymentHash(Sha256::hash(&value.0).to_byte_array())
}
}
/// The payment secret is used to authenticate the sender of an HTLC to the recipient and tie
/// multi-part HTLCs together into a single payment.
///
/// This is not exported to bindings users as we just use [u8; 32] directly
#[derive(Hash, Copy, Clone, PartialEq, Eq, Ord, PartialOrd)]
pub struct PaymentSecret(pub [u8; 32]);
impl Borrow<[u8]> for PaymentSecret {
fn borrow(&self) -> &[u8] {
&self.0[..]
}
}
impl_fmt_traits! {
impl fmt_traits for PaymentSecret {
const LENGTH: usize = 32;
}
}
use bech32::{u5, Base32Len, FromBase32, ToBase32, WriteBase32};
impl FromBase32 for PaymentSecret {
type Err = bech32::Error;
fn from_base32(field_data: &[u5]) -> Result<PaymentSecret, bech32::Error> {
if field_data.len() != 52 {
return Err(bech32::Error::InvalidLength);
} else {
let data_bytes = Vec::<u8>::from_base32(field_data)?;
let mut payment_secret = [0; 32];
payment_secret.copy_from_slice(&data_bytes);
Ok(PaymentSecret(payment_secret))
}
}
}
impl ToBase32 for PaymentSecret {
fn write_base32<W: WriteBase32>(&self, writer: &mut W) -> Result<(), <W as WriteBase32>::Err> {
(&self.0[..]).write_base32(writer)
}
}
impl Base32Len for PaymentSecret {
fn base32_len(&self) -> usize {
52
}
}

View file

@ -0,0 +1,50 @@
// This file is Copyright its original authors, visible in version control
// history.
//
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
// You may not use this file except in accordance with one or both of these
// licenses.
//! Various types which describe routes or information about partial routes within the lightning
//! network.
use alloc::vec::Vec;
use bitcoin::secp256k1::PublicKey;
/// Fees for routing via a given channel or a node
#[derive(Eq, PartialEq, Copy, Clone, Debug, Hash, Ord, PartialOrd)]
pub struct RoutingFees {
/// Flat routing fee in millisatoshis.
pub base_msat: u32,
/// Liquidity-based routing fee in millionths of a routed amount.
/// In other words, 10000 is 1%.
pub proportional_millionths: u32,
}
/// A list of hops along a payment path terminating with a channel to the recipient.
#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub struct RouteHint(pub Vec<RouteHintHop>);
/// A channel descriptor for a hop along a payment path.
///
/// While this generally comes from BOLT 11's `r` field, this struct includes more fields than are
/// available in BOLT 11. Thus, encoding and decoding this via `lightning-invoice` is lossy, as
/// fields not supported in BOLT 11 will be stripped.
#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub struct RouteHintHop {
/// The node_id of the non-target end of the route
pub src_node_id: PublicKey,
/// The short_channel_id of this channel
pub short_channel_id: u64,
/// The fees which must be paid to use this channel
pub fees: RoutingFees,
/// The difference in CLTV values between this node and the next node.
pub cltv_expiry_delta: u16,
/// The minimum value, in msat, which must be relayed to the next hop.
pub htlc_minimum_msat: Option<u64>,
/// The maximum value in msat available for routing with a single HTLC.
pub htlc_maximum_msat: Option<u64>,
}

View file

@ -9,31 +9,13 @@
//! Utilities for strings.
use alloc::string::String;
use core::fmt;
use crate::io::{self, Read};
use crate::ln::msgs;
use crate::util::ser::{Writeable, Writer, Readable};
#[allow(unused_imports)]
use crate::prelude::*;
/// Struct to `Display` fields in a safe way using `PrintableString`
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
pub struct UntrustedString(pub String);
impl Writeable for UntrustedString {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
self.0.write(w)
}
}
impl Readable for UntrustedString {
fn read<R: Read>(r: &mut R) -> Result<Self, msgs::DecodeError> {
let s: String = Readable::read(r)?;
Ok(Self(s))
}
}
impl fmt::Display for UntrustedString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
PrintableString(&self.0).fmt(f)

View file

@ -17,7 +17,7 @@ rustdoc-args = ["--cfg", "docsrs"]
[features]
# Internal test utilities exposed to other repo crates
_test_utils = ["regex", "bitcoin/bitcoinconsensus"]
_test_utils = ["regex", "bitcoin/bitcoinconsensus", "lightning-types/_test_utils"]
# Unlog messages superior at targeted level.
max_level_off = []
max_level_error = []
@ -31,8 +31,8 @@ unsafe_revoked_tx_signing = []
# Override signing to not include randomness when generating signatures for test vectors.
_test_vectors = []
no-std = ["hashbrown", "possiblyrandom", "bitcoin/no-std", "core2/alloc", "libm"]
std = ["bitcoin/std", "bech32/std"]
no-std = ["hashbrown", "possiblyrandom", "bitcoin/no-std", "lightning-invoice/no-std", "core2/alloc", "libm"]
std = ["bitcoin/std", "bech32/std", "lightning-invoice/std"]
# Generates low-r bitcoin signatures, which saves 1 byte in 50% of the cases
grind_signatures = []
@ -40,6 +40,9 @@ grind_signatures = []
default = ["std", "grind_signatures"]
[dependencies]
lightning-types = { version = "0.1", path = "../lightning-types", default-features = false }
lightning-invoice = { version = "0.31.0-beta", path = "../lightning-invoice", default-features = false }
bech32 = { version = "0.9.1", default-features = false }
bitcoin = { version = "0.31.2", default-features = false, features = ["secp-recovery"] }
@ -53,6 +56,7 @@ libm = { version = "0.2", optional = true, default-features = false }
[dev-dependencies]
regex = "1.5.6"
lightning-types = { version = "0.1", path = "../lightning-types", features = ["_test_utils"] }
[dev-dependencies.bitcoin]
version = "0.31.2"

View file

@ -93,7 +93,7 @@ pub(crate) fn verify_channel_type_features(channel_type_features: &Option<Channe
supported_feature_set |= additional_permitted_features;
}
if !features.is_subset(&supported_feature_set) {
if features.requires_unknown_bits_from(&supported_feature_set) {
return Err(DecodeError::UnknownRequiredFeature);
}
}

View file

@ -61,6 +61,9 @@ compile_error!("Tests will always fail with cfg=fuzzing");
#[macro_use]
extern crate alloc;
extern crate lightning_types;
pub extern crate bitcoin;
#[cfg(any(test, feature = "std"))]
extern crate core;

View file

@ -9,12 +9,12 @@
//! Convenient utilities for paying Lightning invoices.
use crate::Bolt11Invoice;
use bitcoin::hashes::Hash;
use lightning_invoice::Bolt11Invoice;
use lightning::ln::types::PaymentHash;
use lightning::ln::channelmanager::RecipientOnionFields;
use lightning::routing::router::{PaymentParameters, RouteParameters};
use crate::ln::channelmanager::RecipientOnionFields;
use crate::ln::types::PaymentHash;
use crate::routing::router::{PaymentParameters, RouteParameters};
/// Builds the necessary parameters to pay or pre-flight probe the given zero-amount
/// [`Bolt11Invoice`] using [`ChannelManager::send_payment`] or
@ -26,10 +26,11 @@ use lightning::routing::router::{PaymentParameters, RouteParameters};
/// Will always succeed unless the invoice has an amount specified, in which case
/// [`payment_parameters_from_invoice`] should be used.
///
/// [`ChannelManager::send_payment`]: lightning::ln::channelmanager::ChannelManager::send_payment
/// [`ChannelManager::send_preflight_probes`]: lightning::ln::channelmanager::ChannelManager::send_preflight_probes
pub fn payment_parameters_from_zero_amount_invoice(invoice: &Bolt11Invoice, amount_msat: u64)
-> Result<(PaymentHash, RecipientOnionFields, RouteParameters), ()> {
/// [`ChannelManager::send_payment`]: crate::ln::channelmanager::ChannelManager::send_payment
/// [`ChannelManager::send_preflight_probes`]: crate::ln::channelmanager::ChannelManager::send_preflight_probes
pub fn payment_parameters_from_zero_amount_invoice(
invoice: &Bolt11Invoice, amount_msat: u64,
) -> Result<(PaymentHash, RecipientOnionFields, RouteParameters), ()> {
if invoice.amount_milli_satoshis().is_some() {
Err(())
} else {
@ -46,10 +47,11 @@ pub fn payment_parameters_from_zero_amount_invoice(invoice: &Bolt11Invoice, amou
/// Will always succeed unless the invoice has no amount specified, in which case
/// [`payment_parameters_from_zero_amount_invoice`] should be used.
///
/// [`ChannelManager::send_payment`]: lightning::ln::channelmanager::ChannelManager::send_payment
/// [`ChannelManager::send_preflight_probes`]: lightning::ln::channelmanager::ChannelManager::send_preflight_probes
pub fn payment_parameters_from_invoice(invoice: &Bolt11Invoice)
-> Result<(PaymentHash, RecipientOnionFields, RouteParameters), ()> {
/// [`ChannelManager::send_payment`]: crate::ln::channelmanager::ChannelManager::send_payment
/// [`ChannelManager::send_preflight_probes`]: crate::ln::channelmanager::ChannelManager::send_preflight_probes
pub fn payment_parameters_from_invoice(
invoice: &Bolt11Invoice,
) -> Result<(PaymentHash, RecipientOnionFields, RouteParameters), ()> {
if let Some(amount_msat) = invoice.amount_milli_satoshis() {
Ok(params_from_invoice(invoice, amount_msat))
} else {
@ -57,18 +59,20 @@ pub fn payment_parameters_from_invoice(invoice: &Bolt11Invoice)
}
}
fn params_from_invoice(invoice: &Bolt11Invoice, amount_msat: u64)
-> (PaymentHash, RecipientOnionFields, RouteParameters) {
fn params_from_invoice(
invoice: &Bolt11Invoice, amount_msat: u64,
) -> (PaymentHash, RecipientOnionFields, RouteParameters) {
let payment_hash = PaymentHash((*invoice.payment_hash()).to_byte_array());
let mut recipient_onion = RecipientOnionFields::secret_only(*invoice.payment_secret());
recipient_onion.payment_metadata = invoice.payment_metadata().map(|v| v.clone());
let mut payment_params = PaymentParameters::from_node_id(
invoice.recover_payee_pub_key(),
invoice.min_final_cltv_expiry_delta() as u32
)
.with_route_hints(invoice.route_hints()).unwrap();
invoice.recover_payee_pub_key(),
invoice.min_final_cltv_expiry_delta() as u32,
)
.with_route_hints(invoice.route_hints())
.unwrap();
if let Some(expiry) = invoice.expires_at() {
payment_params = payment_params.with_expiry_time(expiry.as_secs());
}
@ -83,19 +87,18 @@ fn params_from_invoice(invoice: &Bolt11Invoice, amount_msat: u64)
#[cfg(test)]
mod tests {
use super::*;
use crate::{InvoiceBuilder, Currency};
use crate::ln::types::PaymentSecret;
use crate::routing::router::Payee;
use bitcoin::hashes::sha256::Hash as Sha256;
use lightning::ln::types::PaymentSecret;
use lightning::routing::router::Payee;
use secp256k1::{SecretKey, PublicKey, Secp256k1};
use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
use core::time::Duration;
use lightning_invoice::{Currency, InvoiceBuilder};
#[cfg(feature = "std")]
use std::time::SystemTime;
fn duration_since_epoch() -> Duration {
#[cfg(feature = "std")]
let duration_since_epoch =
SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
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
@ -115,9 +118,7 @@ mod tests {
.duration_since_epoch(duration_since_epoch())
.min_final_cltv_expiry_delta(144)
.amount_milli_satoshis(128)
.build_signed(|hash| {
secp_ctx.sign_ecdsa_recoverable(hash, &private_key)
})
.build_signed(|hash| secp_ctx.sign_ecdsa_recoverable(hash, &private_key))
.unwrap();
assert!(payment_parameters_from_zero_amount_invoice(&invoice, 42).is_err());
@ -147,14 +148,13 @@ mod tests {
.payment_secret(PaymentSecret([0; 32]))
.duration_since_epoch(duration_since_epoch())
.min_final_cltv_expiry_delta(144)
.build_signed(|hash| {
secp_ctx.sign_ecdsa_recoverable(hash, &private_key)
})
.unwrap();
.build_signed(|hash| secp_ctx.sign_ecdsa_recoverable(hash, &private_key))
.unwrap();
assert!(payment_parameters_from_invoice(&invoice).is_err());
let (hash, onion, params) = payment_parameters_from_zero_amount_invoice(&invoice, 42).unwrap();
let (hash, onion, params) =
payment_parameters_from_zero_amount_invoice(&invoice, 42).unwrap();
assert_eq!(&hash.0[..], &payment_hash[..]);
assert_eq!(onion.payment_secret, Some(PaymentSecret([0; 32])));
assert_eq!(params.final_value_msat, 42);
@ -169,10 +169,10 @@ mod tests {
#[test]
#[cfg(feature = "std")]
fn payment_metadata_end_to_end() {
use lightning::events::Event;
use lightning::ln::channelmanager::{Retry, PaymentId};
use lightning::ln::msgs::ChannelMessageHandler;
use lightning::ln::functional_test_utils::*;
use crate::events::Event;
use crate::ln::channelmanager::{PaymentId, Retry};
use crate::ln::functional_test_utils::*;
use crate::ln::msgs::ChannelMessageHandler;
// Test that a payment metadata read from an invoice passed to `pay_invoice` makes it all
// the way out through the `PaymentClaimable` event.
let chanmon_cfgs = create_chanmon_cfgs(2);
@ -186,6 +186,8 @@ mod tests {
let (payment_hash, payment_secret) =
nodes[1].node.create_inbound_payment(None, 7200, None).unwrap();
let secp_ctx = Secp256k1::new();
let node_secret = nodes[1].keys_manager.backing.get_node_secret_key();
let invoice = InvoiceBuilder::new(Currency::Bitcoin)
.description("test".into())
.payment_hash(Sha256::from_slice(&payment_hash.0).unwrap())
@ -194,14 +196,14 @@ mod tests {
.min_final_cltv_expiry_delta(144)
.amount_milli_satoshis(50_000)
.payment_metadata(payment_metadata.clone())
.build_signed(|hash| {
Secp256k1::new().sign_ecdsa_recoverable(hash,
&nodes[1].keys_manager.backing.get_node_secret_key())
})
.build_signed(|hash| secp_ctx.sign_ecdsa_recoverable(hash, &node_secret))
.unwrap();
let (hash, onion, params) = payment_parameters_from_invoice(&invoice).unwrap();
nodes[0].node.send_payment(hash, onion, PaymentId(hash.0), params, Retry::Attempts(0)).unwrap();
nodes[0]
.node
.send_payment(hash, onion, PaymentId(hash.0), params, Retry::Attempts(0))
.unwrap();
check_added_monitors(&nodes[0], 1);
let send_event = SendEvent::from_node(&nodes[0]);
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &send_event.msgs[0]);
@ -215,7 +217,7 @@ mod tests {
Event::PaymentClaimable { onion_fields, .. } => {
assert_eq!(Some(payment_metadata), onion_fields.unwrap().payment_metadata);
},
_ => panic!("Unexpected event")
_ => panic!("Unexpected event"),
}
}
}

View file

@ -772,10 +772,12 @@ pub(crate) fn legacy_deserialization_prevention_marker_for_channel_type_features
legacy_version_bit_set.set_scid_privacy_required();
legacy_version_bit_set.set_zero_conf_required();
if features.is_subset(&legacy_version_bit_set) {
None
} else {
debug_assert!(!legacy_version_bit_set.supports_any_optional_bits());
debug_assert!(!features.supports_any_optional_bits());
if features.requires_unknown_bits_from(&legacy_version_bit_set) {
Some(())
} else {
None
}
}

View file

@ -1877,7 +1877,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
}
let channel_type = get_initial_channel_type(&config, their_features);
debug_assert!(channel_type.is_subset(&channelmanager::provided_channel_type_features(&config)));
debug_assert!(!channel_type.supports_any_optional_bits());
debug_assert!(!channel_type.requires_unknown_bits_from(&channelmanager::provided_channel_type_features(&config)));
let (commitment_conf_target, anchor_outputs_value_msat) = if channel_type.supports_anchors_zero_fee_htlc_tx() {
(ConfirmationTarget::AnchorChannelFee, ANCHOR_OUTPUT_VALUE_SATOSHI * 2 * 1000)
@ -7967,7 +7968,7 @@ pub(super) fn channel_type_from_open_channel(
return Err(ChannelError::close("Channel Type was not understood - we require static remote key".to_owned()));
}
// Make sure we support all of the features behind the channel type.
if !channel_type.is_subset(our_supported_features) {
if channel_type.requires_unknown_bits_from(&our_supported_features) {
return Err(ChannelError::close("Channel Type contains unsupported features".to_owned()));
}
let announced_channel = if (common_fields.channel_flags & 1) == 1 { true } else { false };
@ -9355,7 +9356,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
}
let chan_features = channel_type.as_ref().unwrap();
if !chan_features.is_subset(our_supported_features) {
if chan_features.supports_any_optional_bits() || chan_features.requires_unknown_bits_from(&our_supported_features) {
// If the channel was written by a new version and negotiated with features we don't
// understand yet, refuse to read it.
return Err(DecodeError::UnknownRequiredFeature);

File diff suppressed because it is too large Load diff

View file

@ -1,22 +1,23 @@
//! Convenient utilities to create an invoice.
use crate::{Bolt11Invoice, CreationError, Currency, InvoiceBuilder, SignOrCreationError};
use lightning_invoice::{Bolt11Invoice, CreationError, Currency, InvoiceBuilder, SignOrCreationError};
use lightning_invoice::{Description, Bolt11InvoiceDescription, Sha256};
use crate::prelude::*;
use crate::{prelude::*, Description, Bolt11InvoiceDescription, Sha256};
use bech32::ToBase32;
use bitcoin::hashes::Hash;
use lightning::chain;
use lightning::chain::chaininterface::{BroadcasterInterface, FeeEstimator};
use lightning::sign::{Recipient, NodeSigner, SignerProvider, EntropySource};
use lightning::ln::types::{PaymentHash, PaymentSecret};
use lightning::ln::channel_state::ChannelDetails;
use lightning::ln::channelmanager::{ChannelManager, MIN_FINAL_CLTV_EXPIRY_DELTA};
use lightning::ln::channelmanager::{PhantomRouteHints, MIN_CLTV_EXPIRY_DELTA};
use lightning::ln::inbound_payment::{create, create_from_hash, ExpandedKey};
use lightning::routing::gossip::RoutingFees;
use lightning::routing::router::{RouteHint, RouteHintHop, Router};
use lightning::util::logger::{Logger, Record};
use secp256k1::PublicKey;
use crate::chain;
use crate::chain::chaininterface::{BroadcasterInterface, FeeEstimator};
use crate::sign::{Recipient, NodeSigner, SignerProvider, EntropySource};
use crate::ln::types::{PaymentHash, PaymentSecret};
use crate::ln::channel_state::ChannelDetails;
use crate::ln::channelmanager::{ChannelManager, MIN_FINAL_CLTV_EXPIRY_DELTA};
use crate::ln::channelmanager::{PhantomRouteHints, MIN_CLTV_EXPIRY_DELTA};
use crate::ln::inbound_payment::{create, create_from_hash, ExpandedKey};
use crate::routing::gossip::RoutingFees;
use crate::routing::router::{RouteHint, RouteHintHop, Router};
use crate::util::logger::{Logger, Record};
use bitcoin::secp256k1::PublicKey;
use alloc::collections::{btree_map, BTreeMap};
use core::ops::Deref;
use core::time::Duration;
@ -54,12 +55,12 @@ use core::iter::Iterator;
/// invoices in its `sign_invoice` implementation ([`PhantomKeysManager`] satisfies this
/// requirement).
///
/// [`PhantomKeysManager`]: lightning::sign::PhantomKeysManager
/// [`ChannelManager::get_phantom_route_hints`]: lightning::ln::channelmanager::ChannelManager::get_phantom_route_hints
/// [`ChannelManager::create_inbound_payment`]: lightning::ln::channelmanager::ChannelManager::create_inbound_payment
/// [`ChannelManager::create_inbound_payment_for_hash`]: lightning::ln::channelmanager::ChannelManager::create_inbound_payment_for_hash
/// [`PhantomRouteHints::channels`]: lightning::ln::channelmanager::PhantomRouteHints::channels
/// [`MIN_FINAL_CLTV_EXPIRY_DETLA`]: lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA
/// [`PhantomKeysManager`]: crate::sign::PhantomKeysManager
/// [`ChannelManager::get_phantom_route_hints`]: crate::ln::channelmanager::ChannelManager::get_phantom_route_hints
/// [`ChannelManager::create_inbound_payment`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment
/// [`ChannelManager::create_inbound_payment_for_hash`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment_for_hash
/// [`PhantomRouteHints::channels`]: crate::ln::channelmanager::PhantomRouteHints::channels
/// [`MIN_FINAL_CLTV_EXPIRY_DETLA`]: crate::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA
///
/// This can be used in a `no_std` environment, where [`std::time::SystemTime`] is not
/// available and the current time is supplied by the caller.
@ -111,11 +112,11 @@ where
/// invoices in its `sign_invoice` implementation ([`PhantomKeysManager`] satisfies this
/// requirement).
///
/// [`PhantomKeysManager`]: lightning::sign::PhantomKeysManager
/// [`ChannelManager::get_phantom_route_hints`]: lightning::ln::channelmanager::ChannelManager::get_phantom_route_hints
/// [`ChannelManager::create_inbound_payment`]: lightning::ln::channelmanager::ChannelManager::create_inbound_payment
/// [`ChannelManager::create_inbound_payment_for_hash`]: lightning::ln::channelmanager::ChannelManager::create_inbound_payment_for_hash
/// [`PhantomRouteHints::channels`]: lightning::ln::channelmanager::PhantomRouteHints::channels
/// [`PhantomKeysManager`]: crate::sign::PhantomKeysManager
/// [`ChannelManager::get_phantom_route_hints`]: crate::ln::channelmanager::ChannelManager::get_phantom_route_hints
/// [`ChannelManager::create_inbound_payment`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment
/// [`ChannelManager::create_inbound_payment_for_hash`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment_for_hash
/// [`PhantomRouteHints::channels`]: crate::ln::channelmanager::PhantomRouteHints::channels
///
/// This can be used in a `no_std` environment, where [`std::time::SystemTime`] is not
/// available and the current time is supplied by the caller.
@ -161,7 +162,7 @@ where
let invoice = match description {
Bolt11InvoiceDescription::Direct(description) => {
InvoiceBuilder::new(network).description(description.0.0.clone())
InvoiceBuilder::new(network).description(description.as_inner().0.clone())
}
Bolt11InvoiceDescription::Hash(hash) => InvoiceBuilder::new(network).description_hash(hash.0),
};
@ -217,10 +218,8 @@ where
Ok(inv) => inv,
Err(e) => return Err(SignOrCreationError::CreationError(e))
};
let hrp_str = raw_invoice.hrp.to_string();
let hrp_bytes = hrp_str.as_bytes();
let data_without_signature = raw_invoice.data.to_base32();
let signed_raw_invoice = raw_invoice.sign(|_| node_signer.sign_invoice(hrp_bytes, &data_without_signature, Recipient::PhantomNode));
let signature = node_signer.sign_invoice(&raw_invoice, Recipient::PhantomNode);
let signed_raw_invoice = raw_invoice.sign(|_| signature);
match signed_raw_invoice {
Ok(inv) => Ok(Bolt11Invoice::from_signed(inv).unwrap()),
Err(e) => Err(SignOrCreationError::SignError(e))
@ -234,7 +233,7 @@ where
/// * Select up to three channels per node.
/// * Select one hint from each node, up to three hints or until we run out of hints.
///
/// [`PhantomKeysManager`]: lightning::sign::PhantomKeysManager
/// [`PhantomKeysManager`]: crate::sign::PhantomKeysManager
fn select_phantom_hints<L: Deref>(amt_msat: Option<u64>, phantom_route_hints: Vec<PhantomRouteHints>,
logger: L) -> impl Iterator<Item = RouteHint>
where
@ -331,7 +330,7 @@ fn rotate_through_iterators<T, I: Iterator<Item = T>>(mut vecs: Vec<I>) -> impl
/// Note that LDK will add a buffer of 3 blocks to the delta to allow for up to a few new block
/// confirmations during routing.
///
/// [`MIN_FINAL_CLTV_EXPIRY_DETLA`]: lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA
/// [`MIN_FINAL_CLTV_EXPIRY_DETLA`]: crate::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA
pub fn create_invoice_from_channelmanager<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref>(
channelmanager: &ChannelManager<M, T, ES, NS, SP, F, R, L>, node_signer: NS, logger: L,
network: Currency, amt_msat: Option<u64>, description: String, invoice_expiry_delta_secs: u32,
@ -372,7 +371,7 @@ where
/// Note that LDK will add a buffer of 3 blocks to the delta to allow for up to a few new block
/// confirmations during routing.
///
/// [`MIN_FINAL_CLTV_EXPIRY_DETLA`]: lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA
/// [`MIN_FINAL_CLTV_EXPIRY_DETLA`]: crate::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA
pub fn create_invoice_from_channelmanager_with_description_hash<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref>(
channelmanager: &ChannelManager<M, T, ES, NS, SP, F, R, L>, node_signer: NS, logger: L,
network: Currency, amt_msat: Option<u64>, description_hash: Sha256,
@ -541,7 +540,7 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_has
let invoice = match description {
Bolt11InvoiceDescription::Direct(description) => {
InvoiceBuilder::new(network).description(description.0.0.clone())
InvoiceBuilder::new(network).description(description.as_inner().0.clone())
}
Bolt11InvoiceDescription::Hash(hash) => InvoiceBuilder::new(network).description_hash(hash.0),
};
@ -569,10 +568,8 @@ fn _create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_has
Ok(inv) => inv,
Err(e) => return Err(SignOrCreationError::CreationError(e))
};
let hrp_str = raw_invoice.hrp.to_string();
let hrp_bytes = hrp_str.as_bytes();
let data_without_signature = raw_invoice.data.to_base32();
let signed_raw_invoice = raw_invoice.sign(|_| node_signer.sign_invoice(hrp_bytes, &data_without_signature, Recipient::Node));
let signature = node_signer.sign_invoice(&raw_invoice, Recipient::Node);
let signed_raw_invoice = raw_invoice.sign(|_| signature);
match signed_raw_invoice {
Ok(inv) => Ok(Bolt11Invoice::from_signed(inv).unwrap()),
Err(e) => Err(SignOrCreationError::SignError(e))
@ -819,50 +816,49 @@ impl<'a, 'b, L: Deref> WithChannelDetails<'a, 'b, L> where L::Target: Logger {
#[cfg(test)]
mod test {
use super::*;
use core::time::Duration;
use crate::{Currency, Description, Bolt11InvoiceDescription, SignOrCreationError, CreationError};
use lightning_invoice::{Currency, Description, Bolt11InvoiceDescription, SignOrCreationError, CreationError};
use bitcoin::hashes::{Hash, sha256};
use bitcoin::hashes::sha256::Hash as Sha256;
use lightning::sign::PhantomKeysManager;
use lightning::events::{MessageSendEvent, MessageSendEventsProvider};
use lightning::ln::types::PaymentHash;
use crate::sign::PhantomKeysManager;
use crate::events::{MessageSendEvent, MessageSendEventsProvider};
use crate::ln::types::PaymentHash;
#[cfg(feature = "std")]
use lightning::ln::types::PaymentPreimage;
use lightning::ln::channelmanager::{PhantomRouteHints, MIN_FINAL_CLTV_EXPIRY_DELTA, PaymentId, RecipientOnionFields, Retry};
use lightning::ln::functional_test_utils::*;
use lightning::ln::msgs::ChannelMessageHandler;
use lightning::routing::router::{PaymentParameters, RouteParameters};
use lightning::util::test_utils;
use lightning::util::config::UserConfig;
use crate::utils::{create_invoice_from_channelmanager_and_duration_since_epoch, rotate_through_iterators};
use crate::ln::types::PaymentPreimage;
use crate::ln::channelmanager::{PhantomRouteHints, MIN_FINAL_CLTV_EXPIRY_DELTA, PaymentId, RecipientOnionFields, Retry};
use crate::ln::functional_test_utils::*;
use crate::ln::msgs::ChannelMessageHandler;
use crate::routing::router::{PaymentParameters, RouteParameters};
use crate::util::test_utils;
use crate::util::config::UserConfig;
use std::collections::HashSet;
use lightning::util::string::UntrustedString;
#[test]
fn test_prefer_current_channel() {
// No minimum, prefer larger candidate channel.
assert_eq!(crate::utils::prefer_current_channel(None, 100, 200), false);
assert_eq!(prefer_current_channel(None, 100, 200), false);
// No minimum, prefer larger current channel.
assert_eq!(crate::utils::prefer_current_channel(None, 200, 100), true);
assert_eq!(prefer_current_channel(None, 200, 100), true);
// Minimum set, prefer current channel over minimum + buffer.
assert_eq!(crate::utils::prefer_current_channel(Some(100), 115, 100), true);
assert_eq!(prefer_current_channel(Some(100), 115, 100), true);
// Minimum set, prefer candidate channel over minimum + buffer.
assert_eq!(crate::utils::prefer_current_channel(Some(100), 105, 125), false);
assert_eq!(prefer_current_channel(Some(100), 105, 125), false);
// Minimum set, both channels sufficient, prefer smaller current channel.
assert_eq!(crate::utils::prefer_current_channel(Some(100), 115, 125), true);
assert_eq!(prefer_current_channel(Some(100), 115, 125), true);
// Minimum set, both channels sufficient, prefer smaller candidate channel.
assert_eq!(crate::utils::prefer_current_channel(Some(100), 200, 160), false);
assert_eq!(prefer_current_channel(Some(100), 200, 160), false);
// Minimum set, neither sufficient, prefer larger current channel.
assert_eq!(crate::utils::prefer_current_channel(Some(200), 100, 50), true);
assert_eq!(prefer_current_channel(Some(200), 100, 50), true);
// Minimum set, neither sufficient, prefer larger candidate channel.
assert_eq!(crate::utils::prefer_current_channel(Some(200), 100, 150), false);
assert_eq!(prefer_current_channel(Some(200), 100, 150), false);
}
@ -878,10 +874,10 @@ mod test {
nodes[1].node, nodes[1].keys_manager, nodes[1].logger, Currency::BitcoinTestnet,
Some(10_000), "test".to_string(), Duration::from_secs(1234567),
non_default_invoice_expiry_secs, None).unwrap();
assert_eq!(invoice.amount_pico_btc(), Some(100_000));
assert_eq!(invoice.amount_milli_satoshis(), Some(10_000));
// If no `min_final_cltv_expiry_delta` is specified, then it should be `MIN_FINAL_CLTV_EXPIRY_DELTA`.
assert_eq!(invoice.min_final_cltv_expiry_delta(), MIN_FINAL_CLTV_EXPIRY_DELTA as u64);
assert_eq!(invoice.description(), Bolt11InvoiceDescription::Direct(&Description(UntrustedString("test".to_string()))));
assert_eq!(invoice.description(), Bolt11InvoiceDescription::Direct(&Description::new("test".to_string()).unwrap()));
assert_eq!(invoice.expiry_time(), Duration::from_secs(non_default_invoice_expiry_secs.into()));
// Invoice SCIDs should always use inbound SCID aliases over the real channel ID, if one is
@ -905,20 +901,15 @@ mod test {
nodes[0].node.send_payment(payment_hash,
RecipientOnionFields::secret_only(*invoice.payment_secret()),
PaymentId(payment_hash.0), route_params, Retry::Attempts(0)).unwrap();
let mut added_monitors = nodes[0].chain_monitor.added_monitors.lock().unwrap();
assert_eq!(added_monitors.len(), 1);
added_monitors.clear();
check_added_monitors(&nodes[0], 1);
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 1);
SendEvent::from_event(events.remove(0))
};
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
nodes[1].node.handle_commitment_signed(&nodes[0].node.get_our_node_id(), &payment_event.commitment_msg);
let mut added_monitors = nodes[1].chain_monitor.added_monitors.lock().unwrap();
assert_eq!(added_monitors.len(), 1);
added_monitors.clear();
check_added_monitors(&nodes[1], 1);
let events = nodes[1].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 2);
}
@ -930,7 +921,7 @@ mod test {
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
let custom_min_final_cltv_expiry_delta = Some(50);
let invoice = crate::utils::create_invoice_from_channelmanager_and_duration_since_epoch(
let invoice = create_invoice_from_channelmanager_and_duration_since_epoch(
nodes[1].node, nodes[1].keys_manager, nodes[1].logger, Currency::BitcoinTestnet,
Some(10_000), "".into(), Duration::from_secs(1234567), 3600,
if with_custom_delta { custom_min_final_cltv_expiry_delta } else { None },
@ -953,7 +944,7 @@ mod test {
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
let custom_min_final_cltv_expiry_delta = Some(21);
let invoice = crate::utils::create_invoice_from_channelmanager_and_duration_since_epoch(
let invoice = create_invoice_from_channelmanager_and_duration_since_epoch(
nodes[1].node, nodes[1].keys_manager, nodes[1].logger, Currency::BitcoinTestnet,
Some(10_000), "".into(), Duration::from_secs(1234567), 3600,
custom_min_final_cltv_expiry_delta,
@ -967,14 +958,14 @@ mod test {
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
let description_hash = crate::Sha256(Hash::hash("Testing description_hash".as_bytes()));
let invoice = crate::utils::create_invoice_from_channelmanager_with_description_hash_and_duration_since_epoch(
let description_hash = Sha256(Hash::hash("Testing description_hash".as_bytes()));
let invoice = create_invoice_from_channelmanager_with_description_hash_and_duration_since_epoch(
nodes[1].node, nodes[1].keys_manager, nodes[1].logger, Currency::BitcoinTestnet,
Some(10_000), description_hash, Duration::from_secs(1234567), 3600, None,
).unwrap();
assert_eq!(invoice.amount_pico_btc(), Some(100_000));
assert_eq!(invoice.amount_milli_satoshis(), Some(10_000));
assert_eq!(invoice.min_final_cltv_expiry_delta(), MIN_FINAL_CLTV_EXPIRY_DELTA as u64);
assert_eq!(invoice.description(), Bolt11InvoiceDescription::Hash(&crate::Sha256(Sha256::hash("Testing description_hash".as_bytes()))));
assert_eq!(invoice.description(), Bolt11InvoiceDescription::Hash(&Sha256(Sha256::hash("Testing description_hash".as_bytes()))));
}
#[test]
@ -984,14 +975,14 @@ mod test {
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
let payment_hash = PaymentHash([0; 32]);
let invoice = crate::utils::create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash(
let invoice = create_invoice_from_channelmanager_and_duration_since_epoch_with_payment_hash(
nodes[1].node, nodes[1].keys_manager, nodes[1].logger, Currency::BitcoinTestnet,
Some(10_000), "test".to_string(), Duration::from_secs(1234567), 3600,
payment_hash, None,
).unwrap();
assert_eq!(invoice.amount_pico_btc(), Some(100_000));
assert_eq!(invoice.amount_milli_satoshis(), Some(10_000));
assert_eq!(invoice.min_final_cltv_expiry_delta(), MIN_FINAL_CLTV_EXPIRY_DELTA as u64);
assert_eq!(invoice.description(), Bolt11InvoiceDescription::Direct(&Description(UntrustedString("test".to_string()))));
assert_eq!(invoice.description(), Bolt11InvoiceDescription::Direct(&Description::new("test".to_string()).unwrap()));
assert_eq!(invoice.payment_hash(), &sha256::Hash::from_slice(&payment_hash.0[..]).unwrap());
}
@ -1283,7 +1274,7 @@ mod test {
let hints = invoice.private_routes();
for hint in hints {
let hint_short_chan_id = (hint.0).0[0].short_channel_id;
let hint_short_chan_id = hint.0[0].short_channel_id;
assert!(chan_ids_to_match.remove(&hint_short_chan_id));
}
assert!(chan_ids_to_match.is_empty(), "Unmatched short channel ids: {:?}", chan_ids_to_match);
@ -1298,7 +1289,7 @@ mod test {
#[cfg(feature = "std")]
fn do_test_multi_node_receive(user_generated_pmt_hash: bool) {
use lightning::events::{Event, EventsProvider};
use crate::events::{Event, EventsProvider};
use core::cell::RefCell;
let mut chanmon_cfgs = create_chanmon_cfgs(3);
@ -1333,7 +1324,7 @@ mod test {
let non_default_invoice_expiry_secs = 4200;
let invoice =
crate::utils::create_phantom_invoice::<&test_utils::TestKeysInterface, &test_utils::TestKeysInterface, &test_utils::TestLogger>(
create_phantom_invoice::<&test_utils::TestKeysInterface, &test_utils::TestKeysInterface, &test_utils::TestLogger>(
Some(payment_amt), payment_hash, "test".to_string(), non_default_invoice_expiry_secs,
route_hints, nodes[1].keys_manager, nodes[1].keys_manager, nodes[1].logger,
Currency::BitcoinTestnet, None, Duration::from_secs(genesis_timestamp)
@ -1346,7 +1337,7 @@ mod test {
};
assert_eq!(invoice.min_final_cltv_expiry_delta(), MIN_FINAL_CLTV_EXPIRY_DELTA as u64);
assert_eq!(invoice.description(), Bolt11InvoiceDescription::Direct(&Description(UntrustedString("test".to_string()))));
assert_eq!(invoice.description(), Bolt11InvoiceDescription::Direct(&Description::new("test".to_string()).unwrap()));
assert_eq!(invoice.route_hints().len(), 2);
assert_eq!(invoice.expiry_time(), Duration::from_secs(non_default_invoice_expiry_secs.into()));
assert!(!invoice.features().unwrap().supports_basic_mpp());
@ -1362,9 +1353,7 @@ mod test {
nodes[0].node.send_payment(payment_hash,
RecipientOnionFields::secret_only(*invoice.payment_secret()),
PaymentId(payment_hash.0), params, Retry::Attempts(0)).unwrap();
let mut added_monitors = nodes[0].chain_monitor.added_monitors.lock().unwrap();
assert_eq!(added_monitors.len(), 1);
added_monitors.clear();
check_added_monitors(&nodes[0], 1);
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 1);
@ -1428,7 +1417,7 @@ mod test {
nodes[2].node.get_phantom_route_hints(),
];
let invoice = crate::utils::create_phantom_invoice::<&test_utils::TestKeysInterface,
let invoice = create_phantom_invoice::<&test_utils::TestKeysInterface,
&test_utils::TestKeysInterface, &test_utils::TestLogger>(Some(payment_amt), Some(payment_hash),
"test".to_string(), 3600, route_hints, nodes[1].keys_manager, nodes[1].keys_manager,
nodes[1].logger, Currency::BitcoinTestnet, None, Duration::from_secs(1234567)).unwrap();
@ -1444,7 +1433,7 @@ mod test {
#[test]
#[cfg(feature = "std")]
fn create_phantom_invoice_with_description_hash() {
fn test_create_phantom_invoice_with_description_hash() {
let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
@ -1456,9 +1445,9 @@ mod test {
nodes[2].node.get_phantom_route_hints(),
];
let description_hash = crate::Sha256(Hash::hash("Description hash phantom invoice".as_bytes()));
let description_hash = Sha256(Hash::hash("Description hash phantom invoice".as_bytes()));
let non_default_invoice_expiry_secs = 4200;
let invoice = crate::utils::create_phantom_invoice_with_description_hash::<
let invoice = create_phantom_invoice_with_description_hash::<
&test_utils::TestKeysInterface, &test_utils::TestKeysInterface, &test_utils::TestLogger,
>(
Some(payment_amt), None, non_default_invoice_expiry_secs, description_hash,
@ -1466,10 +1455,10 @@ mod test {
Currency::BitcoinTestnet, None, Duration::from_secs(1234567),
)
.unwrap();
assert_eq!(invoice.amount_pico_btc(), Some(200_000));
assert_eq!(invoice.amount_milli_satoshis(), Some(20_000));
assert_eq!(invoice.min_final_cltv_expiry_delta(), MIN_FINAL_CLTV_EXPIRY_DELTA as u64);
assert_eq!(invoice.expiry_time(), Duration::from_secs(non_default_invoice_expiry_secs.into()));
assert_eq!(invoice.description(), Bolt11InvoiceDescription::Hash(&crate::Sha256(Sha256::hash("Description hash phantom invoice".as_bytes()))));
assert_eq!(invoice.description(), Bolt11InvoiceDescription::Hash(&Sha256(Sha256::hash("Description hash phantom invoice".as_bytes()))));
}
#[test]
@ -1490,11 +1479,11 @@ mod test {
let non_default_invoice_expiry_secs = 4200;
let min_final_cltv_expiry_delta = Some(100);
let duration_since_epoch = Duration::from_secs(1234567);
let invoice = crate::utils::create_phantom_invoice::<&test_utils::TestKeysInterface,
let invoice = create_phantom_invoice::<&test_utils::TestKeysInterface,
&test_utils::TestKeysInterface, &test_utils::TestLogger>(Some(payment_amt), payment_hash,
"".to_string(), non_default_invoice_expiry_secs, route_hints, nodes[1].keys_manager, nodes[1].keys_manager,
nodes[1].logger, Currency::BitcoinTestnet, min_final_cltv_expiry_delta, duration_since_epoch).unwrap();
assert_eq!(invoice.amount_pico_btc(), Some(200_000));
assert_eq!(invoice.amount_milli_satoshis(), Some(20_000));
assert_eq!(invoice.min_final_cltv_expiry_delta(), (min_final_cltv_expiry_delta.unwrap() + 3) as u64);
assert_eq!(invoice.expiry_time(), Duration::from_secs(non_default_invoice_expiry_secs.into()));
}
@ -1895,7 +1884,7 @@ mod test {
.map(|route_hint| route_hint.phantom_scid)
.collect::<HashSet<u64>>();
let invoice = crate::utils::create_phantom_invoice::<&test_utils::TestKeysInterface,
let invoice = create_phantom_invoice::<&test_utils::TestKeysInterface,
&test_utils::TestKeysInterface, &test_utils::TestLogger>(invoice_amt, None, "test".to_string(),
3600, phantom_route_hints, invoice_node.keys_manager, invoice_node.keys_manager,
invoice_node.logger, Currency::BitcoinTestnet, None, Duration::from_secs(1234567)).unwrap();
@ -1903,7 +1892,7 @@ mod test {
let invoice_hints = invoice.private_routes();
for hint in invoice_hints {
let hints = &(hint.0).0;
let hints = &hint.0;
match hints.len() {
1 => {
assert!(nodes_contains_public_channels);
@ -1928,7 +1917,7 @@ mod test {
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
let result = crate::utils::create_invoice_from_channelmanager_and_duration_since_epoch(
let result = create_invoice_from_channelmanager_and_duration_since_epoch(
nodes[1].node, nodes[1].keys_manager, nodes[1].logger, Currency::BitcoinTestnet,
Some(10_000), "Some description".into(), Duration::from_secs(1234567), 3600, Some(MIN_FINAL_CLTV_EXPIRY_DELTA - 4),
);

View file

@ -25,7 +25,12 @@ pub mod features;
pub mod script;
pub mod types;
pub use types::{ChannelId, PaymentHash, PaymentPreimage, PaymentSecret};
// TODO: These modules were moved from lightning-invoice and need to be better integrated into this
// crate now:
pub mod invoice_utils;
pub mod bolt11_payment;
pub use lightning_types::payment::{PaymentHash, PaymentPreimage, PaymentSecret};
#[cfg(fuzzing)]
pub mod peer_channel_encryptor;

View file

@ -2320,11 +2320,26 @@ impl_writeable_msg!(ChannelReady, {
(1, short_channel_id_alias, option),
});
pub(crate) fn write_features_up_to_13<W: Writer>(w: &mut W, le_flags: &[u8]) -> Result<(), io::Error> {
let len = core::cmp::min(2, le_flags.len());
(len as u16).write(w)?;
for i in (0..len).rev() {
if i == 0 {
le_flags[i].write(w)?;
} else {
// On byte 1, we want up-to-and-including-bit-13, 0-indexed, which is
// up-to-and-including-bit-5, 0-indexed, on this byte:
(le_flags[i] & 0b00_11_11_11).write(w)?;
}
}
Ok(())
}
impl Writeable for Init {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
// global_features gets the bottom 13 bits of our features, and local_features gets all of
// our relevant feature bits. This keeps us compatible with old nodes.
self.features.write_up_to_13(w)?;
write_features_up_to_13(w, self.features.le_flags())?;
self.features.write(w)?;
encode_tlv_stream!(w, {
(1, self.networks.as_ref().map(|n| WithoutLength(n)), option),

View file

@ -121,75 +121,7 @@ impl fmt::Display for ChannelId {
}
}
/// The payment hash is the hash of the [`PaymentPreimage`] which is the value used to lock funds
/// in HTLCs while they transit the lightning network.
///
/// This is not exported to bindings users as we just use [u8; 32] directly
#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug, Ord, PartialOrd)]
pub struct PaymentHash(pub [u8; 32]);
impl core::fmt::Display for PaymentHash {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
crate::util::logger::DebugBytes(&self.0).fmt(f)
}
}
/// The payment preimage is the "secret key" which is used to claim the funds of an HTLC on-chain
/// or in a lightning channel.
///
/// This is not exported to bindings users as we just use [u8; 32] directly
#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug, Ord, PartialOrd)]
pub struct PaymentPreimage(pub [u8; 32]);
impl core::fmt::Display for PaymentPreimage {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
crate::util::logger::DebugBytes(&self.0).fmt(f)
}
}
/// Converts a `PaymentPreimage` into a `PaymentHash` by hashing the preimage with SHA256.
impl From<PaymentPreimage> for PaymentHash {
fn from(value: PaymentPreimage) -> Self {
PaymentHash(Sha256::hash(&value.0).to_byte_array())
}
}
/// The payment secret is used to authenticate the sender of an HTLC to the recipient and tie
/// multi-part HTLCs together into a single payment.
///
/// This is not exported to bindings users as we just use [u8; 32] directly
#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug, Ord, PartialOrd)]
pub struct PaymentSecret(pub [u8; 32]);
use bech32::{Base32Len, FromBase32, ToBase32, WriteBase32, u5};
impl FromBase32 for PaymentSecret {
type Err = bech32::Error;
fn from_base32(field_data: &[u5]) -> Result<PaymentSecret, bech32::Error> {
if field_data.len() != 52 {
return Err(bech32::Error::InvalidLength)
} else {
let data_bytes = Vec::<u8>::from_base32(field_data)?;
let mut payment_secret = [0; 32];
payment_secret.copy_from_slice(&data_bytes);
Ok(PaymentSecret(payment_secret))
}
}
}
impl ToBase32 for PaymentSecret {
fn write_base32<W: WriteBase32>(&self, writer: &mut W) -> Result<(), <W as WriteBase32>::Err> {
(&self.0[..]).write_base32(writer)
}
}
impl Base32Len for PaymentSecret {
fn base32_len(&self) -> usize {
52
}
}
pub use lightning_types::payment::{PaymentHash, PaymentPreimage, PaymentSecret};
#[cfg(test)]
mod tests {

View file

@ -45,6 +45,8 @@ use core::str::FromStr;
use core::sync::atomic::{AtomicUsize, Ordering};
use core::{cmp, fmt};
pub use lightning_types::routing::RoutingFees;
#[cfg(feature = "std")]
use std::time::{SystemTime, UNIX_EPOCH};
@ -1212,16 +1214,6 @@ impl EffectiveCapacity {
}
}
/// Fees for routing via a given channel or a node
#[derive(Eq, PartialEq, Copy, Clone, Debug, Hash, Ord, PartialOrd)]
pub struct RoutingFees {
/// Flat routing fee in millisatoshis.
pub base_msat: u32,
/// Liquidity-based routing fee in millionths of a routed amount.
/// In other words, 10000 is 1%.
pub proportional_millionths: u32,
}
impl_writeable_tlv_based!(RoutingFees, {
(0, base_msat, required),
(2, proportional_millionths, required)

View file

@ -22,7 +22,7 @@ use crate::ln::msgs::{DecodeError, ErrorAction, LightningError, MAX_VALUE_MSAT};
use crate::ln::onion_utils;
use crate::offers::invoice::{BlindedPayInfo, Bolt12Invoice};
use crate::onion_message::messenger::{DefaultMessageRouter, Destination, MessageRouter, OnionMessagePath};
use crate::routing::gossip::{DirectedChannelInfo, EffectiveCapacity, ReadOnlyNetworkGraph, NetworkGraph, NodeId, RoutingFees};
use crate::routing::gossip::{DirectedChannelInfo, EffectiveCapacity, ReadOnlyNetworkGraph, NetworkGraph, NodeId};
use crate::routing::scoring::{ChannelUsage, LockableScore, ScoreLookUp};
use crate::sign::EntropySource;
use crate::util::ser::{Writeable, Readable, ReadableArgs, Writer};
@ -35,6 +35,10 @@ use alloc::collections::BinaryHeap;
use core::{cmp, fmt};
use core::ops::Deref;
use lightning_types::routing::RoutingFees;
pub use lightning_types::routing::{RouteHint, RouteHintHop};
/// A [`Router`] implemented using [`find_route`].
///
/// # Privacy
@ -1099,10 +1103,6 @@ impl ReadableArgs<bool> for Features {
}
}
/// A list of hops along a payment path terminating with a channel to the recipient.
#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub struct RouteHint(pub Vec<RouteHintHop>);
impl Writeable for RouteHint {
fn write<W: crate::util::ser::Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
(self.0.len() as u64).write(writer)?;
@ -1124,27 +1124,6 @@ impl Readable for RouteHint {
}
}
/// A channel descriptor for a hop along a payment path.
///
/// While this generally comes from BOLT 11's `r` field, this struct includes more fields than are
/// available in BOLT 11. Thus, encoding and decoding this via `lightning-invoice` is lossy, as
/// fields not supported in BOLT 11 will be stripped.
#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub struct RouteHintHop {
/// The node_id of the non-target end of the route
pub src_node_id: PublicKey,
/// The short_channel_id of this channel
pub short_channel_id: u64,
/// The fees which must be paid to use this channel
pub fees: RoutingFees,
/// The difference in CLTV values between this node and the next node.
pub cltv_expiry_delta: u16,
/// The minimum value, in msat, which must be relayed to the next hop.
pub htlc_minimum_msat: Option<u64>,
/// The maximum value in msat available for routing with a single HTLC.
pub htlc_maximum_msat: Option<u64>,
}
impl_writeable_tlv_based!(RouteHintHop, {
(0, src_node_id, required),
(1, htlc_minimum_msat, option),

View file

@ -24,7 +24,6 @@ use bitcoin::sighash::EcdsaSighashType;
use bitcoin::transaction::Version;
use bitcoin::transaction::{Transaction, TxIn, TxOut};
use bech32::u5;
use bitcoin::hashes::sha256::Hash as Sha256;
use bitcoin::hashes::sha256d::Hash as Sha256dHash;
use bitcoin::hashes::{Hash, HashEngine};
@ -37,6 +36,8 @@ use bitcoin::secp256k1::All;
use bitcoin::secp256k1::{Keypair, PublicKey, Scalar, Secp256k1, SecretKey, Signing};
use bitcoin::{secp256k1, Psbt, Sequence, Txid, WPubkeyHash, Witness};
use lightning_invoice::RawBolt11Invoice;
use crate::chain::transaction::OutPoint;
use crate::crypto::utils::{hkdf_extract_expand_twice, sign, sign_with_aux_rand};
use crate::ln::chan_utils;
@ -69,7 +70,6 @@ use crate::sign::ecdsa::EcdsaChannelSigner;
#[cfg(taproot)]
use crate::sign::taproot::TaprootChannelSigner;
use crate::util::atomic_counter::AtomicCounter;
use crate::util::invoice::construct_invoice_preimage;
use core::convert::TryInto;
use core::ops::Deref;
use core::sync::atomic::{AtomicUsize, Ordering};
@ -867,7 +867,7 @@ pub trait NodeSigner {
///
/// Errors if the [`Recipient`] variant is not supported by the implementation.
fn sign_invoice(
&self, hrp_bytes: &[u8], invoice_data: &[u5], recipient: Recipient,
&self, invoice: &RawBolt11Invoice, recipient: Recipient,
) -> Result<RecoverableSignature, ()>;
/// Signs the [`TaggedHash`] of a BOLT 12 invoice request.
@ -2174,17 +2174,14 @@ impl NodeSigner for KeysManager {
}
fn sign_invoice(
&self, hrp_bytes: &[u8], invoice_data: &[u5], recipient: Recipient,
&self, invoice: &RawBolt11Invoice, recipient: Recipient,
) -> Result<RecoverableSignature, ()> {
let preimage = construct_invoice_preimage(&hrp_bytes, &invoice_data);
let hash = invoice.signable_hash();
let secret = match recipient {
Recipient::Node => Ok(&self.node_secret),
Recipient::PhantomNode => Err(()),
}?;
Ok(self.secp_ctx.sign_ecdsa_recoverable(
&hash_to_message!(&Sha256::hash(&preimage).to_byte_array()),
secret,
))
Ok(self.secp_ctx.sign_ecdsa_recoverable(&hash_to_message!(&hash), secret))
}
fn sign_bolt12_invoice_request(
@ -2352,17 +2349,14 @@ impl NodeSigner for PhantomKeysManager {
}
fn sign_invoice(
&self, hrp_bytes: &[u8], invoice_data: &[u5], recipient: Recipient,
&self, invoice: &RawBolt11Invoice, recipient: Recipient,
) -> Result<RecoverableSignature, ()> {
let preimage = construct_invoice_preimage(&hrp_bytes, &invoice_data);
let hash = invoice.signable_hash();
let secret = match recipient {
Recipient::Node => &self.inner.node_secret,
Recipient::PhantomNode => &self.phantom_secret,
};
Ok(self.inner.secp_ctx.sign_ecdsa_recoverable(
&hash_to_message!(&Sha256::hash(&preimage).to_byte_array()),
secret,
))
Ok(self.inner.secp_ctx.sign_ecdsa_recoverable(&hash_to_message!(&hash), secret))
}
fn sign_bolt12_invoice_request(

View file

@ -1,28 +0,0 @@
//! Low level invoice utilities.
use bech32::{u5, FromBase32};
#[allow(unused)]
use crate::prelude::*;
/// Construct the invoice's HRP and signatureless data into a preimage to be hashed.
pub fn construct_invoice_preimage(hrp_bytes: &[u8], data_without_signature: &[u5]) -> Vec<u8> {
let mut preimage = Vec::<u8>::from(hrp_bytes);
let mut data_part = Vec::from(data_without_signature);
let overhang = (data_part.len() * 5) % 8;
if overhang > 0 {
// add padding if data does not end at a byte boundary
data_part.push(u5::try_from_u8(0).unwrap());
// if overhang is in (1..3) we need to add u5(0) padding two times
if overhang < 3 {
data_part.push(u5::try_from_u8(0).unwrap());
}
}
preimage.extend_from_slice(&Vec::<u8>::from_base32(&data_part)
.expect("No padding error may occur due to appended zero above."));
preimage
}

View file

@ -18,10 +18,8 @@ pub mod ser_macros;
pub mod errors;
pub mod ser;
pub mod message_signing;
pub mod invoice;
pub mod persist;
pub mod scid_utils;
pub mod string;
pub mod sweep;
pub mod wakers;
#[cfg(fuzzing)]
@ -54,3 +52,7 @@ pub mod test_utils;
#[cfg(any(test, feature = "_test_utils"))]
pub mod test_channel_signer;
pub mod string {
//! Utilities to wrap untrusted strings and handle them (more) safely
pub use lightning_types::string::{PrintableString, UntrustedString};
}

View file

@ -627,6 +627,18 @@ impl<'a> From<&'a String> for WithoutLength<&'a String> {
fn from(s: &'a String) -> Self { Self(s) }
}
impl Writeable for UntrustedString {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
self.0.write(w)
}
}
impl Readable for UntrustedString {
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
let s: String = Readable::read(r)?;
Ok(Self(s))
}
}
impl Writeable for WithoutLength<&UntrustedString> {
#[inline]

View file

@ -65,6 +65,8 @@ use bitcoin::secp256k1::ecdh::SharedSecret;
use bitcoin::secp256k1::ecdsa::{RecoverableSignature, Signature};
use bitcoin::secp256k1::schnorr;
use lightning_invoice::RawBolt11Invoice;
use crate::io;
use crate::prelude::*;
use core::cell::RefCell;
@ -72,7 +74,6 @@ use core::time::Duration;
use crate::sync::{Mutex, Arc};
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use core::mem;
use bech32::u5;
use crate::sign::{InMemorySigner, RandomBytes, Recipient, EntropySource, NodeSigner, SignerProvider};
#[cfg(feature = "std")]
@ -1217,7 +1218,7 @@ impl NodeSigner for TestNodeSigner {
Ok(SharedSecret::new(other_key, &node_secret))
}
fn sign_invoice(&self, _: &[u8], _: &[bech32::u5], _: Recipient) -> Result<bitcoin::secp256k1::ecdsa::RecoverableSignature, ()> {
fn sign_invoice(&self, _: &RawBolt11Invoice, _: Recipient) -> Result<RecoverableSignature, ()> {
unreachable!()
}
@ -1270,8 +1271,8 @@ impl NodeSigner for TestKeysInterface {
self.backing.get_inbound_payment_key_material()
}
fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5], recipient: Recipient) -> Result<RecoverableSignature, ()> {
self.backing.sign_invoice(hrp_bytes, invoice_data, recipient)
fn sign_invoice(&self, invoice: &RawBolt11Invoice, recipient: Recipient) -> Result<RecoverableSignature, ()> {
self.backing.sign_invoice(invoice, recipient)
}
fn sign_bolt12_invoice_request(

View file

@ -41,6 +41,7 @@
./lightning/src/ln/functional_test_utils.rs
./lightning/src/ln/functional_tests.rs
./lightning/src/ln/inbound_payment.rs
./lightning/src/ln/invoice_utils.rs
./lightning/src/ln/max_payment_path_len_tests.rs
./lightning/src/ln/mod.rs
./lightning/src/ln/monitor_tests.rs