X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannelmanager.rs;h=d206dee4950f3f9908e0cbdd8af6755d485de2a2;hb=1a734492d955e61d43eab4407dd65f556e87ca96;hp=0eaf244d0e47653cc04b2cd0c508f519820f5c78;hpb=0cdea66b0e73d45b2a137eed145a294b7d713cc4;p=rust-lightning diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 0eaf244d..d206dee4 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -24,10 +24,8 @@ use bitcoin::blockdata::constants::genesis_block; use bitcoin::network::constants::Network; use bitcoin::hashes::{Hash, HashEngine}; -use bitcoin::hashes::hmac::{Hmac, HmacEngine}; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::sha256d::Hash as Sha256dHash; -use bitcoin::hashes::cmp::fixed_time_eq; use bitcoin::hash_types::{BlockHash, Txid}; use bitcoin::secp256k1::key::{SecretKey,PublicKey}; @@ -45,32 +43,303 @@ use chain::transaction::{OutPoint, TransactionData}; use ln::{PaymentHash, PaymentPreimage, PaymentSecret}; use ln::channel::{Channel, ChannelError, ChannelUpdateStatus, UpdateFulfillCommitFetch}; use ln::features::{InitFeatures, NodeFeatures}; -use routing::router::{Payee, Route, RouteHop, RoutePath, RouteParameters}; +use routing::router::{PaymentParameters, Route, RouteHop, RoutePath, RouteParameters}; use ln::msgs; use ln::msgs::NetAddress; use ln::onion_utils; -use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError, OptionalField}; -use chain::keysinterface::{Sign, KeysInterface, KeysManager, InMemorySigner}; +use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError, MAX_VALUE_MSAT, OptionalField}; +use chain::keysinterface::{Sign, KeysInterface, KeysManager, InMemorySigner, Recipient}; use util::config::UserConfig; use util::events::{EventHandler, EventsProvider, MessageSendEvent, MessageSendEventsProvider, ClosureReason}; use util::{byte_utils, events}; +use util::scid_utils::fake_scid; use util::ser::{BigSize, FixedLengthReader, Readable, ReadableArgs, MaybeReadable, Writeable, Writer}; -use util::chacha20::{ChaCha20, ChaChaReader}; -use util::logger::{Logger, Level}; +use util::logger::{Level, Logger}; use util::errors::APIError; use io; use prelude::*; use core::{cmp, mem}; use core::cell::RefCell; -use io::{Cursor, Read}; +use io::Read; use sync::{Arc, Condvar, Mutex, MutexGuard, RwLock, RwLockReadGuard}; use core::sync::atomic::{AtomicUsize, Ordering}; use core::time::Duration; -#[cfg(any(test, feature = "allow_wallclock_use"))] -use std::time::Instant; use core::ops::Deref; +#[cfg(any(test, feature = "std"))] +use std::time::Instant; + +mod inbound_payment { + use alloc::string::ToString; + use bitcoin::hashes::{Hash, HashEngine}; + use bitcoin::hashes::cmp::fixed_time_eq; + use bitcoin::hashes::hmac::{Hmac, HmacEngine}; + use bitcoin::hashes::sha256::Hash as Sha256; + use chain::keysinterface::{KeyMaterial, KeysInterface, Sign}; + use ln::{PaymentHash, PaymentPreimage, PaymentSecret}; + use ln::channelmanager::APIError; + use ln::msgs; + use ln::msgs::MAX_VALUE_MSAT; + use util::chacha20::ChaCha20; + use util::crypto::hkdf_extract_expand_thrice; + use util::logger::Logger; + + use core::convert::TryInto; + use core::ops::Deref; + + const IV_LEN: usize = 16; + const METADATA_LEN: usize = 16; + const METADATA_KEY_LEN: usize = 32; + const AMT_MSAT_LEN: usize = 8; + // Used to shift the payment type bits to take up the top 3 bits of the metadata bytes, or to + // retrieve said payment type bits. + const METHOD_TYPE_OFFSET: usize = 5; + + /// A set of keys that were HKDF-expanded from an initial call to + /// [`KeysInterface::get_inbound_payment_key_material`]. + /// + /// [`KeysInterface::get_inbound_payment_key_material`]: crate::chain::keysinterface::KeysInterface::get_inbound_payment_key_material + pub(super) struct ExpandedKey { + /// The key used to encrypt the bytes containing the payment metadata (i.e. the amount and + /// expiry, included for payment verification on decryption). + metadata_key: [u8; 32], + /// The key used to authenticate an LDK-provided payment hash and metadata as previously + /// registered with LDK. + ldk_pmt_hash_key: [u8; 32], + /// The key used to authenticate a user-provided payment hash and metadata as previously + /// registered with LDK. + user_pmt_hash_key: [u8; 32], + } + + impl ExpandedKey { + pub(super) fn new(key_material: &KeyMaterial) -> ExpandedKey { + let (metadata_key, ldk_pmt_hash_key, user_pmt_hash_key) = + hkdf_extract_expand_thrice(b"LDK Inbound Payment Key Expansion", &key_material.0); + Self { + metadata_key, + ldk_pmt_hash_key, + user_pmt_hash_key, + } + } + } + + enum Method { + LdkPaymentHash = 0, + UserPaymentHash = 1, + } + + impl Method { + fn from_bits(bits: u8) -> Result { + match bits { + bits if bits == Method::LdkPaymentHash as u8 => Ok(Method::LdkPaymentHash), + bits if bits == Method::UserPaymentHash as u8 => Ok(Method::UserPaymentHash), + unknown => Err(unknown), + } + } + } + + pub(super) fn create(keys: &ExpandedKey, min_value_msat: Option, invoice_expiry_delta_secs: u32, keys_manager: &K, highest_seen_timestamp: u64) -> Result<(PaymentHash, PaymentSecret), ()> + where K::Target: KeysInterface + { + let metadata_bytes = construct_metadata_bytes(min_value_msat, Method::LdkPaymentHash, invoice_expiry_delta_secs, highest_seen_timestamp)?; + + let mut iv_bytes = [0 as u8; IV_LEN]; + let rand_bytes = keys_manager.get_secure_random_bytes(); + iv_bytes.copy_from_slice(&rand_bytes[..IV_LEN]); + + let mut hmac = HmacEngine::::new(&keys.ldk_pmt_hash_key); + hmac.input(&iv_bytes); + hmac.input(&metadata_bytes); + let payment_preimage_bytes = Hmac::from_engine(hmac).into_inner(); + + let ldk_pmt_hash = PaymentHash(Sha256::hash(&payment_preimage_bytes).into_inner()); + let payment_secret = construct_payment_secret(&iv_bytes, &metadata_bytes, &keys.metadata_key); + Ok((ldk_pmt_hash, payment_secret)) + } + + pub(super) fn create_from_hash(keys: &ExpandedKey, min_value_msat: Option, payment_hash: PaymentHash, invoice_expiry_delta_secs: u32, highest_seen_timestamp: u64) -> Result { + let metadata_bytes = construct_metadata_bytes(min_value_msat, Method::UserPaymentHash, invoice_expiry_delta_secs, highest_seen_timestamp)?; + + let mut hmac = HmacEngine::::new(&keys.user_pmt_hash_key); + hmac.input(&metadata_bytes); + hmac.input(&payment_hash.0); + let hmac_bytes = Hmac::from_engine(hmac).into_inner(); + + let mut iv_bytes = [0 as u8; IV_LEN]; + iv_bytes.copy_from_slice(&hmac_bytes[..IV_LEN]); + + Ok(construct_payment_secret(&iv_bytes, &metadata_bytes, &keys.metadata_key)) + } + + fn construct_metadata_bytes(min_value_msat: Option, payment_type: Method, invoice_expiry_delta_secs: u32, highest_seen_timestamp: u64) -> Result<[u8; METADATA_LEN], ()> { + if min_value_msat.is_some() && min_value_msat.unwrap() > MAX_VALUE_MSAT { + return Err(()); + } + + let mut min_amt_msat_bytes: [u8; AMT_MSAT_LEN] = match min_value_msat { + Some(amt) => amt.to_be_bytes(), + None => [0; AMT_MSAT_LEN], + }; + min_amt_msat_bytes[0] |= (payment_type as u8) << METHOD_TYPE_OFFSET; + + // We assume that highest_seen_timestamp is pretty close to the current time - it's updated when + // we receive a new block with the maximum time we've seen in a header. It should never be more + // than two hours in the future. Thus, we add two hours here as a buffer to ensure we + // absolutely never fail a payment too early. + // Note that we assume that received blocks have reasonably up-to-date timestamps. + let expiry_bytes = (highest_seen_timestamp + invoice_expiry_delta_secs as u64 + 7200).to_be_bytes(); + + let mut metadata_bytes: [u8; METADATA_LEN] = [0; METADATA_LEN]; + metadata_bytes[..AMT_MSAT_LEN].copy_from_slice(&min_amt_msat_bytes); + metadata_bytes[AMT_MSAT_LEN..].copy_from_slice(&expiry_bytes); + + Ok(metadata_bytes) + } + + fn construct_payment_secret(iv_bytes: &[u8; IV_LEN], metadata_bytes: &[u8; METADATA_LEN], metadata_key: &[u8; METADATA_KEY_LEN]) -> PaymentSecret { + let mut payment_secret_bytes: [u8; 32] = [0; 32]; + let (iv_slice, encrypted_metadata_slice) = payment_secret_bytes.split_at_mut(IV_LEN); + iv_slice.copy_from_slice(iv_bytes); + + let chacha_block = ChaCha20::get_single_block(metadata_key, iv_bytes); + for i in 0..METADATA_LEN { + encrypted_metadata_slice[i] = chacha_block[i] ^ metadata_bytes[i]; + } + PaymentSecret(payment_secret_bytes) + } + + /// Check that an inbound payment's `payment_data` field is sane. + /// + /// LDK does not store any data for pending inbound payments. Instead, we construct our payment + /// secret (and, if supplied by LDK, our payment preimage) to include encrypted metadata about the + /// payment. + /// + /// The metadata is constructed as: + /// payment method (3 bits) || payment amount (8 bytes - 3 bits) || expiry (8 bytes) + /// and encrypted using a key derived from [`KeysInterface::get_inbound_payment_key_material`]. + /// + /// Then on payment receipt, we verify in this method that the payment preimage and payment secret + /// match what was constructed. + /// + /// [`create_inbound_payment`] and [`create_inbound_payment_for_hash`] are called by the user to + /// construct the payment secret and/or payment hash that this method is verifying. If the former + /// method is called, then the payment method bits mentioned above are represented internally as + /// [`Method::LdkPaymentHash`]. If the latter, [`Method::UserPaymentHash`]. + /// + /// For the former method, the payment preimage is constructed as an HMAC of payment metadata and + /// random bytes. Because the payment secret is also encoded with these random bytes and metadata + /// (with the metadata encrypted with a block cipher), we're able to authenticate the preimage on + /// payment receipt. + /// + /// For the latter, the payment secret instead contains an HMAC of the user-provided payment hash + /// and payment metadata (encrypted with a block cipher), allowing us to authenticate the payment + /// hash and metadata on payment receipt. + /// + /// See [`ExpandedKey`] docs for more info on the individual keys used. + /// + /// [`KeysInterface::get_inbound_payment_key_material`]: crate::chain::keysinterface::KeysInterface::get_inbound_payment_key_material + /// [`create_inbound_payment`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment + /// [`create_inbound_payment_for_hash`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment_for_hash + pub(super) fn verify(payment_hash: PaymentHash, payment_data: msgs::FinalOnionHopData, highest_seen_timestamp: u64, keys: &ExpandedKey, logger: &L) -> Result, ()> + where L::Target: Logger + { + let (iv_bytes, metadata_bytes) = decrypt_metadata(payment_data.payment_secret, keys); + + let payment_type_res = Method::from_bits((metadata_bytes[0] & 0b1110_0000) >> METHOD_TYPE_OFFSET); + let mut amt_msat_bytes = [0; AMT_MSAT_LEN]; + amt_msat_bytes.copy_from_slice(&metadata_bytes[..AMT_MSAT_LEN]); + // Zero out the bits reserved to indicate the payment type. + amt_msat_bytes[0] &= 0b00011111; + let min_amt_msat: u64 = u64::from_be_bytes(amt_msat_bytes.into()); + let expiry = u64::from_be_bytes(metadata_bytes[AMT_MSAT_LEN..].try_into().unwrap()); + + // Make sure to check to check the HMAC before doing the other checks below, to mitigate timing + // attacks. + let mut payment_preimage = None; + match payment_type_res { + Ok(Method::UserPaymentHash) => { + let mut hmac = HmacEngine::::new(&keys.user_pmt_hash_key); + hmac.input(&metadata_bytes[..]); + hmac.input(&payment_hash.0); + if !fixed_time_eq(&iv_bytes, &Hmac::from_engine(hmac).into_inner().split_at_mut(IV_LEN).0) { + log_trace!(logger, "Failing HTLC with user-generated payment_hash {}: unexpected payment_secret", log_bytes!(payment_hash.0)); + return Err(()) + } + }, + Ok(Method::LdkPaymentHash) => { + match derive_ldk_payment_preimage(payment_hash, &iv_bytes, &metadata_bytes, keys) { + Ok(preimage) => payment_preimage = Some(preimage), + Err(bad_preimage_bytes) => { + log_trace!(logger, "Failing HTLC with payment_hash {} due to mismatching preimage {}", log_bytes!(payment_hash.0), log_bytes!(bad_preimage_bytes)); + return Err(()) + } + } + }, + Err(unknown_bits) => { + log_trace!(logger, "Failing HTLC with payment hash {} due to unknown payment type {}", log_bytes!(payment_hash.0), unknown_bits); + return Err(()); + } + } + + if payment_data.total_msat < min_amt_msat { + log_trace!(logger, "Failing HTLC with payment_hash {} due to total_msat {} being less than the minimum amount of {} msat", log_bytes!(payment_hash.0), payment_data.total_msat, min_amt_msat); + return Err(()) + } + + if expiry < highest_seen_timestamp { + log_trace!(logger, "Failing HTLC with payment_hash {}: expired payment", log_bytes!(payment_hash.0)); + return Err(()) + } + + Ok(payment_preimage) + } + + pub(super) fn get_payment_preimage(payment_hash: PaymentHash, payment_secret: PaymentSecret, keys: &ExpandedKey) -> Result { + let (iv_bytes, metadata_bytes) = decrypt_metadata(payment_secret, keys); + + match Method::from_bits((metadata_bytes[0] & 0b1110_0000) >> METHOD_TYPE_OFFSET) { + Ok(Method::LdkPaymentHash) => { + derive_ldk_payment_preimage(payment_hash, &iv_bytes, &metadata_bytes, keys) + .map_err(|bad_preimage_bytes| APIError::APIMisuseError { + err: format!("Payment hash {} did not match decoded preimage {}", log_bytes!(payment_hash.0), log_bytes!(bad_preimage_bytes)) + }) + }, + Ok(Method::UserPaymentHash) => Err(APIError::APIMisuseError { + err: "Expected payment type to be LdkPaymentHash, instead got UserPaymentHash".to_string() + }), + Err(other) => Err(APIError::APIMisuseError { err: format!("Unknown payment type: {}", other) }), + } + } + + fn decrypt_metadata(payment_secret: PaymentSecret, keys: &ExpandedKey) -> ([u8; IV_LEN], [u8; METADATA_LEN]) { + let mut iv_bytes = [0; IV_LEN]; + let (iv_slice, encrypted_metadata_bytes) = payment_secret.0.split_at(IV_LEN); + iv_bytes.copy_from_slice(iv_slice); + + let chacha_block = ChaCha20::get_single_block(&keys.metadata_key, &iv_bytes); + let mut metadata_bytes: [u8; METADATA_LEN] = [0; METADATA_LEN]; + for i in 0..METADATA_LEN { + metadata_bytes[i] = chacha_block[i] ^ encrypted_metadata_bytes[i]; + } + + (iv_bytes, metadata_bytes) + } + + // Errors if the payment preimage doesn't match `payment_hash`. Returns the bad preimage bytes in + // this case. + fn derive_ldk_payment_preimage(payment_hash: PaymentHash, iv_bytes: &[u8; IV_LEN], metadata_bytes: &[u8; METADATA_LEN], keys: &ExpandedKey) -> Result { + let mut hmac = HmacEngine::::new(&keys.ldk_pmt_hash_key); + hmac.input(iv_bytes); + hmac.input(metadata_bytes); + let decoded_payment_preimage = Hmac::from_engine(hmac).into_inner(); + if !fixed_time_eq(&payment_hash.0, &Sha256::hash(&decoded_payment_preimage).into_inner()) { + return Err(decoded_payment_preimage); + } + return Ok(PaymentPreimage(decoded_payment_preimage)) + } +} + // We hold various information about HTLC relay in the HTLC objects in Channel itself: // // Upon receipt of an HTLC from a peer, we'll give it a PendingHTLCStatus indicating if it should @@ -89,7 +358,7 @@ use core::ops::Deref; // our payment, which we can use to decode errors or inform the user that the payment was sent. #[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug -enum PendingHTLCRouting { +pub(super) enum PendingHTLCRouting { Forward { onion_packet: msgs::OnionPacket, short_channel_id: u64, // This should be NonZero eventually when we bump MSRV @@ -97,6 +366,7 @@ enum PendingHTLCRouting { Receive { payment_data: msgs::FinalOnionHopData, incoming_cltv_expiry: u32, // Used to track when we should expire pending HTLCs that go unclaimed + phantom_shared_secret: Option<[u8; 32]>, }, ReceiveKeysend { payment_preimage: PaymentPreimage, @@ -106,8 +376,8 @@ enum PendingHTLCRouting { #[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug pub(super) struct PendingHTLCInfo { - routing: PendingHTLCRouting, - incoming_shared_secret: [u8; 32], + pub(super) routing: PendingHTLCRouting, + pub(super) incoming_shared_secret: [u8; 32], payment_hash: PaymentHash, pub(super) amt_to_forward: u64, pub(super) outgoing_cltv_value: u32, @@ -150,6 +420,7 @@ pub(crate) struct HTLCPreviousHopData { short_channel_id: u64, htlc_id: u64, incoming_packet_shared_secret: [u8; 32], + phantom_shared_secret: Option<[u8; 32]>, // This field is consumed by `claim_funds_from_hop()` when updating a force-closed backwards // channel with a preimage provided by the forward channel. @@ -202,7 +473,7 @@ pub(crate) enum HTLCSource { first_hop_htlc_msat: u64, payment_id: PaymentId, payment_secret: Option, - payee: Option, + payment_params: Option, }, } #[allow(clippy::derive_hash_xor_eq)] // Our Hash is faithful to the data, we just don't have SecretKey::hash @@ -213,14 +484,14 @@ impl core::hash::Hash for HTLCSource { 0u8.hash(hasher); prev_hop_data.hash(hasher); }, - HTLCSource::OutboundRoute { path, session_priv, payment_id, payment_secret, first_hop_htlc_msat, payee } => { + HTLCSource::OutboundRoute { path, session_priv, payment_id, payment_secret, first_hop_htlc_msat, payment_params } => { 1u8.hash(hasher); path.hash(hasher); session_priv[..].hash(hasher); payment_id.hash(hasher); payment_secret.hash(hasher); first_hop_htlc_msat.hash(hasher); - payee.hash(hasher); + payment_params.hash(hasher); }, } } @@ -234,7 +505,7 @@ impl HTLCSource { first_hop_htlc_msat: 0, payment_id: PaymentId([2; 32]), payment_secret: None, - payee: None, + payment_params: None, } } } @@ -250,6 +521,12 @@ pub(super) enum HTLCFailReason { } } +struct ReceiveError { + err_code: u16, + err_data: Vec, + msg: &'static str, +} + /// Return value for claim_funds_from_hop enum ClaimFundsFromHop { PrevHopForceClosed, @@ -324,8 +601,14 @@ impl MsgHandleErrInternal { Self { err: match err { ChannelError::Warn(msg) => LightningError { - err: msg, - action: msgs::ErrorAction::IgnoreError, + err: msg.clone(), + action: msgs::ErrorAction::SendWarningMessage { + msg: msgs::WarningMessage { + channel_id, + data: msg + }, + log_level: Level::Warn, + }, }, ChannelError::Ignore(msg) => LightningError { err: msg, @@ -454,6 +737,17 @@ pub(crate) enum PendingOutboundPayment { session_privs: HashSet<[u8; 32]>, payment_hash: Option, }, + /// When a payer gives up trying to retry a payment, they inform us, letting us generate a + /// `PaymentFailed` event when all HTLCs have irrevocably failed. This avoids a number of race + /// conditions in MPP-aware payment retriers (1), where the possibility of multiple + /// `PaymentPathFailed` events with `all_paths_failed` can be pending at once, confusing a + /// downstream event handler as to when a payment has actually failed. + /// + /// (1) https://github.com/lightningdevkit/rust-lightning/issues/1164 + Abandoned { + session_privs: HashSet<[u8; 32]>, + payment_hash: PaymentHash, + }, } impl PendingOutboundPayment { @@ -469,6 +763,12 @@ impl PendingOutboundPayment { _ => false, } } + fn abandoned(&self) -> bool { + match self { + PendingOutboundPayment::Abandoned { .. } => true, + _ => false, + } + } fn get_pending_fee_msat(&self) -> Option { match self { PendingOutboundPayment::Retryable { pending_fee_msat, .. } => pending_fee_msat.clone(), @@ -481,6 +781,7 @@ impl PendingOutboundPayment { PendingOutboundPayment::Legacy { .. } => None, PendingOutboundPayment::Retryable { payment_hash, .. } => Some(*payment_hash), PendingOutboundPayment::Fulfilled { payment_hash, .. } => *payment_hash, + PendingOutboundPayment::Abandoned { payment_hash, .. } => Some(*payment_hash), } } @@ -489,19 +790,38 @@ impl PendingOutboundPayment { core::mem::swap(&mut session_privs, match self { PendingOutboundPayment::Legacy { session_privs } | PendingOutboundPayment::Retryable { session_privs, .. } | - PendingOutboundPayment::Fulfilled { session_privs, .. } - => session_privs + PendingOutboundPayment::Fulfilled { session_privs, .. } | + PendingOutboundPayment::Abandoned { session_privs, .. } + => session_privs, }); let payment_hash = self.payment_hash(); *self = PendingOutboundPayment::Fulfilled { session_privs, payment_hash }; } + fn mark_abandoned(&mut self) -> Result<(), ()> { + let mut session_privs = HashSet::new(); + let our_payment_hash; + core::mem::swap(&mut session_privs, match self { + PendingOutboundPayment::Legacy { .. } | + PendingOutboundPayment::Fulfilled { .. } => + return Err(()), + PendingOutboundPayment::Retryable { session_privs, payment_hash, .. } | + PendingOutboundPayment::Abandoned { session_privs, payment_hash, .. } => { + our_payment_hash = *payment_hash; + session_privs + }, + }); + *self = PendingOutboundPayment::Abandoned { session_privs, payment_hash: our_payment_hash }; + Ok(()) + } + /// panics if path is None and !self.is_fulfilled fn remove(&mut self, session_priv: &[u8; 32], path: Option<&Vec>) -> bool { let remove_res = match self { PendingOutboundPayment::Legacy { session_privs } | PendingOutboundPayment::Retryable { session_privs, .. } | - PendingOutboundPayment::Fulfilled { session_privs, .. } => { + PendingOutboundPayment::Fulfilled { session_privs, .. } | + PendingOutboundPayment::Abandoned { session_privs, .. } => { session_privs.remove(session_priv) } }; @@ -524,7 +844,8 @@ impl PendingOutboundPayment { PendingOutboundPayment::Retryable { session_privs, .. } => { session_privs.insert(session_priv) } - PendingOutboundPayment::Fulfilled { .. } => false + PendingOutboundPayment::Fulfilled { .. } => false, + PendingOutboundPayment::Abandoned { .. } => false, }; if insert_res { if let PendingOutboundPayment::Retryable { ref mut pending_amt_msat, ref mut pending_fee_msat, .. } = self { @@ -542,7 +863,8 @@ impl PendingOutboundPayment { match self { PendingOutboundPayment::Legacy { session_privs } | PendingOutboundPayment::Retryable { session_privs, .. } | - PendingOutboundPayment::Fulfilled { session_privs, .. } => { + PendingOutboundPayment::Fulfilled { session_privs, .. } | + PendingOutboundPayment::Abandoned { session_privs, .. } => { session_privs.len() } } @@ -652,6 +974,15 @@ pub struct ChannelManager, /// The `user_channel_id` passed in to create_channel, or 0 if the channel was inbound. pub user_channel_id: u64, + /// Our total balance. This is the amount we would get if we close the channel. + /// This value is not exact. Due to various in-flight changes and feerate changes, exactly this + /// amount is not likely to be recoverable on close. + /// + /// This does not include any pending HTLCs which are not yet fully resolved (and, thus, whose + /// balance is not available for inclusion in new outbound HTLCs). This further does not include + /// any pending outgoing HTLCs which are awaiting some other resolution to be sent. + /// This does not consider any on-chain fees. + /// + /// See also [`ChannelDetails::outbound_capacity_msat`] + pub balance_msat: u64, /// The available outbound capacity for sending HTLCs to the remote peer. This does not include - /// any pending HTLCs which are not yet fully resolved (and, thus, who's balance is not + /// any pending HTLCs which are not yet fully resolved (and, thus, whose balance is not /// available for inclusion in new outbound HTLCs). This further does not include any pending /// outgoing HTLCs which are awaiting some other resolution to be sent. /// + /// See also [`ChannelDetails::balance_msat`] + /// /// This value is not exact. Due to various in-flight changes, feerate changes, and our /// conflict-avoidance policy, exactly this amount is not likely to be spendable. However, we /// should be able to spend nearly this amount. pub outbound_capacity_msat: u64, /// The available inbound capacity for the remote peer to send HTLCs to us. This does not - /// include any pending HTLCs which are not yet fully resolved (and, thus, who's balance is not + /// include any pending HTLCs which are not yet fully resolved (and, thus, whose balance is not /// available for inclusion in new inbound HTLCs). /// Note that there are some corner cases not fully handled here, so the actual available /// inbound capacity may be slightly higher than this. @@ -971,6 +1319,20 @@ pub enum PaymentSendFailure { }, } +/// Route hints used in constructing invoices for [phantom node payents]. +/// +/// [phantom node payments]: crate::chain::keysinterface::PhantomKeysManager +#[derive(Clone)] +pub struct PhantomRouteHints { + /// The list of channels to be included in the invoice route hints. + pub channels: Vec, + /// A fake scid used for representing the phantom node's fake channel in generating the invoice + /// route hints. + pub phantom_scid: u64, + /// The pubkey of the real backing node that would ultimately receive the payment. + pub real_node_pubkey: PublicKey, +} + macro_rules! handle_error { ($self: ident, $internal: expr, $counterparty_node_id: expr) => { match $internal { @@ -1026,9 +1388,7 @@ macro_rules! convert_chan_err { ($self: ident, $err: expr, $short_to_id: expr, $channel: expr, $channel_id: expr) => { match $err { ChannelError::Warn(msg) => { - //TODO: Once warning messages are merged, we should send a `warning` message to our - //peer here. - (false, MsgHandleErrInternal::from_chan_no_close(ChannelError::Ignore(msg), $channel_id.clone())) + (false, MsgHandleErrInternal::from_chan_no_close(ChannelError::Warn(msg), $channel_id.clone())) }, ChannelError::Ignore(msg) => { (false, MsgHandleErrInternal::from_chan_no_close(ChannelError::Ignore(msg), $channel_id.clone())) @@ -1182,7 +1542,7 @@ macro_rules! maybe_break_monitor_err { macro_rules! handle_chan_restoration_locked { ($self: ident, $channel_lock: expr, $channel_state: expr, $channel_entry: expr, $raa: expr, $commitment_update: expr, $order: expr, $chanmon_update: expr, - $pending_forwards: expr, $funding_broadcastable: expr, $funding_locked: expr) => { { + $pending_forwards: expr, $funding_broadcastable: expr, $funding_locked: expr, $announcement_sigs: expr) => { { let mut htlc_forwards = None; let counterparty_node_id = $channel_entry.get().get_counterparty_node_id(); @@ -1217,14 +1577,14 @@ macro_rules! handle_chan_restoration_locked { node_id: counterparty_node_id, msg, }); - if let Some(announcement_sigs) = $self.get_announcement_sigs($channel_entry.get()) { - $channel_state.pending_msg_events.push(events::MessageSendEvent::SendAnnouncementSignatures { - node_id: counterparty_node_id, - msg: announcement_sigs, - }); - } $channel_state.short_to_id.insert($channel_entry.get().get_short_channel_id().unwrap(), $channel_entry.get().channel_id()); } + if let Some(msg) = $announcement_sigs { + $channel_state.pending_msg_events.push(events::MessageSendEvent::SendAnnouncementSignatures { + node_id: counterparty_node_id, + msg, + }); + } let funding_broadcastable: Option = $funding_broadcastable; // Force type-checking to resolve if let Some(monitor_update) = chanmon_update { @@ -1328,7 +1688,8 @@ impl ChannelMana pub fn new(fee_est: F, chain_monitor: M, tx_broadcaster: T, logger: L, keys_manager: K, config: UserConfig, params: ChainParameters) -> Self { let mut secp_ctx = Secp256k1::new(); secp_ctx.seeded_randomize(&keys_manager.get_secure_random_bytes()); - + let inbound_pmt_key_material = keys_manager.get_inbound_payment_key_material(); + let expanded_inbound_key = inbound_payment::ExpandedKey::new(&inbound_pmt_key_material); ChannelManager { default_configuration: config.clone(), genesis_hash: genesis_block(params.network).header.block_hash(), @@ -1348,10 +1709,13 @@ impl ChannelMana pending_inbound_payments: Mutex::new(HashMap::new()), pending_outbound_payments: Mutex::new(HashMap::new()), - our_network_key: keys_manager.get_node_secret(), - our_network_pubkey: PublicKey::from_secret_key(&secp_ctx, &keys_manager.get_node_secret()), + our_network_key: keys_manager.get_node_secret(Recipient::Node).unwrap(), + our_network_pubkey: PublicKey::from_secret_key(&secp_ctx, &keys_manager.get_node_secret(Recipient::Node).unwrap()), secp_ctx, + inbound_payment_key: expanded_inbound_key, + fake_scid_rand_bytes: keys_manager.get_secure_random_bytes(), + last_node_announcement_serial: AtomicUsize::new(0), highest_seen_timestamp: AtomicUsize::new(0), @@ -1427,7 +1791,7 @@ impl ChannelMana let mut channel_state = self.channel_state.lock().unwrap(); match channel_state.by_id.entry(temporary_channel_id) { hash_map::Entry::Occupied(_) => { - if cfg!(feature = "fuzztarget") { + if cfg!(fuzzing) { return Err(APIError::APIMisuseError { err: "Fuzzy bad RNG".to_owned() }); } else { panic!("RNG is bad???"); @@ -1449,6 +1813,7 @@ impl ChannelMana res.reserve(channel_state.by_id.len()); for (channel_id, channel) in channel_state.by_id.iter().filter(f) { let (inbound_capacity_msat, outbound_capacity_msat) = channel.get_inbound_outbound_available_balance_msat(); + let balance_msat = channel.get_balance_msat(); let (to_remote_reserve_satoshis, to_self_reserve_satoshis) = channel.get_holder_counterparty_selected_channel_reserve_satoshis(); res.push(ChannelDetails { @@ -1463,6 +1828,7 @@ impl ChannelMana short_channel_id: channel.get_short_channel_id(), channel_value_satoshis: channel.get_value_satoshis(), unspendable_punishment_reserve: to_self_reserve_satoshis, + balance_msat, inbound_capacity_msat, outbound_capacity_msat, user_channel_id: channel.get_user_id(), @@ -1708,6 +2074,103 @@ impl ChannelMana } } + fn construct_recv_pending_htlc_info(&self, hop_data: msgs::OnionHopData, shared_secret: [u8; 32], + payment_hash: PaymentHash, amt_msat: u64, cltv_expiry: u32, phantom_shared_secret: Option<[u8; 32]>) -> Result + { + // final_incorrect_cltv_expiry + if hop_data.outgoing_cltv_value != cltv_expiry { + return Err(ReceiveError { + msg: "Upstream node set CLTV to the wrong value", + err_code: 18, + err_data: byte_utils::be32_to_array(cltv_expiry).to_vec() + }) + } + // final_expiry_too_soon + // We have to have some headroom to broadcast on chain if we have the preimage, so make sure + // we have at least HTLC_FAIL_BACK_BUFFER blocks to go. + // Also, ensure that, in the case of an unknown preimage for the received payment hash, our + // payment logic has enough time to fail the HTLC backward before our onchain logic triggers a + // channel closure (see HTLC_FAIL_BACK_BUFFER rationale). + if (hop_data.outgoing_cltv_value as u64) <= self.best_block.read().unwrap().height() as u64 + HTLC_FAIL_BACK_BUFFER as u64 + 1 { + return Err(ReceiveError { + err_code: 17, + err_data: Vec::new(), + msg: "The final CLTV expiry is too soon to handle", + }); + } + if hop_data.amt_to_forward > amt_msat { + return Err(ReceiveError { + err_code: 19, + err_data: byte_utils::be64_to_array(amt_msat).to_vec(), + msg: "Upstream node sent less than we were supposed to receive in payment", + }); + } + + let routing = match hop_data.format { + msgs::OnionHopDataFormat::Legacy { .. } => { + return Err(ReceiveError { + err_code: 0x4000|0x2000|3, + err_data: Vec::new(), + msg: "We require payment_secrets", + }); + }, + msgs::OnionHopDataFormat::NonFinalNode { .. } => { + return Err(ReceiveError { + err_code: 0x4000|22, + err_data: Vec::new(), + msg: "Got non final data with an HMAC of 0", + }); + }, + msgs::OnionHopDataFormat::FinalNode { payment_data, keysend_preimage } => { + if payment_data.is_some() && keysend_preimage.is_some() { + return Err(ReceiveError { + err_code: 0x4000|22, + err_data: Vec::new(), + msg: "We don't support MPP keysend payments", + }); + } else if let Some(data) = payment_data { + PendingHTLCRouting::Receive { + payment_data: data, + incoming_cltv_expiry: hop_data.outgoing_cltv_value, + phantom_shared_secret, + } + } else if let Some(payment_preimage) = keysend_preimage { + // We need to check that the sender knows the keysend preimage before processing this + // payment further. Otherwise, an intermediary routing hop forwarding non-keysend-HTLC X + // could discover the final destination of X, by probing the adjacent nodes on the route + // with a keysend payment of identical payment hash to X and observing the processing + // time discrepancies due to a hash collision with X. + let hashed_preimage = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner()); + if hashed_preimage != payment_hash { + return Err(ReceiveError { + err_code: 0x4000|22, + err_data: Vec::new(), + msg: "Payment preimage didn't match payment hash", + }); + } + + PendingHTLCRouting::ReceiveKeysend { + payment_preimage, + incoming_cltv_expiry: hop_data.outgoing_cltv_value, + } + } else { + return Err(ReceiveError { + err_code: 0x4000|0x2000|3, + err_data: Vec::new(), + msg: "We require payment_secrets", + }); + } + }, + }; + Ok(PendingHTLCInfo { + routing, + payment_hash, + incoming_shared_secret: shared_secret, + amt_to_forward: amt_msat, + outgoing_cltv_value: hop_data.outgoing_cltv_value, + }) + } + fn decode_update_add_htlc_onion(&self, msg: &msgs::UpdateAddHTLC) -> (PendingHTLCStatus, MutexGuard>) { macro_rules! return_malformed_err { ($msg: expr, $err_code: expr) => { @@ -1732,7 +2195,6 @@ impl ChannelMana arr.copy_from_slice(&SharedSecret::new(&msg.onion_routing_packet.public_key.unwrap(), &self.our_network_key)[..]); arr }; - let (rho, mu) = onion_utils::gen_rho_mu_from_shared_secret(&shared_secret); if msg.onion_routing_packet.version != 0 { //TODO: Spec doesn't indicate if we should only hash hop_data here (and in other @@ -1744,13 +2206,6 @@ impl ChannelMana return_malformed_err!("Unknown onion packet version", 0x8000 | 0x4000 | 4); } - let mut hmac = HmacEngine::::new(&mu); - hmac.input(&msg.onion_routing_packet.hop_data); - hmac.input(&msg.payment_hash.0[..]); - if !fixed_time_eq(&Hmac::from_engine(hmac).into_inner(), &msg.onion_routing_packet.hmac) { - return_malformed_err!("HMAC Check failed", 0x8000 | 0x4000 | 5); - } - let mut channel_state = None; macro_rules! return_err { ($msg: expr, $err_code: expr, $data: expr) => { @@ -1768,164 +2223,70 @@ impl ChannelMana } } - let mut chacha = ChaCha20::new(&rho, &[0u8; 8]); - let mut chacha_stream = ChaChaReader { chacha: &mut chacha, read: Cursor::new(&msg.onion_routing_packet.hop_data[..]) }; - let (next_hop_data, next_hop_hmac): (msgs::OnionHopData, _) = { - match ::read(&mut chacha_stream) { - Err(err) => { - let error_code = match err { - msgs::DecodeError::UnknownVersion => 0x4000 | 1, // unknown realm byte - msgs::DecodeError::UnknownRequiredFeature| - msgs::DecodeError::InvalidValue| - msgs::DecodeError::ShortRead => 0x4000 | 22, // invalid_onion_payload - _ => 0x2000 | 2, // Should never happen - }; - return_err!("Unable to decode our hop data", error_code, &[0;0]); - }, - Ok(msg) => { - let mut hmac = [0; 32]; - if let Err(_) = chacha_stream.read_exact(&mut hmac[..]) { - return_err!("Unable to decode hop data", 0x4000 | 22, &[0;0]); - } - (msg, hmac) - }, - } + let next_hop = match onion_utils::decode_next_hop(shared_secret, &msg.onion_routing_packet.hop_data[..], msg.onion_routing_packet.hmac, msg.payment_hash) { + Ok(res) => res, + Err(onion_utils::OnionDecodeErr::Malformed { err_msg, err_code }) => { + return_malformed_err!(err_msg, err_code); + }, + Err(onion_utils::OnionDecodeErr::Relay { err_msg, err_code }) => { + return_err!(err_msg, err_code, &[0; 0]); + }, }; - let pending_forward_info = if next_hop_hmac == [0; 32] { - #[cfg(test)] - { - // In tests, make sure that the initial onion pcket data is, at least, non-0. - // We could do some fancy randomness test here, but, ehh, whatever. - // This checks for the issue where you can calculate the path length given the - // onion data as all the path entries that the originator sent will be here - // as-is (and were originally 0s). - // Of course reverse path calculation is still pretty easy given naive routing - // algorithms, but this fixes the most-obvious case. - let mut next_bytes = [0; 32]; - chacha_stream.read_exact(&mut next_bytes).unwrap(); - assert_ne!(next_bytes[..], [0; 32][..]); - chacha_stream.read_exact(&mut next_bytes).unwrap(); - assert_ne!(next_bytes[..], [0; 32][..]); - } + let pending_forward_info = match next_hop { + onion_utils::Hop::Receive(next_hop_data) => { + // OUR PAYMENT! + match self.construct_recv_pending_htlc_info(next_hop_data, shared_secret, msg.payment_hash, msg.amount_msat, msg.cltv_expiry, None) { + Ok(info) => { + // Note that we could obviously respond immediately with an update_fulfill_htlc + // message, however that would leak that we are the recipient of this payment, so + // instead we stay symmetric with the forwarding case, only responding (after a + // delay) once they've send us a commitment_signed! + PendingHTLCStatus::Forward(info) + }, + Err(ReceiveError { err_code, err_data, msg }) => return_err!(msg, err_code, &err_data) + } + }, + onion_utils::Hop::Forward { next_hop_data, next_hop_hmac, new_packet_bytes } => { + let mut new_pubkey = msg.onion_routing_packet.public_key.unwrap(); + + let blinding_factor = { + let mut sha = Sha256::engine(); + sha.input(&new_pubkey.serialize()[..]); + sha.input(&shared_secret); + Sha256::from_engine(sha).into_inner() + }; - // OUR PAYMENT! - // final_expiry_too_soon - // We have to have some headroom to broadcast on chain if we have the preimage, so make sure - // we have at least HTLC_FAIL_BACK_BUFFER blocks to go. - // Also, ensure that, in the case of an unknown preimage for the received payment hash, our - // payment logic has enough time to fail the HTLC backward before our onchain logic triggers a - // channel closure (see HTLC_FAIL_BACK_BUFFER rationale). - if (msg.cltv_expiry as u64) <= self.best_block.read().unwrap().height() as u64 + HTLC_FAIL_BACK_BUFFER as u64 + 1 { - return_err!("The final CLTV expiry is too soon to handle", 17, &[0;0]); - } - // final_incorrect_htlc_amount - if next_hop_data.amt_to_forward > msg.amount_msat { - return_err!("Upstream node sent less than we were supposed to receive in payment", 19, &byte_utils::be64_to_array(msg.amount_msat)); - } - // final_incorrect_cltv_expiry - if next_hop_data.outgoing_cltv_value != msg.cltv_expiry { - return_err!("Upstream node set CLTV to the wrong value", 18, &byte_utils::be32_to_array(msg.cltv_expiry)); - } + let public_key = if let Err(e) = new_pubkey.mul_assign(&self.secp_ctx, &blinding_factor[..]) { + Err(e) + } else { Ok(new_pubkey) }; - let routing = match next_hop_data.format { - msgs::OnionHopDataFormat::Legacy { .. } => return_err!("We require payment_secrets", 0x4000|0x2000|3, &[0;0]), - msgs::OnionHopDataFormat::NonFinalNode { .. } => return_err!("Got non final data with an HMAC of 0", 0x4000 | 22, &[0;0]), - msgs::OnionHopDataFormat::FinalNode { payment_data, keysend_preimage } => { - if payment_data.is_some() && keysend_preimage.is_some() { - return_err!("We don't support MPP keysend payments", 0x4000|22, &[0;0]); - } else if let Some(data) = payment_data { - PendingHTLCRouting::Receive { - payment_data: data, - incoming_cltv_expiry: msg.cltv_expiry, - } - } else if let Some(payment_preimage) = keysend_preimage { - // We need to check that the sender knows the keysend preimage before processing this - // payment further. Otherwise, an intermediary routing hop forwarding non-keysend-HTLC X - // could discover the final destination of X, by probing the adjacent nodes on the route - // with a keysend payment of identical payment hash to X and observing the processing - // time discrepancies due to a hash collision with X. - let hashed_preimage = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner()); - if hashed_preimage != msg.payment_hash { - return_err!("Payment preimage didn't match payment hash", 0x4000|22, &[0;0]); - } + let outgoing_packet = msgs::OnionPacket { + version: 0, + public_key, + hop_data: new_packet_bytes, + hmac: next_hop_hmac.clone(), + }; - PendingHTLCRouting::ReceiveKeysend { - payment_preimage, - incoming_cltv_expiry: msg.cltv_expiry, - } - } else { - return_err!("We require payment_secrets", 0x4000|0x2000|3, &[0;0]); - } - }, - }; + let short_channel_id = match next_hop_data.format { + msgs::OnionHopDataFormat::Legacy { short_channel_id } => short_channel_id, + msgs::OnionHopDataFormat::NonFinalNode { short_channel_id } => short_channel_id, + msgs::OnionHopDataFormat::FinalNode { .. } => { + return_err!("Final Node OnionHopData provided for us as an intermediary node", 0x4000 | 22, &[0;0]); + }, + }; - // Note that we could obviously respond immediately with an update_fulfill_htlc - // message, however that would leak that we are the recipient of this payment, so - // instead we stay symmetric with the forwarding case, only responding (after a - // delay) once they've send us a commitment_signed! - - PendingHTLCStatus::Forward(PendingHTLCInfo { - routing, - payment_hash: msg.payment_hash.clone(), - incoming_shared_secret: shared_secret, - amt_to_forward: next_hop_data.amt_to_forward, - outgoing_cltv_value: next_hop_data.outgoing_cltv_value, - }) - } else { - let mut new_packet_data = [0; 20*65]; - let read_pos = chacha_stream.read(&mut new_packet_data).unwrap(); - #[cfg(debug_assertions)] - { - // Check two things: - // a) that the behavior of our stream here will return Ok(0) even if the TLV - // read above emptied out our buffer and the unwrap() wont needlessly panic - // b) that we didn't somehow magically end up with extra data. - let mut t = [0; 1]; - debug_assert!(chacha_stream.read(&mut t).unwrap() == 0); + PendingHTLCStatus::Forward(PendingHTLCInfo { + routing: PendingHTLCRouting::Forward { + onion_packet: outgoing_packet, + short_channel_id, + }, + payment_hash: msg.payment_hash.clone(), + incoming_shared_secret: shared_secret, + amt_to_forward: next_hop_data.amt_to_forward, + outgoing_cltv_value: next_hop_data.outgoing_cltv_value, + }) } - // Once we've emptied the set of bytes our peer gave us, encrypt 0 bytes until we - // fill the onion hop data we'll forward to our next-hop peer. - chacha_stream.chacha.process_in_place(&mut new_packet_data[read_pos..]); - - let mut new_pubkey = msg.onion_routing_packet.public_key.unwrap(); - - let blinding_factor = { - let mut sha = Sha256::engine(); - sha.input(&new_pubkey.serialize()[..]); - sha.input(&shared_secret); - Sha256::from_engine(sha).into_inner() - }; - - let public_key = if let Err(e) = new_pubkey.mul_assign(&self.secp_ctx, &blinding_factor[..]) { - Err(e) - } else { Ok(new_pubkey) }; - - let outgoing_packet = msgs::OnionPacket { - version: 0, - public_key, - hop_data: new_packet_data, - hmac: next_hop_hmac.clone(), - }; - - let short_channel_id = match next_hop_data.format { - msgs::OnionHopDataFormat::Legacy { short_channel_id } => short_channel_id, - msgs::OnionHopDataFormat::NonFinalNode { short_channel_id } => short_channel_id, - msgs::OnionHopDataFormat::FinalNode { .. } => { - return_err!("Final Node OnionHopData provided for us as an intermediary node", 0x4000 | 22, &[0;0]); - }, - }; - - PendingHTLCStatus::Forward(PendingHTLCInfo { - routing: PendingHTLCRouting::Forward { - onion_packet: outgoing_packet, - short_channel_id, - }, - payment_hash: msg.payment_hash.clone(), - incoming_shared_secret: shared_secret, - amt_to_forward: next_hop_data.amt_to_forward, - outgoing_cltv_value: next_hop_data.outgoing_cltv_value, - }) }; channel_state = Some(self.channel_state.lock().unwrap()); @@ -1936,48 +2297,59 @@ impl ChannelMana if let &PendingHTLCRouting::Forward { ref short_channel_id, .. } = routing { let id_option = channel_state.as_ref().unwrap().short_to_id.get(&short_channel_id).cloned(); if let Some((err, code, chan_update)) = loop { - let forwarding_id = match id_option { + let forwarding_id_opt = match id_option { None => { // unknown_next_peer - break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None)); + // Note that this is likely a timing oracle for detecting whether an scid is a + // phantom. + if fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, *short_channel_id) { + None + } else { + break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None)); + } }, - Some(id) => id.clone(), + Some(id) => Some(id.clone()), }; + let (chan_update_opt, forwardee_cltv_expiry_delta) = if let Some(forwarding_id) = forwarding_id_opt { + let chan = channel_state.as_mut().unwrap().by_id.get_mut(&forwarding_id).unwrap(); + // Leave channel updates as None for private channels. + let chan_update_opt = if chan.should_announce() { + Some(self.get_channel_update_for_unicast(chan).unwrap()) } else { None }; + if !chan.should_announce() && !self.default_configuration.accept_forwards_to_priv_channels { + // Note that the behavior here should be identical to the above block - we + // should NOT reveal the existence or non-existence of a private channel if + // we don't allow forwards outbound over them. + break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None)); + } - let chan = channel_state.as_mut().unwrap().by_id.get_mut(&forwarding_id).unwrap(); - - if !chan.should_announce() && !self.default_configuration.accept_forwards_to_priv_channels { - // Note that the behavior here should be identical to the above block - we - // should NOT reveal the existence or non-existence of a private channel if - // we don't allow forwards outbound over them. - break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None)); - } + // Note that we could technically not return an error yet here and just hope + // that the connection is reestablished or monitor updated by the time we get + // around to doing the actual forward, but better to fail early if we can and + // hopefully an attacker trying to path-trace payments cannot make this occur + // on a small/per-node/per-channel scale. + if !chan.is_live() { // channel_disabled + break Some(("Forwarding channel is not in a ready state.", 0x1000 | 20, chan_update_opt)); + } + if *amt_to_forward < chan.get_counterparty_htlc_minimum_msat() { // amount_below_minimum + break Some(("HTLC amount was below the htlc_minimum_msat", 0x1000 | 11, chan_update_opt)); + } + let fee = amt_to_forward.checked_mul(chan.get_fee_proportional_millionths() as u64) + .and_then(|prop_fee| { (prop_fee / 1000000) + .checked_add(chan.get_outbound_forwarding_fee_base_msat() as u64) }); + if fee.is_none() || msg.amount_msat < fee.unwrap() || (msg.amount_msat - fee.unwrap()) < *amt_to_forward { // fee_insufficient + break Some(("Prior hop has deviated from specified fees parameters or origin node has obsolete ones", 0x1000 | 12, chan_update_opt)); + } + (chan_update_opt, chan.get_cltv_expiry_delta()) + } else { (None, MIN_CLTV_EXPIRY_DELTA) }; - // Note that we could technically not return an error yet here and just hope - // that the connection is reestablished or monitor updated by the time we get - // around to doing the actual forward, but better to fail early if we can and - // hopefully an attacker trying to path-trace payments cannot make this occur - // on a small/per-node/per-channel scale. - if !chan.is_live() { // channel_disabled - break Some(("Forwarding channel is not in a ready state.", 0x1000 | 20, Some(self.get_channel_update_for_unicast(chan).unwrap()))); - } - if *amt_to_forward < chan.get_counterparty_htlc_minimum_msat() { // amount_below_minimum - break Some(("HTLC amount was below the htlc_minimum_msat", 0x1000 | 11, Some(self.get_channel_update_for_unicast(chan).unwrap()))); - } - let fee = amt_to_forward.checked_mul(chan.get_fee_proportional_millionths() as u64) - .and_then(|prop_fee| { (prop_fee / 1000000) - .checked_add(chan.get_outbound_forwarding_fee_base_msat() as u64) }); - if fee.is_none() || msg.amount_msat < fee.unwrap() || (msg.amount_msat - fee.unwrap()) < *amt_to_forward { // fee_insufficient - break Some(("Prior hop has deviated from specified fees parameters or origin node has obsolete ones", 0x1000 | 12, Some(self.get_channel_update_for_unicast(chan).unwrap()))); - } - if (msg.cltv_expiry as u64) < (*outgoing_cltv_value) as u64 + chan.get_cltv_expiry_delta() as u64 { // incorrect_cltv_expiry - break Some(("Forwarding node has tampered with the intended HTLC values or origin node has an obsolete cltv_expiry_delta", 0x1000 | 13, Some(self.get_channel_update_for_unicast(chan).unwrap()))); + if (msg.cltv_expiry as u64) < (*outgoing_cltv_value) as u64 + forwardee_cltv_expiry_delta as u64 { // incorrect_cltv_expiry + break Some(("Forwarding node has tampered with the intended HTLC values or origin node has an obsolete cltv_expiry_delta", 0x1000 | 13, chan_update_opt)); } let cur_height = self.best_block.read().unwrap().height() + 1; // Theoretically, channel counterparty shouldn't send us a HTLC expiring now, // but we want to be robust wrt to counterparty packet sanitization (see // HTLC_FAIL_BACK_BUFFER rationale). if msg.cltv_expiry <= cur_height + HTLC_FAIL_BACK_BUFFER as u32 { // expiry_too_soon - break Some(("CLTV expiry is too close", 0x1000 | 14, Some(self.get_channel_update_for_unicast(chan).unwrap()))); + break Some(("CLTV expiry is too close", 0x1000 | 14, chan_update_opt)); } if msg.cltv_expiry > cur_height + CLTV_FAR_FAR_AWAY as u32 { // expiry_too_far break Some(("CLTV expiry is too far in the future", 21, None)); @@ -1991,7 +2363,7 @@ impl ChannelMana // but there is no need to do that, and since we're a bit conservative with our // risk threshold it just results in failing to forward payments. if (*outgoing_cltv_value) as u64 <= (cur_height + LATENCY_GRACE_PERIOD_BLOCKS) as u64 { - break Some(("Outgoing CLTV value is too soon", 0x1000 | 14, Some(self.get_channel_update_for_unicast(chan).unwrap()))); + break Some(("Outgoing CLTV value is too soon", 0x1000 | 14, chan_update_opt)); } break None; @@ -2072,7 +2444,7 @@ impl ChannelMana } // Only public for testing, this should otherwise never be called direcly - pub(crate) fn send_payment_along_path(&self, path: &Vec, payee: &Option, payment_hash: &PaymentHash, payment_secret: &Option, total_value: u64, cur_height: u32, payment_id: PaymentId, keysend_preimage: &Option) -> Result<(), APIError> { + pub(crate) fn send_payment_along_path(&self, path: &Vec, payment_params: &Option, payment_hash: &PaymentHash, payment_secret: &Option, total_value: u64, cur_height: u32, payment_id: PaymentId, keysend_preimage: &Option) -> Result<(), APIError> { log_trace!(self.logger, "Attempting to send payment for path with next hop {}", path.first().unwrap().short_channel_id); let prng_seed = self.keys_manager.get_secure_random_bytes(); let session_priv_bytes = self.keys_manager.get_secure_random_bytes(); @@ -2137,7 +2509,7 @@ impl ChannelMana first_hop_htlc_msat: htlc_msat, payment_id, payment_secret: payment_secret.clone(), - payee: payee.clone(), + payment_params: payment_params.clone(), }, onion_packet, &self.logger), channel_state, chan) } { @@ -2266,7 +2638,7 @@ impl ChannelMana let cur_height = self.best_block.read().unwrap().height() + 1; let mut results = Vec::new(); for path in route.paths.iter() { - results.push(self.send_payment_along_path(&path, &route.payee, &payment_hash, payment_secret, total_value, cur_height, payment_id, &keysend_preimage)); + results.push(self.send_payment_along_path(&path, &route.payment_params, &payment_hash, payment_secret, total_value, cur_height, payment_id, &keysend_preimage)); } let mut has_ok = false; let mut has_err = false; @@ -2290,9 +2662,9 @@ impl ChannelMana results, payment_id, failed_paths_retry: if pending_amt_unsent != 0 { - if let Some(payee) = &route.payee { + if let Some(payment_params) = &route.payment_params { Some(RouteParameters { - payee: payee.clone(), + payment_params: payment_params.clone(), final_value_msat: pending_amt_unsent, final_cltv_expiry_delta: max_unsent_cltv_delta, }) @@ -2313,10 +2685,12 @@ impl ChannelMana /// /// Errors returned are a superset of those returned from [`send_payment`], so see /// [`send_payment`] documentation for more details on errors. This method will also error if the - /// retry amount puts the payment more than 10% over the payment's total amount, or if the payment - /// for the given `payment_id` cannot be found (likely due to timeout or success). + /// retry amount puts the payment more than 10% over the payment's total amount, if the payment + /// for the given `payment_id` cannot be found (likely due to timeout or success), or if + /// further retries have been disabled with [`abandon_payment`]. /// /// [`send_payment`]: [`ChannelManager::send_payment`] + /// [`abandon_payment`]: [`ChannelManager::abandon_payment`] pub fn retry_payment(&self, route: &Route, payment_id: PaymentId) -> Result<(), PaymentSendFailure> { const RETRY_OVERFLOW_PERCENTAGE: u64 = 10; for path in route.paths.iter() { @@ -2348,8 +2722,13 @@ impl ChannelMana })) }, PendingOutboundPayment::Fulfilled { .. } => { - return Err(PaymentSendFailure::ParameterError(APIError::RouteError { - err: "Payment already completed" + return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError { + err: "Payment already completed".to_owned() + })); + }, + PendingOutboundPayment::Abandoned { .. } => { + return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError { + err: "Payment already abandoned (with some HTLCs still pending)".to_owned() })); }, } @@ -2362,6 +2741,37 @@ impl ChannelMana return self.send_payment_internal(route, payment_hash, &payment_secret, None, Some(payment_id), Some(total_msat)).map(|_| ()) } + /// Signals that no further retries for the given payment will occur. + /// + /// After this method returns, any future calls to [`retry_payment`] for the given `payment_id` + /// will fail with [`PaymentSendFailure::ParameterError`]. If no such event has been generated, + /// an [`Event::PaymentFailed`] event will be generated as soon as there are no remaining + /// pending HTLCs for this payment. + /// + /// Note that calling this method does *not* prevent a payment from succeeding. You must still + /// wait until you receive either a [`Event::PaymentFailed`] or [`Event::PaymentSent`] event to + /// determine the ultimate status of a payment. + /// + /// [`retry_payment`]: Self::retry_payment + /// [`Event::PaymentFailed`]: events::Event::PaymentFailed + /// [`Event::PaymentSent`]: events::Event::PaymentSent + pub fn abandon_payment(&self, payment_id: PaymentId) { + let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier); + + let mut outbounds = self.pending_outbound_payments.lock().unwrap(); + if let hash_map::Entry::Occupied(mut payment) = outbounds.entry(payment_id) { + if let Ok(()) = payment.get_mut().mark_abandoned() { + if payment.get().remaining_parts() == 0 { + self.pending_events.lock().unwrap().push(events::Event::PaymentFailed { + payment_id, + payment_hash: payment.get().payment_hash().expect("PendingOutboundPayments::RetriesExceeded always has a payment hash set"), + }); + payment.remove(); + } + } + } + } + /// Send a spontaneous payment, which is a payment that does not require the recipient to have /// generated an invoice. Optionally, you may specify the preimage. If you do choose to specify /// the preimage, it must be a cryptographically secure random value that no intermediate node @@ -2443,7 +2853,8 @@ impl ChannelMana /// Returns an [`APIError::APIMisuseError`] if the funding_transaction spent non-SegWit outputs /// or if no output was found which matches the parameters in [`Event::FundingGenerationReady`]. /// - /// Panics if a funding transaction has already been provided for this channel. + /// Returns [`APIError::ChannelUnavailable`] if a funding transaction has already been provided + /// for the channel or if the channel has been closed as indicated by [`Event::ChannelClosed`]. /// /// May panic if the output found in the funding transaction is duplicative with some other /// channel (note that this should be trivially prevented by using unique funding transaction @@ -2458,6 +2869,7 @@ impl ChannelMana /// create a new channel with a conflicting funding transaction. /// /// [`Event::FundingGenerationReady`]: crate::util::events::Event::FundingGenerationReady + /// [`Event::ChannelClosed`]: crate::util::events::Event::ChannelClosed pub fn funding_transaction_generated(&self, temporary_channel_id: &[u8; 32], funding_transaction: Transaction) -> Result<(), APIError> { let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier); @@ -2495,27 +2907,6 @@ impl ChannelMana }) } - fn get_announcement_sigs(&self, chan: &Channel) -> Option { - if !chan.should_announce() { - log_trace!(self.logger, "Can't send announcement_signatures for private channel {}", log_bytes!(chan.channel_id())); - return None - } - - let (announcement, our_bitcoin_sig) = match chan.get_channel_announcement(self.get_our_node_id(), self.genesis_hash.clone()) { - Ok(res) => res, - Err(_) => return None, // Only in case of state precondition violations eg channel is closing - }; - let msghash = hash_to_message!(&Sha256dHash::hash(&announcement.encode()[..])[..]); - let our_node_sig = self.secp_ctx.sign(&msghash, &self.our_network_key); - - Some(msgs::AnnouncementSignatures { - channel_id: chan.channel_id(), - short_channel_id: chan.get_short_channel_id().unwrap(), - node_signature: our_node_sig, - bitcoin_signature: our_bitcoin_sig, - }) - } - #[allow(dead_code)] // Messages of up to 64KB should never end up more than half full with addresses, as that would // be absurd. We ensure this by checking that at least 500 (our stated public contract on when @@ -2573,7 +2964,7 @@ impl ChannelMana let mut announced_chans = false; for (_, chan) in channel_state.by_id.iter() { - if let Some(msg) = chan.get_signed_channel_announcement(&self.our_network_key, self.get_our_node_id(), self.genesis_hash.clone()) { + if let Some(msg) = chan.get_signed_channel_announcement(self.get_our_node_id(), self.genesis_hash.clone(), self.best_block.read().unwrap().height()) { channel_state.pending_msg_events.push(events::MessageSendEvent::BroadcastChannelAnnouncement { msg, update_msg: match self.get_channel_update_for_broadcast(chan) { @@ -2608,6 +2999,7 @@ impl ChannelMana let mut new_events = Vec::new(); let mut failed_forwards = Vec::new(); + let mut phantom_receives: Vec<(u64, OutPoint, Vec<(PendingHTLCInfo, u64)>)> = Vec::new(); let mut handle_errors = Vec::new(); { let mut channel_state_lock = self.channel_state.lock().unwrap(); @@ -2618,21 +3010,67 @@ impl ChannelMana let forward_chan_id = match channel_state.short_to_id.get(&short_chan_id) { Some(chan_id) => chan_id.clone(), None => { - failed_forwards.reserve(pending_forwards.len()); for forward_info in pending_forwards.drain(..) { match forward_info { - HTLCForwardInfo::AddHTLC { prev_short_channel_id, prev_htlc_id, forward_info, - prev_funding_outpoint } => { - let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData { - short_channel_id: prev_short_channel_id, - outpoint: prev_funding_outpoint, - htlc_id: prev_htlc_id, - incoming_packet_shared_secret: forward_info.incoming_shared_secret, - }); - failed_forwards.push((htlc_source, forward_info.payment_hash, - HTLCFailReason::Reason { failure_code: 0x4000 | 10, data: Vec::new() } - )); - }, + HTLCForwardInfo::AddHTLC { prev_short_channel_id, prev_htlc_id, forward_info: PendingHTLCInfo { + routing, incoming_shared_secret, payment_hash, amt_to_forward, outgoing_cltv_value }, + prev_funding_outpoint } => { + macro_rules! fail_forward { + ($msg: expr, $err_code: expr, $err_data: expr, $phantom_ss: expr) => { + { + log_info!(self.logger, "Failed to accept/forward incoming HTLC: {}", $msg); + let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData { + short_channel_id: prev_short_channel_id, + outpoint: prev_funding_outpoint, + htlc_id: prev_htlc_id, + incoming_packet_shared_secret: incoming_shared_secret, + phantom_shared_secret: $phantom_ss, + }); + failed_forwards.push((htlc_source, payment_hash, + HTLCFailReason::Reason { failure_code: $err_code, data: $err_data } + )); + continue; + } + } + } + if let PendingHTLCRouting::Forward { onion_packet, .. } = routing { + let phantom_secret_res = self.keys_manager.get_node_secret(Recipient::PhantomNode); + if phantom_secret_res.is_ok() && fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, short_chan_id) { + let phantom_shared_secret = { + let mut arr = [0; 32]; + arr.copy_from_slice(&SharedSecret::new(&onion_packet.public_key.unwrap(), &phantom_secret_res.unwrap())[..]); + arr + }; + let next_hop = match onion_utils::decode_next_hop(phantom_shared_secret, &onion_packet.hop_data, onion_packet.hmac, payment_hash) { + Ok(res) => res, + Err(onion_utils::OnionDecodeErr::Malformed { err_msg, err_code }) => { + let sha256_of_onion = Sha256::hash(&onion_packet.hop_data).into_inner(); + // In this scenario, the phantom would have sent us an + // `update_fail_malformed_htlc`, meaning here we encrypt the error as + // if it came from us (the second-to-last hop) but contains the sha256 + // of the onion. + fail_forward!(err_msg, err_code, sha256_of_onion.to_vec(), None); + }, + Err(onion_utils::OnionDecodeErr::Relay { err_msg, err_code }) => { + fail_forward!(err_msg, err_code, Vec::new(), Some(phantom_shared_secret)); + }, + }; + match next_hop { + onion_utils::Hop::Receive(hop_data) => { + match self.construct_recv_pending_htlc_info(hop_data, incoming_shared_secret, payment_hash, amt_to_forward, outgoing_cltv_value, Some(phantom_shared_secret)) { + Ok(info) => phantom_receives.push((prev_short_channel_id, prev_funding_outpoint, vec![(info, prev_htlc_id)])), + Err(ReceiveError { err_code, err_data, msg }) => fail_forward!(msg, err_code, err_data, Some(phantom_shared_secret)) + } + }, + _ => panic!(), + } + } else { + fail_forward!(format!("Unknown short channel id {} for forward HTLC", short_chan_id), 0x4000 | 10, Vec::new(), None); + } + } else { + fail_forward!(format!("Unknown short channel id {} for forward HTLC", short_chan_id), 0x4000 | 10, Vec::new(), None); + } + }, HTLCForwardInfo::FailHTLC { .. } => { // Channel went away before we could fail it. This implies // the channel is now on chain and our counterparty is @@ -2660,6 +3098,8 @@ impl ChannelMana outpoint: prev_funding_outpoint, htlc_id: prev_htlc_id, incoming_packet_shared_secret: incoming_shared_secret, + // Phantom payments are only PendingHTLCRouting::Receive. + phantom_shared_secret: None, }); match chan.get_mut().send_htlc(amt_to_forward, payment_hash, outgoing_cltv_value, htlc_source.clone(), onion_packet, &self.logger) { Err(e) => { @@ -2776,11 +3216,11 @@ impl ChannelMana HTLCForwardInfo::AddHTLC { prev_short_channel_id, prev_htlc_id, forward_info: PendingHTLCInfo { routing, incoming_shared_secret, payment_hash, amt_to_forward, .. }, prev_funding_outpoint } => { - let (cltv_expiry, onion_payload) = match routing { - PendingHTLCRouting::Receive { payment_data, incoming_cltv_expiry } => - (incoming_cltv_expiry, OnionPayload::Invoice(payment_data)), + let (cltv_expiry, onion_payload, phantom_shared_secret) = match routing { + PendingHTLCRouting::Receive { payment_data, incoming_cltv_expiry, phantom_shared_secret } => + (incoming_cltv_expiry, OnionPayload::Invoice(payment_data), phantom_shared_secret), PendingHTLCRouting::ReceiveKeysend { payment_preimage, incoming_cltv_expiry } => - (incoming_cltv_expiry, OnionPayload::Spontaneous(payment_preimage)), + (incoming_cltv_expiry, OnionPayload::Spontaneous(payment_preimage), None), _ => { panic!("short_channel_id == 0 should imply any pending_forward entries are of type Receive"); } @@ -2791,6 +3231,7 @@ impl ChannelMana outpoint: prev_funding_outpoint, htlc_id: prev_htlc_id, incoming_packet_shared_secret: incoming_shared_secret, + phantom_shared_secret, }, value: amt_to_forward, cltv_expiry, @@ -2808,12 +3249,65 @@ impl ChannelMana outpoint: prev_funding_outpoint, htlc_id: $htlc.prev_hop.htlc_id, incoming_packet_shared_secret: $htlc.prev_hop.incoming_packet_shared_secret, + phantom_shared_secret, }), payment_hash, HTLCFailReason::Reason { failure_code: 0x4000 | 15, data: htlc_msat_height_data } )); } } + macro_rules! check_total_value { + ($payment_data_total_msat: expr, $payment_secret: expr, $payment_preimage: expr) => {{ + let mut payment_received_generated = false; + let htlcs = channel_state.claimable_htlcs.entry(payment_hash) + .or_insert(Vec::new()); + if htlcs.len() == 1 { + if let OnionPayload::Spontaneous(_) = htlcs[0].onion_payload { + log_trace!(self.logger, "Failing new HTLC with payment_hash {} as we already had an existing keysend HTLC with the same payment hash", log_bytes!(payment_hash.0)); + fail_htlc!(claimable_htlc); + continue + } + } + let mut total_value = claimable_htlc.value; + for htlc in htlcs.iter() { + total_value += htlc.value; + match &htlc.onion_payload { + OnionPayload::Invoice(htlc_payment_data) => { + if htlc_payment_data.total_msat != $payment_data_total_msat { + log_trace!(self.logger, "Failing HTLCs with payment_hash {} as the HTLCs had inconsistent total values (eg {} and {})", + log_bytes!(payment_hash.0), $payment_data_total_msat, htlc_payment_data.total_msat); + total_value = msgs::MAX_VALUE_MSAT; + } + if total_value >= msgs::MAX_VALUE_MSAT { break; } + }, + _ => unreachable!(), + } + } + if total_value >= msgs::MAX_VALUE_MSAT || total_value > $payment_data_total_msat { + log_trace!(self.logger, "Failing HTLCs with payment_hash {} as the total value {} ran over expected value {} (or HTLCs were inconsistent)", + log_bytes!(payment_hash.0), total_value, $payment_data_total_msat); + fail_htlc!(claimable_htlc); + } else if total_value == $payment_data_total_msat { + htlcs.push(claimable_htlc); + new_events.push(events::Event::PaymentReceived { + payment_hash, + purpose: events::PaymentPurpose::InvoicePayment { + payment_preimage: $payment_preimage, + payment_secret: $payment_secret, + }, + amt: total_value, + }); + payment_received_generated = true; + } else { + // Nothing to do - we haven't reached the total + // payment value yet, wait until we receive more + // MPP parts. + htlcs.push(claimable_htlc); + } + payment_received_generated + }} + } + // Check that the payment hash and secret are known. Note that we // MUST take care to handle the "unknown payment hash" and // "incorrect payment secret" cases here identically or we'd expose @@ -2824,9 +3318,17 @@ impl ChannelMana match payment_secrets.entry(payment_hash) { hash_map::Entry::Vacant(_) => { match claimable_htlc.onion_payload { - OnionPayload::Invoice(_) => { - log_trace!(self.logger, "Failing new HTLC with payment_hash {} as we didn't have a corresponding inbound payment.", log_bytes!(payment_hash.0)); - fail_htlc!(claimable_htlc); + OnionPayload::Invoice(ref payment_data) => { + let payment_preimage = match inbound_payment::verify(payment_hash, payment_data.clone(), self.highest_seen_timestamp.load(Ordering::Acquire) as u64, &self.inbound_payment_key, &self.logger) { + Ok(payment_preimage) => payment_preimage, + Err(()) => { + fail_htlc!(claimable_htlc); + continue + } + }; + let payment_data_total_msat = payment_data.total_msat; + let payment_secret = payment_data.payment_secret.clone(); + check_total_value!(payment_data_total_msat, payment_secret, payment_preimage); }, OnionPayload::Spontaneous(preimage) => { match channel_state.claimable_htlcs.entry(payment_hash) { @@ -2863,54 +3365,9 @@ impl ChannelMana log_bytes!(payment_hash.0), payment_data.total_msat, inbound_payment.get().min_value_msat.unwrap()); fail_htlc!(claimable_htlc); } else { - let mut total_value = 0; - let htlcs = channel_state.claimable_htlcs.entry(payment_hash) - .or_insert(Vec::new()); - if htlcs.len() == 1 { - if let OnionPayload::Spontaneous(_) = htlcs[0].onion_payload { - log_trace!(self.logger, "Failing new HTLC with payment_hash {} as we already had an existing keysend HTLC with the same payment hash", log_bytes!(payment_hash.0)); - fail_htlc!(claimable_htlc); - continue - } - } - htlcs.push(claimable_htlc); - for htlc in htlcs.iter() { - total_value += htlc.value; - match &htlc.onion_payload { - OnionPayload::Invoice(htlc_payment_data) => { - if htlc_payment_data.total_msat != payment_data.total_msat { - log_trace!(self.logger, "Failing HTLCs with payment_hash {} as the HTLCs had inconsistent total values (eg {} and {})", - log_bytes!(payment_hash.0), payment_data.total_msat, htlc_payment_data.total_msat); - total_value = msgs::MAX_VALUE_MSAT; - } - if total_value >= msgs::MAX_VALUE_MSAT { break; } - }, - _ => unreachable!(), - } - } - if total_value >= msgs::MAX_VALUE_MSAT || total_value > payment_data.total_msat { - log_trace!(self.logger, "Failing HTLCs with payment_hash {} as the total value {} ran over expected value {} (or HTLCs were inconsistent)", - log_bytes!(payment_hash.0), total_value, payment_data.total_msat); - for htlc in htlcs.iter() { - fail_htlc!(htlc); - } - } else if total_value == payment_data.total_msat { - new_events.push(events::Event::PaymentReceived { - payment_hash, - purpose: events::PaymentPurpose::InvoicePayment { - payment_preimage: inbound_payment.get().payment_preimage, - payment_secret: payment_data.payment_secret, - }, - amt: total_value, - }); - // Only ever generate at most one PaymentReceived - // per registered payment_hash, even if it isn't - // claimed. + let payment_received_generated = check_total_value!(payment_data.total_msat, payment_data.payment_secret, inbound_payment.get().payment_preimage); + if payment_received_generated { inbound_payment.remove_entry(); - } else { - // Nothing to do - we haven't reached the total - // payment value yet, wait until we receive more - // MPP parts. } } }, @@ -2928,6 +3385,7 @@ impl ChannelMana for (htlc_source, payment_hash, failure_reason) in failed_forwards.drain(..) { self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), htlc_source, &payment_hash, failure_reason); } + self.forward_htlcs(&mut phantom_receives); for (counterparty_node_id, err) in handle_errors.drain(..) { let _ = handle_error!(self, err, counterparty_node_id); @@ -3173,36 +3631,42 @@ impl ChannelMana self.fail_htlc_backwards_internal(channel_state, htlc_src, &payment_hash, HTLCFailReason::Reason { failure_code, data: onion_failure_data}); }, - HTLCSource::OutboundRoute { session_priv, payment_id, path, payee, .. } => { + HTLCSource::OutboundRoute { session_priv, payment_id, path, payment_params, .. } => { let mut session_priv_bytes = [0; 32]; session_priv_bytes.copy_from_slice(&session_priv[..]); let mut outbounds = self.pending_outbound_payments.lock().unwrap(); if let hash_map::Entry::Occupied(mut payment) = outbounds.entry(payment_id) { if payment.get_mut().remove(&session_priv_bytes, Some(&path)) && !payment.get().is_fulfilled() { - let retry = if let Some(payee_data) = payee { + let retry = if let Some(payment_params_data) = payment_params { let path_last_hop = path.last().expect("Outbound payments must have had a valid path"); Some(RouteParameters { - payee: payee_data, + payment_params: payment_params_data, final_value_msat: path_last_hop.fee_msat, final_cltv_expiry_delta: path_last_hop.cltv_expiry_delta, }) } else { None }; - self.pending_events.lock().unwrap().push( - events::Event::PaymentPathFailed { - payment_id: Some(payment_id), - payment_hash, - rejected_by_dest: false, - network_update: None, - all_paths_failed: payment.get().remaining_parts() == 0, - path: path.clone(), - short_channel_id: None, - retry, - #[cfg(test)] - error_code: None, - #[cfg(test)] - error_data: None, - } - ); + let mut pending_events = self.pending_events.lock().unwrap(); + pending_events.push(events::Event::PaymentPathFailed { + payment_id: Some(payment_id), + payment_hash, + rejected_by_dest: false, + network_update: None, + all_paths_failed: payment.get().remaining_parts() == 0, + path: path.clone(), + short_channel_id: None, + retry, + #[cfg(test)] + error_code: None, + #[cfg(test)] + error_data: None, + }); + if payment.get().abandoned() && payment.get().remaining_parts() == 0 { + pending_events.push(events::Event::PaymentFailed { + payment_id, + payment_hash: payment.get().payment_hash().expect("PendingOutboundPayments::RetriesExceeded always has a payment hash set"), + }); + payment.remove(); + } } } else { log_trace!(self.logger, "Received duplicative fail for HTLC with payment_hash {}", log_bytes!(payment_hash.0)); @@ -3228,11 +3692,12 @@ impl ChannelMana // from block_connected which may run during initialization prior to the chain_monitor // being fully configured. See the docs for `ChannelManagerReadArgs` for more. match source { - HTLCSource::OutboundRoute { ref path, session_priv, payment_id, ref payee, .. } => { + HTLCSource::OutboundRoute { ref path, session_priv, payment_id, ref payment_params, .. } => { let mut session_priv_bytes = [0; 32]; session_priv_bytes.copy_from_slice(&session_priv[..]); let mut outbounds = self.pending_outbound_payments.lock().unwrap(); let mut all_paths_failed = false; + let mut full_failure_ev = None; if let hash_map::Entry::Occupied(mut payment) = outbounds.entry(payment_id) { if !payment.get_mut().remove(&session_priv_bytes, Some(&path)) { log_trace!(self.logger, "Received duplicative fail for HTLC with payment_hash {}", log_bytes!(payment_hash.0)); @@ -3244,22 +3709,30 @@ impl ChannelMana } if payment.get().remaining_parts() == 0 { all_paths_failed = true; + if payment.get().abandoned() { + full_failure_ev = Some(events::Event::PaymentFailed { + payment_id, + payment_hash: payment.get().payment_hash().expect("PendingOutboundPayments::RetriesExceeded always has a payment hash set"), + }); + payment.remove(); + } } } else { log_trace!(self.logger, "Received duplicative fail for HTLC with payment_hash {}", log_bytes!(payment_hash.0)); return; } mem::drop(channel_state_lock); - let retry = if let Some(payee_data) = payee { + let retry = if let Some(payment_params_data) = payment_params { let path_last_hop = path.last().expect("Outbound payments must have had a valid path"); Some(RouteParameters { - payee: payee_data.clone(), + payment_params: payment_params_data.clone(), final_value_msat: path_last_hop.fee_msat, final_cltv_expiry_delta: path_last_hop.cltv_expiry_delta, }) } else { None }; log_trace!(self.logger, "Failing outbound payment HTLC with payment_hash {}", log_bytes!(payment_hash.0)); - match &onion_error { + + let path_failure = match &onion_error { &HTLCFailReason::LightningError { ref err } => { #[cfg(test)] let (network_update, short_channel_id, payment_retryable, onion_error_code, onion_error_data) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone()); @@ -3268,22 +3741,20 @@ impl ChannelMana // TODO: If we decided to blame ourselves (or one of our channels) in // process_onion_failure we should close that channel as it implies our // next-hop is needlessly blaming us! - self.pending_events.lock().unwrap().push( - events::Event::PaymentPathFailed { - payment_id: Some(payment_id), - payment_hash: payment_hash.clone(), - rejected_by_dest: !payment_retryable, - network_update, - all_paths_failed, - path: path.clone(), - short_channel_id, - retry, + events::Event::PaymentPathFailed { + payment_id: Some(payment_id), + payment_hash: payment_hash.clone(), + rejected_by_dest: !payment_retryable, + network_update, + all_paths_failed, + path: path.clone(), + short_channel_id, + retry, #[cfg(test)] - error_code: onion_error_code, + error_code: onion_error_code, #[cfg(test)] - error_data: onion_error_data - } - ); + error_data: onion_error_data + } }, &HTLCFailReason::Reason { #[cfg(test)] @@ -3298,31 +3769,38 @@ impl ChannelMana // ChannelDetails. // TODO: For non-temporary failures, we really should be closing the // channel here as we apparently can't relay through them anyway. - self.pending_events.lock().unwrap().push( - events::Event::PaymentPathFailed { - payment_id: Some(payment_id), - payment_hash: payment_hash.clone(), - rejected_by_dest: path.len() == 1, - network_update: None, - all_paths_failed, - path: path.clone(), - short_channel_id: Some(path.first().unwrap().short_channel_id), - retry, + events::Event::PaymentPathFailed { + payment_id: Some(payment_id), + payment_hash: payment_hash.clone(), + rejected_by_dest: path.len() == 1, + network_update: None, + all_paths_failed, + path: path.clone(), + short_channel_id: Some(path.first().unwrap().short_channel_id), + retry, #[cfg(test)] - error_code: Some(*failure_code), + error_code: Some(*failure_code), #[cfg(test)] - error_data: Some(data.clone()), - } - ); + error_data: Some(data.clone()), + } } - } + }; + let mut pending_events = self.pending_events.lock().unwrap(); + pending_events.push(path_failure); + if let Some(ev) = full_failure_ev { pending_events.push(ev); } }, - HTLCSource::PreviousHopData(HTLCPreviousHopData { short_channel_id, htlc_id, incoming_packet_shared_secret, .. }) => { + HTLCSource::PreviousHopData(HTLCPreviousHopData { short_channel_id, htlc_id, incoming_packet_shared_secret, phantom_shared_secret, .. }) => { let err_packet = match onion_error { HTLCFailReason::Reason { failure_code, data } => { log_trace!(self.logger, "Failing HTLC with payment_hash {} backwards from us with code {}", log_bytes!(payment_hash.0), failure_code); - let packet = onion_utils::build_failure_packet(&incoming_packet_shared_secret, failure_code, &data[..]).encode(); - onion_utils::encrypt_failure_packet(&incoming_packet_shared_secret, &packet) + if let Some(phantom_ss) = phantom_shared_secret { + let phantom_packet = onion_utils::build_failure_packet(&phantom_ss, failure_code, &data[..]).encode(); + let encrypted_phantom_packet = onion_utils::encrypt_failure_packet(&phantom_ss, &phantom_packet); + onion_utils::encrypt_failure_packet(&incoming_packet_shared_secret, &encrypted_phantom_packet.data[..]) + } else { + let packet = onion_utils::build_failure_packet(&incoming_packet_shared_secret, failure_code, &data[..]).encode(); + onion_utils::encrypt_failure_packet(&incoming_packet_shared_secret, &packet) + } }, HTLCFailReason::LightningError { err } => { log_trace!(self.logger, "Failing HTLC with payment_hash {} backwards with pre-built LightningError", log_bytes!(payment_hash.0)); @@ -3353,19 +3831,21 @@ impl ChannelMana } } - /// Provides a payment preimage in response to a PaymentReceived event, returning true and - /// generating message events for the net layer to claim the payment, if possible. Thus, you - /// should probably kick the net layer to go send messages if this returns true! + /// Provides a payment preimage in response to [`Event::PaymentReceived`], generating any + /// [`MessageSendEvent`]s needed to claim the payment. /// /// Note that if you did not set an `amount_msat` when calling [`create_inbound_payment`] or /// [`create_inbound_payment_for_hash`] you must check that the amount in the `PaymentReceived` /// event matches your expectation. If you fail to do so and call this method, you may provide /// the sender "proof-of-payment" when they did not fulfill the full expected payment. /// - /// May panic if called except in response to a PaymentReceived event. + /// Returns whether any HTLCs were claimed, and thus if any new [`MessageSendEvent`]s are now + /// pending for processing via [`get_and_clear_pending_msg_events`]. /// + /// [`Event::PaymentReceived`]: crate::util::events::Event::PaymentReceived /// [`create_inbound_payment`]: Self::create_inbound_payment /// [`create_inbound_payment_for_hash`]: Self::create_inbound_payment_for_hash + /// [`get_and_clear_pending_msg_events`]: MessageSendEventsProvider::get_and_clear_pending_msg_events pub fn claim_funds(&self, payment_preimage: PaymentPreimage) -> bool { let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner()); @@ -3503,12 +3983,12 @@ impl ChannelMana } fn finalize_claims(&self, mut sources: Vec) { + let mut outbounds = self.pending_outbound_payments.lock().unwrap(); let mut pending_events = self.pending_events.lock().unwrap(); for source in sources.drain(..) { if let HTLCSource::OutboundRoute { session_priv, payment_id, path, .. } = source { let mut session_priv_bytes = [0; 32]; session_priv_bytes.copy_from_slice(&session_priv[..]); - let mut outbounds = self.pending_outbound_payments.lock().unwrap(); if let hash_map::Entry::Occupied(mut payment) = outbounds.entry(payment_id) { assert!(payment.get().is_fulfilled()); if payment.get_mut().remove(&session_priv_bytes, None) { @@ -3649,18 +4129,19 @@ impl ChannelMana return; } - let updates = channel.get_mut().monitor_updating_restored(&self.logger); - let channel_update = if updates.funding_locked.is_some() && channel.get().is_usable() && !channel.get().should_announce() { + let updates = channel.get_mut().monitor_updating_restored(&self.logger, self.get_our_node_id(), self.genesis_hash, self.best_block.read().unwrap().height()); + let channel_update = if updates.funding_locked.is_some() && channel.get().is_usable() { // We only send a channel_update in the case where we are just now sending a - // funding_locked and the channel is in a usable state. Further, we rely on the - // normal announcement_signatures process to send a channel_update for public - // channels, only generating a unicast channel_update if this is a private channel. + // funding_locked and the channel is in a usable state. We may re-send a + // channel_update later through the announcement_signatures process for public + // channels, but there's no reason not to just inform our counterparty of our fees + // now. Some(events::MessageSendEvent::SendChannelUpdate { node_id: channel.get().get_counterparty_node_id(), msg: self.get_channel_update_for_unicast(channel.get()).unwrap(), }) } else { None }; - chan_restoration_res = handle_chan_restoration_locked!(self, channel_lock, channel_state, channel, updates.raa, updates.commitment_update, updates.order, None, updates.accepted_htlcs, updates.funding_broadcastable, updates.funding_locked); + chan_restoration_res = handle_chan_restoration_locked!(self, channel_lock, channel_state, channel, updates.raa, updates.commitment_update, updates.order, None, updates.accepted_htlcs, updates.funding_broadcastable, updates.funding_locked, updates.announcement_sigs); if let Some(upd) = channel_update { channel_state.pending_msg_events.push(upd); } @@ -3673,6 +4154,34 @@ impl ChannelMana } } + /// Called to accept a request to open a channel after [`Event::OpenChannelRequest`] has been + /// triggered. + /// + /// The `temporary_channel_id` parameter indicates which inbound channel should be accepted. + /// + /// [`Event::OpenChannelRequest`]: crate::util::events::Event::OpenChannelRequest + pub fn accept_inbound_channel(&self, temporary_channel_id: &[u8; 32]) -> Result<(), APIError> { + let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier); + + let mut channel_state_lock = self.channel_state.lock().unwrap(); + let channel_state = &mut *channel_state_lock; + match channel_state.by_id.entry(temporary_channel_id.clone()) { + hash_map::Entry::Occupied(mut channel) => { + if !channel.get().inbound_is_awaiting_accept() { + return Err(APIError::APIMisuseError { err: "The channel isn't currently awaiting to be accepted.".to_owned() }); + } + channel_state.pending_msg_events.push(events::MessageSendEvent::SendAcceptChannel { + node_id: channel.get().get_counterparty_node_id(), + msg: channel.get_mut().accept_inbound_channel(), + }); + } + hash_map::Entry::Vacant(_) => { + return Err(APIError::ChannelUnavailable { err: "Can't accept a channel that doesn't exist".to_owned() }); + } + } + Ok(()) + } + fn internal_open_channel(&self, counterparty_node_id: &PublicKey, their_features: InitFeatures, msg: &msgs::OpenChannel) -> Result<(), MsgHandleErrInternal> { if msg.chain_hash != self.genesis_hash { return Err(MsgHandleErrInternal::send_err_msg_no_close("Unknown genesis block hash".to_owned(), msg.temporary_channel_id.clone())); @@ -3682,7 +4191,7 @@ impl ChannelMana return Err(MsgHandleErrInternal::send_err_msg_no_close("No inbound channels accepted".to_owned(), msg.temporary_channel_id.clone())); } - let channel = Channel::new_from_req(&self.fee_estimator, &self.keys_manager, counterparty_node_id.clone(), + let mut channel = Channel::new_from_req(&self.fee_estimator, &self.keys_manager, counterparty_node_id.clone(), &their_features, msg, 0, &self.default_configuration, self.best_block.read().unwrap().height(), &self.logger) .map_err(|e| MsgHandleErrInternal::from_chan_no_close(e, msg.temporary_channel_id))?; let mut channel_state_lock = self.channel_state.lock().unwrap(); @@ -3690,10 +4199,23 @@ impl ChannelMana match channel_state.by_id.entry(channel.channel_id()) { hash_map::Entry::Occupied(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("temporary_channel_id collision!".to_owned(), msg.temporary_channel_id.clone())), hash_map::Entry::Vacant(entry) => { - channel_state.pending_msg_events.push(events::MessageSendEvent::SendAcceptChannel { - node_id: counterparty_node_id.clone(), - msg: channel.get_accept_channel(), - }); + if !self.default_configuration.manually_accept_inbound_channels { + channel_state.pending_msg_events.push(events::MessageSendEvent::SendAcceptChannel { + node_id: counterparty_node_id.clone(), + msg: channel.accept_inbound_channel(), + }); + } else { + let mut pending_events = self.pending_events.lock().unwrap(); + pending_events.push( + events::Event::OpenChannelRequest { + temporary_channel_id: msg.temporary_channel_id.clone(), + counterparty_node_id: counterparty_node_id.clone(), + funding_satoshis: msg.funding_satoshis, + push_msat: msg.push_msat, + } + ); + } + entry.insert(channel); } } @@ -3709,7 +4231,7 @@ impl ChannelMana if chan.get().get_counterparty_node_id() != *counterparty_node_id { return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.temporary_channel_id)); } - try_chan_entry!(self, chan.get_mut().accept_channel(&msg, &self.default_configuration, &their_features), channel_state, chan); + try_chan_entry!(self, chan.get_mut().accept_channel(&msg, &self.default_configuration.peer_channel_config_limits, &their_features), channel_state, chan); (chan.get().get_value_satoshis(), chan.get().get_funding_redeemscript().to_v0_p2wsh(), chan.get().get_user_id()) }, hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel".to_owned(), msg.temporary_channel_id)) @@ -3826,23 +4348,21 @@ impl ChannelMana if chan.get().get_counterparty_node_id() != *counterparty_node_id { return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.channel_id)); } - try_chan_entry!(self, chan.get_mut().funding_locked(&msg, &self.logger), channel_state, chan); - if let Some(announcement_sigs) = self.get_announcement_sigs(chan.get()) { - log_trace!(self.logger, "Sending announcement_signatures for {} in response to funding_locked", log_bytes!(chan.get().channel_id())); - // If we see locking block before receiving remote funding_locked, we broadcast our - // announcement_sigs at remote funding_locked reception. If we receive remote - // funding_locked before seeing locking block, we broadcast our announcement_sigs at locking - // block connection. We should guanrantee to broadcast announcement_sigs to our peer whatever - // the order of the events but our peer may not receive it due to disconnection. The specs - // lacking an acknowledgement for announcement_sigs we may have to re-send them at peer - // connection in the future if simultaneous misses by both peers due to network/hardware - // failures is an issue. Note, to achieve its goal, only one of the announcement_sigs needs - // to be received, from then sigs are going to be flood to the whole network. + let announcement_sigs_opt = try_chan_entry!(self, chan.get_mut().funding_locked(&msg, self.get_our_node_id(), + self.genesis_hash.clone(), &self.best_block.read().unwrap(), &self.logger), channel_state, chan); + if let Some(announcement_sigs) = announcement_sigs_opt { + log_trace!(self.logger, "Sending announcement_signatures for channel {}", log_bytes!(chan.get().channel_id())); channel_state.pending_msg_events.push(events::MessageSendEvent::SendAnnouncementSignatures { node_id: counterparty_node_id.clone(), msg: announcement_sigs, }); } else if chan.get().is_usable() { + // If we're sending an announcement_signatures, we'll send the (public) + // channel_update after sending a channel_announcement when we receive our + // counterparty's announcement_signatures. Thus, we only bother to send a + // channel_update here if the channel is not public, i.e. we're not sending an + // announcement_signatures. + log_trace!(self.logger, "Sending private initial channel_update for our counterparty on channel {}", log_bytes!(chan.get().channel_id())); channel_state.pending_msg_events.push(events::MessageSendEvent::SendChannelUpdate { node_id: counterparty_node_id.clone(), msg: self.get_channel_update_for_unicast(chan.get()).unwrap(), @@ -3984,7 +4504,9 @@ impl ChannelMana onion_utils::build_first_hop_failure_packet(incoming_shared_secret, error_code, &{ let mut res = Vec::with_capacity(8 + 128); // TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791 - res.extend_from_slice(&byte_utils::be16_to_array(0)); + if error_code == 0x1000 | 20 { + res.extend_from_slice(&byte_utils::be16_to_array(0)); + } res.extend_from_slice(&upd.encode_with_len()[..]); res }[..]) @@ -4246,7 +4768,8 @@ impl ChannelMana } channel_state.pending_msg_events.push(events::MessageSendEvent::BroadcastChannelAnnouncement { - msg: try_chan_entry!(self, chan.get_mut().announcement_signatures(&self.our_network_key, self.get_our_node_id(), self.genesis_hash.clone(), msg), channel_state, chan), + msg: try_chan_entry!(self, chan.get_mut().announcement_signatures( + self.get_our_node_id(), self.genesis_hash.clone(), self.best_block.read().unwrap().height(), msg), channel_state, chan), // Note that announcement_signatures fails if the channel cannot be announced, // so get_channel_update_for_broadcast will never fail by the time we get here. update_msg: self.get_channel_update_for_broadcast(chan.get()).unwrap(), @@ -4307,10 +4830,11 @@ impl ChannelMana // disconnect, so Channel's reestablish will never hand us any holding cell // freed HTLCs to fail backwards. If in the future we no longer drop pending // add-HTLCs on disconnect, we may be handed HTLCs to fail backwards here. - let (funding_locked, revoke_and_ack, commitment_update, monitor_update_opt, order, htlcs_failed_forward, shutdown) = - try_chan_entry!(self, chan.get_mut().channel_reestablish(msg, &self.logger), channel_state, chan); + let responses = try_chan_entry!(self, chan.get_mut().channel_reestablish( + msg, &self.logger, self.our_network_pubkey.clone(), self.genesis_hash, + &*self.best_block.read().unwrap()), channel_state, chan); let mut channel_update = None; - if let Some(msg) = shutdown { + if let Some(msg) = responses.shutdown_msg { channel_state.pending_msg_events.push(events::MessageSendEvent::SendShutdown { node_id: counterparty_node_id.clone(), msg, @@ -4325,11 +4849,13 @@ impl ChannelMana }); } let need_lnd_workaround = chan.get_mut().workaround_lnd_bug_4006.take(); - chan_restoration_res = handle_chan_restoration_locked!(self, channel_state_lock, channel_state, chan, revoke_and_ack, commitment_update, order, monitor_update_opt, Vec::new(), None, funding_locked); + chan_restoration_res = handle_chan_restoration_locked!( + self, channel_state_lock, channel_state, chan, responses.raa, responses.commitment_update, responses.order, + responses.mon_update, Vec::new(), None, responses.funding_locked, responses.announcement_sigs); if let Some(upd) = channel_update { channel_state.pending_msg_events.push(upd); } - (htlcs_failed_forward, need_lnd_workaround) + (responses.holding_cell_failed_htlcs, need_lnd_workaround) }, hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel".to_owned(), msg.channel_id)) } @@ -4406,7 +4932,7 @@ impl ChannelMana /// In chanmon_consistency_target, we'd like to be able to restore monitor updating without /// handling all pending events (i.e. not PendingHTLCsForwardable). Thus, we expose monitor /// update events as a separate process method here. - #[cfg(feature = "fuzztarget")] + #[cfg(fuzzing)] pub fn process_monitor_events(&self) { self.process_pending_monitor_events(); } @@ -4558,6 +5084,10 @@ impl ChannelMana fn set_payment_hash_secret_map(&self, payment_hash: PaymentHash, payment_preimage: Option, min_value_msat: Option, invoice_expiry_delta_secs: u32) -> Result { assert!(invoice_expiry_delta_secs <= 60*60*24*365); // Sadly bitcoin timestamps are u32s, so panic before 2106 + if min_value_msat.is_some() && min_value_msat.unwrap() > MAX_VALUE_MSAT { + return Err(APIError::APIMisuseError { err: format!("min_value_msat of {} greater than total 21 million bitcoin supply", min_value_msat.unwrap()) }); + } + let payment_secret = PaymentSecret(self.keys_manager.get_secure_random_bytes()); let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier); @@ -4568,7 +5098,7 @@ impl ChannelMana payment_secret, min_value_msat, payment_preimage, user_payment_id: 0, // For compatibility with version 0.0.103 and earlier // We assume that highest_seen_timestamp is pretty close to the current time - - // its updated when we receive a new block with the maximum time we've seen in + // it's updated when we receive a new block with the maximum time we've seen in // a header. It should never be more than two hours in the future. // Thus, we add two hours here as a buffer to ensure we absolutely // never fail a payment too early. @@ -4586,7 +5116,7 @@ impl ChannelMana /// to pay us. /// /// This differs from [`create_inbound_payment_for_hash`] only in that it generates the - /// [`PaymentHash`] and [`PaymentPreimage`] for you, returning the first and storing the second. + /// [`PaymentHash`] and [`PaymentPreimage`] for you. /// /// The [`PaymentPreimage`] will ultimately be returned to you in the [`PaymentReceived`], which /// will have the [`PaymentReceived::payment_preimage`] field filled in. That should then be @@ -4594,17 +5124,37 @@ impl ChannelMana /// /// See [`create_inbound_payment_for_hash`] for detailed documentation on behavior and requirements. /// + /// Note that a malicious eavesdropper can intuit whether an inbound payment was created by + /// `create_inbound_payment` or `create_inbound_payment_for_hash` based on runtime. + /// + /// # Note + /// + /// If you register an inbound payment with this method, then serialize the `ChannelManager`, then + /// deserialize it with a node running 0.0.103 and earlier, the payment will fail to be received. + /// + /// Errors if `min_value_msat` is greater than total bitcoin supply. + /// /// [`claim_funds`]: Self::claim_funds /// [`PaymentReceived`]: events::Event::PaymentReceived /// [`PaymentReceived::payment_preimage`]: events::Event::PaymentReceived::payment_preimage /// [`create_inbound_payment_for_hash`]: Self::create_inbound_payment_for_hash - pub fn create_inbound_payment(&self, min_value_msat: Option, invoice_expiry_delta_secs: u32) -> (PaymentHash, PaymentSecret) { + pub fn create_inbound_payment(&self, min_value_msat: Option, invoice_expiry_delta_secs: u32) -> Result<(PaymentHash, PaymentSecret), ()> { + inbound_payment::create(&self.inbound_payment_key, min_value_msat, invoice_expiry_delta_secs, &self.keys_manager, self.highest_seen_timestamp.load(Ordering::Acquire) as u64) + } + + /// Legacy version of [`create_inbound_payment`]. Use this method if you wish to share + /// serialized state with LDK node(s) running 0.0.103 and earlier. + /// + /// # Note + /// This method is deprecated and will be removed soon. + /// + /// [`create_inbound_payment`]: Self::create_inbound_payment + #[deprecated] + pub fn create_inbound_payment_legacy(&self, min_value_msat: Option, invoice_expiry_delta_secs: u32) -> Result<(PaymentHash, PaymentSecret), APIError> { let payment_preimage = PaymentPreimage(self.keys_manager.get_secure_random_bytes()); let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner()); - - (payment_hash, - self.set_payment_hash_secret_map(payment_hash, Some(payment_preimage), min_value_msat, invoice_expiry_delta_secs) - .expect("RNG Generated Duplicate PaymentHash")) + let payment_secret = self.set_payment_hash_secret_map(payment_hash, Some(payment_preimage), min_value_msat, invoice_expiry_delta_secs)?; + Ok((payment_hash, payment_secret)) } /// Gets a [`PaymentSecret`] for a given [`PaymentHash`], for which the payment preimage is @@ -4614,8 +5164,9 @@ impl ChannelMana /// payment secret fetched via this method or [`create_inbound_payment`], and which is at least /// the `min_value_msat` provided here, if one is provided. /// - /// The [`PaymentHash`] (and corresponding [`PaymentPreimage`]) must be globally unique. This - /// method may return an Err if another payment with the same payment_hash is still pending. + /// The [`PaymentHash`] (and corresponding [`PaymentPreimage`]) should be globally unique, though + /// note that LDK will not stop you from registering duplicate payment hashes for inbound + /// payments. /// /// `min_value_msat` should be set if the invoice being generated contains a value. Any payment /// received for the returned [`PaymentHash`] will be required to be at least `min_value_msat` @@ -4634,22 +5185,76 @@ impl ChannelMana /// If you need exact expiry semantics, you should enforce them upon receipt of /// [`PaymentReceived`]. /// - /// Pending inbound payments are stored in memory and in serialized versions of this - /// [`ChannelManager`]. If potentially unbounded numbers of inbound payments may exist and - /// space is limited, you may wish to rate-limit inbound payment creation. - /// /// May panic if `invoice_expiry_delta_secs` is greater than one year. /// /// Note that invoices generated for inbound payments should have their `min_final_cltv_expiry` /// set to at least [`MIN_FINAL_CLTV_EXPIRY`]. /// + /// Note that a malicious eavesdropper can intuit whether an inbound payment was created by + /// `create_inbound_payment` or `create_inbound_payment_for_hash` based on runtime. + /// + /// # Note + /// + /// If you register an inbound payment with this method, then serialize the `ChannelManager`, then + /// deserialize it with a node running 0.0.103 and earlier, the payment will fail to be received. + /// + /// Errors if `min_value_msat` is greater than total bitcoin supply. + /// /// [`create_inbound_payment`]: Self::create_inbound_payment /// [`PaymentReceived`]: events::Event::PaymentReceived - pub fn create_inbound_payment_for_hash(&self, payment_hash: PaymentHash, min_value_msat: Option, invoice_expiry_delta_secs: u32) -> Result { + pub fn create_inbound_payment_for_hash(&self, payment_hash: PaymentHash, min_value_msat: Option, invoice_expiry_delta_secs: u32) -> Result { + inbound_payment::create_from_hash(&self.inbound_payment_key, min_value_msat, payment_hash, invoice_expiry_delta_secs, self.highest_seen_timestamp.load(Ordering::Acquire) as u64) + } + + /// Legacy version of [`create_inbound_payment_for_hash`]. Use this method if you wish to share + /// serialized state with LDK node(s) running 0.0.103 and earlier. + /// + /// # Note + /// This method is deprecated and will be removed soon. + /// + /// [`create_inbound_payment_for_hash`]: Self::create_inbound_payment_for_hash + #[deprecated] + pub fn create_inbound_payment_for_hash_legacy(&self, payment_hash: PaymentHash, min_value_msat: Option, invoice_expiry_delta_secs: u32) -> Result { self.set_payment_hash_secret_map(payment_hash, None, min_value_msat, invoice_expiry_delta_secs) } - #[cfg(any(test, feature = "fuzztarget", feature = "_test_utils"))] + /// Gets an LDK-generated payment preimage from a payment hash and payment secret that were + /// previously returned from [`create_inbound_payment`]. + /// + /// [`create_inbound_payment`]: Self::create_inbound_payment + pub fn get_payment_preimage(&self, payment_hash: PaymentHash, payment_secret: PaymentSecret) -> Result { + inbound_payment::get_payment_preimage(payment_hash, payment_secret, &self.inbound_payment_key) + } + + /// Gets a fake short channel id for use in receiving [phantom node payments]. These fake scids + /// are used when constructing the phantom invoice's route hints. + /// + /// [phantom node payments]: crate::chain::keysinterface::PhantomKeysManager + pub fn get_phantom_scid(&self) -> u64 { + let mut channel_state = self.channel_state.lock().unwrap(); + let best_block = self.best_block.read().unwrap(); + loop { + let scid_candidate = fake_scid::get_phantom_scid(&self.fake_scid_rand_bytes, best_block.height(), &self.genesis_hash, &self.keys_manager); + // Ensure the generated scid doesn't conflict with a real channel. + match channel_state.short_to_id.entry(scid_candidate) { + hash_map::Entry::Occupied(_) => continue, + hash_map::Entry::Vacant(_) => return scid_candidate + } + } + } + + /// Gets route hints for use in receiving [phantom node payments]. + /// + /// [phantom node payments]: crate::chain::keysinterface::PhantomKeysManager + pub fn get_phantom_route_hints(&self) -> PhantomRouteHints { + PhantomRouteHints { + channels: self.list_usable_channels(), + phantom_scid: self.get_phantom_scid(), + real_node_pubkey: self.get_our_node_id(), + } + } + + #[cfg(any(test, fuzzing, feature = "_test_utils"))] pub fn get_and_clear_pending_events(&self) -> Vec { let events = core::cell::RefCell::new(Vec::new()); let event_handler = |event: &events::Event| events.borrow_mut().push(event.clone()); @@ -4781,7 +5386,7 @@ where *best_block = BestBlock::new(header.prev_blockhash, new_height) } - self.do_chain_event(Some(new_height), |channel| channel.best_block_updated(new_height, header.time, &self.logger)); + self.do_chain_event(Some(new_height), |channel| channel.best_block_updated(new_height, header.time, self.genesis_hash.clone(), self.get_our_node_id(), &self.logger)); } } @@ -4802,7 +5407,8 @@ where log_trace!(self.logger, "{} transactions included in block {} at height {} provided", txdata.len(), block_hash, height); let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier); - self.do_chain_event(Some(height), |channel| channel.transactions_confirmed(&block_hash, height, txdata, &self.logger).map(|a| (a, Vec::new()))); + self.do_chain_event(Some(height), |channel| channel.transactions_confirmed(&block_hash, height, txdata, self.genesis_hash.clone(), self.get_our_node_id(), &self.logger) + .map(|(a, b)| (a, Vec::new(), b))); } fn best_block_updated(&self, header: &BlockHeader, height: u32) { @@ -4817,7 +5423,7 @@ where *self.best_block.write().unwrap() = BestBlock::new(block_hash, height); - self.do_chain_event(Some(height), |channel| channel.best_block_updated(height, header.time, &self.logger)); + self.do_chain_event(Some(height), |channel| channel.best_block_updated(height, header.time, self.genesis_hash.clone(), self.get_our_node_id(), &self.logger)); macro_rules! max_time { ($timestamp: expr) => { @@ -4843,13 +5449,18 @@ where }); let mut outbounds = self.pending_outbound_payments.lock().unwrap(); - outbounds.retain(|_, payment| { - const PAYMENT_EXPIRY_BLOCKS: u32 = 3; + let mut pending_events = self.pending_events.lock().unwrap(); + outbounds.retain(|payment_id, payment| { if payment.remaining_parts() != 0 { return true } - if let PendingOutboundPayment::Retryable { starting_block_height, .. } = payment { - return *starting_block_height + PAYMENT_EXPIRY_BLOCKS > height - } - true + if let PendingOutboundPayment::Retryable { starting_block_height, payment_hash, .. } = payment { + if *starting_block_height + PAYMENT_EXPIRY_BLOCKS <= height { + log_info!(self.logger, "Timing out payment with id {} and hash {}", log_bytes!(payment_id.0), log_bytes!(payment_hash.0)); + pending_events.push(events::Event::PaymentFailed { + payment_id: *payment_id, payment_hash: *payment_hash, + }); + false + } else { true } + } else { true } }); } @@ -4869,9 +5480,9 @@ where self.do_chain_event(None, |channel| { if let Some(funding_txo) = channel.get_funding_txo() { if funding_txo.txid == *txid { - channel.funding_transaction_unconfirmed(&self.logger).map(|_| (None, Vec::new())) - } else { Ok((None, Vec::new())) } - } else { Ok((None, Vec::new())) } + channel.funding_transaction_unconfirmed(&self.logger).map(|()| (None, Vec::new(), None)) + } else { Ok((None, Vec::new(), None)) } + } else { Ok((None, Vec::new(), None)) } }); } } @@ -4887,7 +5498,7 @@ where /// Calls a function which handles an on-chain event (blocks dis/connected, transactions /// un/confirmed, etc) on each channel, handling any resulting errors or messages generated by /// the function. - fn do_chain_event) -> Result<(Option, Vec<(HTLCSource, PaymentHash)>), ClosureReason>> + fn do_chain_event) -> Result<(Option, Vec<(HTLCSource, PaymentHash)>, Option), ClosureReason>> (&self, height_opt: Option, f: FN) { // Note that we MUST NOT end up calling methods on self.chain_monitor here - we're called // during initialization prior to the chain_monitor being fully configured in some cases. @@ -4902,7 +5513,7 @@ where let pending_msg_events = &mut channel_state.pending_msg_events; channel_state.by_id.retain(|_, channel| { let res = f(channel); - if let Ok((chan_res, mut timed_out_pending_htlcs)) = res { + if let Ok((funding_locked_opt, mut timed_out_pending_htlcs, announcement_sigs)) = res { for (source, payment_hash) in timed_out_pending_htlcs.drain(..) { let chan_update = self.get_channel_update_for_unicast(&channel).map(|u| u.encode_with_len()).unwrap(); // Cannot add/recv HTLCs before we have a short_id so unwrap is safe timed_out_htlcs.push((source, payment_hash, HTLCFailReason::Reason { @@ -4910,28 +5521,39 @@ where data: chan_update, })); } - if let Some(funding_locked) = chan_res { + if let Some(funding_locked) = funding_locked_opt { pending_msg_events.push(events::MessageSendEvent::SendFundingLocked { node_id: channel.get_counterparty_node_id(), msg: funding_locked, }); - if let Some(announcement_sigs) = self.get_announcement_sigs(channel) { - log_trace!(self.logger, "Sending funding_locked and announcement_signatures for {}", log_bytes!(channel.channel_id())); - pending_msg_events.push(events::MessageSendEvent::SendAnnouncementSignatures { - node_id: channel.get_counterparty_node_id(), - msg: announcement_sigs, - }); - } else if channel.is_usable() { - log_trace!(self.logger, "Sending funding_locked WITHOUT announcement_signatures but with private channel_update for our counterparty on channel {}", log_bytes!(channel.channel_id())); + if channel.is_usable() { + log_trace!(self.logger, "Sending funding_locked with private initial channel_update for our counterparty on channel {}", log_bytes!(channel.channel_id())); pending_msg_events.push(events::MessageSendEvent::SendChannelUpdate { node_id: channel.get_counterparty_node_id(), msg: self.get_channel_update_for_unicast(channel).unwrap(), }); } else { - log_trace!(self.logger, "Sending funding_locked WITHOUT announcement_signatures for {}", log_bytes!(channel.channel_id())); + log_trace!(self.logger, "Sending funding_locked WITHOUT channel_update for {}", log_bytes!(channel.channel_id())); } short_to_id.insert(channel.get_short_channel_id().unwrap(), channel.channel_id()); } + if let Some(announcement_sigs) = announcement_sigs { + log_trace!(self.logger, "Sending announcement_signatures for channel {}", log_bytes!(channel.channel_id())); + pending_msg_events.push(events::MessageSendEvent::SendAnnouncementSignatures { + node_id: channel.get_counterparty_node_id(), + msg: announcement_sigs, + }); + if let Some(height) = height_opt { + if let Some(announcement) = channel.get_signed_channel_announcement(self.get_our_node_id(), self.genesis_hash, height) { + pending_msg_events.push(events::MessageSendEvent::BroadcastChannelAnnouncement { + msg: announcement, + // Note that announcement_signatures fails if the channel cannot be announced, + // so get_channel_update_for_broadcast will never fail by the time we get here. + update_msg: self.get_channel_update_for_broadcast(channel).unwrap(), + }); + } + } + } } else if let Err(reason) = res { if let Some(short_id) = channel.get_short_channel_id() { short_to_id.remove(&short_id); @@ -4991,8 +5613,9 @@ where /// indicating whether persistence is necessary. Only one listener on /// `await_persistable_update` or `await_persistable_update_timeout` is guaranteed to be woken /// up. - /// Note that the feature `allow_wallclock_use` must be enabled to use this function. - #[cfg(any(test, feature = "allow_wallclock_use"))] + /// + /// Note that this method is not available with the `no-std` feature. + #[cfg(any(test, feature = "std"))] pub fn await_persistable_update_timeout(&self, max_wait: Duration) -> bool { self.persistence_notifier.wait_timeout(max_wait) } @@ -5287,7 +5910,7 @@ impl PersistenceNotifier { } } - #[cfg(any(test, feature = "allow_wallclock_use"))] + #[cfg(any(test, feature = "std"))] fn wait_timeout(&self, max_wait: Duration) -> bool { let current_time = Instant::now(); loop { @@ -5329,6 +5952,44 @@ impl PersistenceNotifier { const SERIALIZATION_VERSION: u8 = 1; const MIN_SERIALIZATION_VERSION: u8 = 1; +impl_writeable_tlv_based!(CounterpartyForwardingInfo, { + (2, fee_base_msat, required), + (4, fee_proportional_millionths, required), + (6, cltv_expiry_delta, required), +}); + +impl_writeable_tlv_based!(ChannelCounterparty, { + (2, node_id, required), + (4, features, required), + (6, unspendable_punishment_reserve, required), + (8, forwarding_info, option), +}); + +impl_writeable_tlv_based!(ChannelDetails, { + (2, channel_id, required), + (4, counterparty, required), + (6, funding_txo, option), + (8, short_channel_id, option), + (10, channel_value_satoshis, required), + (12, unspendable_punishment_reserve, option), + (14, user_channel_id, required), + (16, balance_msat, required), + (18, outbound_capacity_msat, required), + (20, inbound_capacity_msat, required), + (22, confirmations_required, option), + (24, force_close_spend_delay, option), + (26, is_outbound, required), + (28, is_funding_locked, required), + (30, is_usable, required), + (32, is_public, required), +}); + +impl_writeable_tlv_based!(PhantomRouteHints, { + (2, channels, vec_type), + (4, phantom_scid, required), + (6, real_node_pubkey, required), +}); + impl_writeable_tlv_based_enum!(PendingHTLCRouting, (0, Forward) => { (0, onion_packet, required), @@ -5336,6 +5997,7 @@ impl_writeable_tlv_based_enum!(PendingHTLCRouting, }, (1, Receive) => { (0, payment_data, required), + (1, phantom_shared_secret, option), (2, incoming_cltv_expiry, required), }, (2, ReceiveKeysend) => { @@ -5427,6 +6089,7 @@ impl_writeable_tlv_based_enum!(PendingHTLCStatus, ; impl_writeable_tlv_based!(HTLCPreviousHopData, { (0, short_channel_id, required), + (1, phantom_shared_secret, option), (2, outpoint, required), (4, htlc_id, required), (6, incoming_packet_shared_secret, required) @@ -5500,14 +6163,14 @@ impl Readable for HTLCSource { let mut path = Some(Vec::new()); let mut payment_id = None; let mut payment_secret = None; - let mut payee = None; + let mut payment_params = None; read_tlv_fields!(reader, { (0, session_priv, required), (1, payment_id, option), (2, first_hop_htlc_msat, required), (3, payment_secret, option), (4, path, vec_type), - (5, payee, option), + (5, payment_params, option), }); if payment_id.is_none() { // For backwards compat, if there was no payment_id written, use the session_priv bytes @@ -5520,7 +6183,7 @@ impl Readable for HTLCSource { path: path.unwrap(), payment_id: payment_id.unwrap(), payment_secret, - payee, + payment_params, }) } 1 => Ok(HTLCSource::PreviousHopData(Readable::read(reader)?)), @@ -5532,7 +6195,7 @@ impl Readable for HTLCSource { impl Writeable for HTLCSource { fn write(&self, writer: &mut W) -> Result<(), ::io::Error> { match self { - HTLCSource::OutboundRoute { ref session_priv, ref first_hop_htlc_msat, ref path, payment_id, payment_secret, payee } => { + HTLCSource::OutboundRoute { ref session_priv, ref first_hop_htlc_msat, ref path, payment_id, payment_secret, payment_params } => { 0u8.write(writer)?; let payment_id_opt = Some(payment_id); write_tlv_fields!(writer, { @@ -5541,7 +6204,7 @@ impl Writeable for HTLCSource { (2, first_hop_htlc_msat, required), (3, payment_secret, option), (4, path, vec_type), - (5, payee, option), + (5, payment_params, option), }); } HTLCSource::PreviousHopData(ref field) => { @@ -5601,6 +6264,10 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment, (8, pending_amt_msat, required), (10, starting_block_height, required), }, + (3, Abandoned) => { + (0, session_privs, required), + (2, payment_hash, required), + }, ); impl Writeable for ChannelManager @@ -5662,6 +6329,8 @@ impl Writeable f peer_state.latest_features.write(writer)?; } + let pending_inbound_payments = self.pending_inbound_payments.lock().unwrap(); + let pending_outbound_payments = self.pending_outbound_payments.lock().unwrap(); let events = self.pending_events.lock().unwrap(); (events.len() as u64).write(writer)?; for event in events.iter() { @@ -5683,18 +6352,16 @@ impl Writeable f (self.last_node_announcement_serial.load(Ordering::Acquire) as u32).write(writer)?; (self.highest_seen_timestamp.load(Ordering::Acquire) as u32).write(writer)?; - let pending_inbound_payments = self.pending_inbound_payments.lock().unwrap(); (pending_inbound_payments.len() as u64).write(writer)?; for (hash, pending_payment) in pending_inbound_payments.iter() { hash.write(writer)?; pending_payment.write(writer)?; } - let pending_outbound_payments = self.pending_outbound_payments.lock().unwrap(); // For backwards compat, write the session privs and their total length. let mut num_pending_outbounds_compat: u64 = 0; for (_, outbound) in pending_outbound_payments.iter() { - if !outbound.is_fulfilled() { + if !outbound.is_fulfilled() && !outbound.abandoned() { num_pending_outbounds_compat += outbound.remaining_parts() as u64; } } @@ -5708,6 +6375,7 @@ impl Writeable f } } PendingOutboundPayment::Fulfilled { .. } => {}, + PendingOutboundPayment::Abandoned { .. } => {}, } } @@ -5725,6 +6393,8 @@ impl Writeable f write_tlv_fields!(writer, { (1, pending_outbound_payments_no_retry, required), (3, pending_outbound_payments, required), + (5, self.our_network_pubkey, required), + (7, self.fake_scid_rand_bytes, required), }); Ok(()) @@ -5886,7 +6556,7 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> log_error!(args.logger, " The chain::Watch API *requires* that monitors are persisted durably before returning,"); log_error!(args.logger, " client applications must ensure that ChannelMonitor data is always available and the latest to avoid funds loss!"); log_error!(args.logger, " Without the latest ChannelMonitor we cannot continue without risking funds."); - log_error!(args.logger, " Please ensure the chain::Watch API requirements are met and file a bug report at https://github.com/rust-bitcoin/rust-lightning"); + log_error!(args.logger, " Please ensure the chain::Watch API requirements are met and file a bug report at https://github.com/lightningdevkit/rust-lightning"); return Err(DecodeError::InvalidValue); } else if channel.get_cur_holder_commitment_transaction_number() > monitor.get_cur_holder_commitment_number() || channel.get_revoked_counterparty_commitment_transaction_number() > monitor.get_min_seen_secret() || @@ -5917,7 +6587,7 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> log_error!(args.logger, " The chain::Watch API *requires* that monitors are persisted durably before returning,"); log_error!(args.logger, " client applications must ensure that ChannelMonitor data is always available and the latest to avoid funds loss!"); log_error!(args.logger, " Without the ChannelMonitor we cannot continue without risking funds."); - log_error!(args.logger, " Please ensure the chain::Watch API requirements are met and file a bug report at https://github.com/rust-bitcoin/rust-lightning"); + log_error!(args.logger, " Please ensure the chain::Watch API requirements are met and file a bug report at https://github.com/lightningdevkit/rust-lightning"); return Err(DecodeError::InvalidValue); } } @@ -6019,10 +6689,18 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> // pending_outbound_payments_no_retry is for compatibility with 0.0.101 clients. let mut pending_outbound_payments_no_retry: Option>> = None; let mut pending_outbound_payments = None; + let mut received_network_pubkey: Option = None; + let mut fake_scid_rand_bytes: Option<[u8; 32]> = None; read_tlv_fields!(reader, { (1, pending_outbound_payments_no_retry, option), (3, pending_outbound_payments, option), + (5, received_network_pubkey, option), + (7, fake_scid_rand_bytes, option), }); + if fake_scid_rand_bytes.is_none() { + fake_scid_rand_bytes = Some(args.keys_manager.get_secure_random_bytes()); + } + if pending_outbound_payments.is_none() && pending_outbound_payments_no_retry.is_none() { pending_outbound_payments = Some(pending_outbound_payments_compat); } else if pending_outbound_payments.is_none() { @@ -6085,6 +6763,20 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> pending_events_read.append(&mut channel_closures); } + let our_network_key = match args.keys_manager.get_node_secret(Recipient::Node) { + Ok(key) => key, + Err(()) => return Err(DecodeError::InvalidValue) + }; + let our_network_pubkey = PublicKey::from_secret_key(&secp_ctx, &our_network_key); + if let Some(network_pubkey) = received_network_pubkey { + if network_pubkey != our_network_pubkey { + log_error!(args.logger, "Key that was generated does not match the existing key."); + return Err(DecodeError::InvalidValue); + } + } + + let inbound_pmt_key_material = args.keys_manager.get_inbound_payment_key_material(); + let expanded_inbound_key = inbound_payment::ExpandedKey::new(&inbound_pmt_key_material); let channel_manager = ChannelManager { genesis_hash, fee_estimator: args.fee_estimator, @@ -6100,11 +6792,13 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> claimable_htlcs, pending_msg_events: Vec::new(), }), + inbound_payment_key: expanded_inbound_key, pending_inbound_payments: Mutex::new(pending_inbound_payments), pending_outbound_payments: Mutex::new(pending_outbound_payments.unwrap()), + fake_scid_rand_bytes: fake_scid_rand_bytes.unwrap(), - our_network_key: args.keys_manager.get_node_secret(), - our_network_pubkey: PublicKey::from_secret_key(&secp_ctx, &args.keys_manager.get_node_secret()), + our_network_key, + our_network_pubkey, secp_ctx, last_node_announcement_serial: AtomicUsize::new(last_node_announcement_serial as usize), @@ -6138,13 +6832,15 @@ mod tests { use bitcoin::hashes::Hash; use bitcoin::hashes::sha256::Hash as Sha256; use core::time::Duration; + use core::sync::atomic::Ordering; use ln::{PaymentPreimage, PaymentHash, PaymentSecret}; use ln::channelmanager::{PaymentId, PaymentSendFailure}; + use ln::channelmanager::inbound_payment; use ln::features::InitFeatures; use ln::functional_test_utils::*; use ln::msgs; use ln::msgs::ChannelMessageHandler; - use routing::router::{Payee, RouteParameters, find_route}; + use routing::router::{PaymentParameters, RouteParameters, find_route}; use util::errors::APIError; use util::events::{Event, MessageSendEvent, MessageSendEventsProvider}; use util::test_utils; @@ -6154,7 +6850,7 @@ mod tests { fn test_wait_timeout() { use ln::channelmanager::PersistenceNotifier; use sync::Arc; - use core::sync::atomic::{AtomicBool, Ordering}; + use core::sync::atomic::AtomicBool; use std::thread; let persistence_notifier = Arc::new(PersistenceNotifier::new()); @@ -6291,7 +6987,7 @@ mod tests { // Use the utility function send_payment_along_path to send the payment with MPP data which // indicates there are more HTLCs coming. let cur_height = CHAN_CONFIRM_DEPTH + 1; // route_payment calls send_payment, which adds 1 to the current height. So we do the same here to match. - nodes[0].node.send_payment_along_path(&route.paths[0], &route.payee, &our_payment_hash, &Some(payment_secret), 200_000, cur_height, payment_id, &None).unwrap(); + nodes[0].node.send_payment_along_path(&route.paths[0], &route.payment_params, &our_payment_hash, &Some(payment_secret), 200_000, cur_height, payment_id, &None).unwrap(); check_added_monitors!(nodes[0], 1); let mut events = nodes[0].node.get_and_clear_pending_msg_events(); assert_eq!(events.len(), 1); @@ -6321,7 +7017,7 @@ mod tests { expect_payment_failed!(nodes[0], our_payment_hash, true); // Send the second half of the original MPP payment. - nodes[0].node.send_payment_along_path(&route.paths[0], &route.payee, &our_payment_hash, &Some(payment_secret), 200_000, cur_height, payment_id, &None).unwrap(); + nodes[0].node.send_payment_along_path(&route.paths[0], &route.payment_params, &our_payment_hash, &Some(payment_secret), 200_000, cur_height, payment_id, &None).unwrap(); check_added_monitors!(nodes[0], 1); let mut events = nodes[0].node.get_and_clear_pending_msg_events(); assert_eq!(events.len(), 1); @@ -6400,20 +7096,20 @@ mod tests { let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); let nodes = create_network(2, &node_cfgs, &node_chanmgrs); create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()); - let scorer = test_utils::TestScorer::with_fixed_penalty(0); + let scorer = test_utils::TestScorer::with_penalty(0); // To start (1), send a regular payment but don't claim it. let expected_route = [&nodes[1]]; let (payment_preimage, payment_hash, _) = route_payment(&nodes[0], &expected_route, 100_000); // Next, attempt a keysend payment and make sure it fails. - let params = RouteParameters { - payee: Payee::for_keysend(expected_route.last().unwrap().node.get_our_node_id()), + let route_params = RouteParameters { + payment_params: PaymentParameters::for_keysend(expected_route.last().unwrap().node.get_our_node_id()), final_value_msat: 100_000, final_cltv_expiry_delta: TEST_FINAL_CLTV, }; let route = find_route( - &nodes[0].node.get_our_node_id(), ¶ms, nodes[0].network_graph, None, + &nodes[0].node.get_our_node_id(), &route_params, nodes[0].network_graph, None, nodes[0].logger, &scorer ).unwrap(); nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage)).unwrap(); @@ -6444,7 +7140,7 @@ mod tests { // To start (2), send a keysend payment but don't claim it. let payment_preimage = PaymentPreimage([42; 32]); let route = find_route( - &nodes[0].node.get_our_node_id(), ¶ms, nodes[0].network_graph, None, + &nodes[0].node.get_our_node_id(), &route_params, nodes[0].network_graph, None, nodes[0].logger, &scorer ).unwrap(); let (payment_hash, _) = nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage)).unwrap(); @@ -6498,16 +7194,16 @@ mod tests { nodes[1].node.peer_connected(&payer_pubkey, &msgs::Init { features: InitFeatures::known() }); let _chan = create_chan_between_nodes(&nodes[0], &nodes[1], InitFeatures::known(), InitFeatures::known()); - let params = RouteParameters { - payee: Payee::for_keysend(payee_pubkey), + let route_params = RouteParameters { + payment_params: PaymentParameters::for_keysend(payee_pubkey), final_value_msat: 10000, final_cltv_expiry_delta: 40, }; let network_graph = nodes[0].network_graph; let first_hops = nodes[0].node.list_usable_channels(); - let scorer = test_utils::TestScorer::with_fixed_penalty(0); + let scorer = test_utils::TestScorer::with_penalty(0); let route = find_route( - &payer_pubkey, ¶ms, network_graph, Some(&first_hops.iter().collect::>()), + &payer_pubkey, &route_params, network_graph, Some(&first_hops.iter().collect::>()), nodes[0].logger, &scorer ).unwrap(); @@ -6541,16 +7237,16 @@ mod tests { nodes[1].node.peer_connected(&payer_pubkey, &msgs::Init { features: InitFeatures::known() }); let _chan = create_chan_between_nodes(&nodes[0], &nodes[1], InitFeatures::known(), InitFeatures::known()); - let params = RouteParameters { - payee: Payee::for_keysend(payee_pubkey), + let route_params = RouteParameters { + payment_params: PaymentParameters::for_keysend(payee_pubkey), final_value_msat: 10000, final_cltv_expiry_delta: 40, }; let network_graph = nodes[0].network_graph; let first_hops = nodes[0].node.list_usable_channels(); - let scorer = test_utils::TestScorer::with_fixed_penalty(0); + let scorer = test_utils::TestScorer::with_penalty(0); let route = find_route( - &payer_pubkey, ¶ms, network_graph, Some(&first_hops.iter().collect::>()), + &payer_pubkey, &route_params, network_graph, Some(&first_hops.iter().collect::>()), nodes[0].logger, &scorer ).unwrap(); @@ -6600,9 +7296,38 @@ mod tests { _ => panic!("unexpected error") } } + + #[test] + fn bad_inbound_payment_hash() { + // Add coverage for checking that a user-provided payment hash matches the payment secret. + let chanmon_cfgs = create_chanmon_cfgs(2); + 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 (_, payment_hash, payment_secret) = get_payment_preimage_hash!(&nodes[0]); + let payment_data = msgs::FinalOnionHopData { + payment_secret, + total_msat: 100_000, + }; + + // Ensure that if the payment hash given to `inbound_payment::verify` differs from the original, + // payment verification fails as expected. + let mut bad_payment_hash = payment_hash.clone(); + bad_payment_hash.0[0] += 1; + match inbound_payment::verify(bad_payment_hash, payment_data.clone(), nodes[0].node.highest_seen_timestamp.load(Ordering::Acquire) as u64, &nodes[0].node.inbound_payment_key, &nodes[0].logger) { + Ok(_) => panic!("Unexpected ok"), + Err(()) => { + nodes[0].logger.assert_log_contains("lightning::ln::channelmanager::inbound_payment".to_string(), "Failing HTLC with user-generated payment_hash".to_string(), 1); + } + } + + // Check that using the original payment hash succeeds. + assert!(inbound_payment::verify(payment_hash, payment_data, nodes[0].node.highest_seen_timestamp.load(Ordering::Acquire) as u64, &nodes[0].node.inbound_payment_key, &nodes[0].logger).is_ok()); + } } -#[cfg(all(any(test, feature = "_test_utils"), feature = "unstable"))] +#[cfg(all(any(test, feature = "_test_utils"), feature = "_bench_unstable"))] pub mod bench { use chain::Listen; use chain::chainmonitor::{ChainMonitor, Persist}; @@ -6612,8 +7337,7 @@ pub mod bench { use ln::functional_test_utils::*; use ln::msgs::{ChannelMessageHandler, Init}; use routing::network_graph::NetworkGraph; - use routing::router::{Payee, get_route}; - use routing::scoring::Scorer; + use routing::router::{PaymentParameters, get_route}; use util::test_utils; use util::config::UserConfig; use util::events::{Event, MessageSendEvent, MessageSendEventsProvider, PaymentPurpose}; @@ -6721,10 +7445,10 @@ pub mod bench { macro_rules! send_payment { ($node_a: expr, $node_b: expr) => { let usable_channels = $node_a.list_usable_channels(); - let payee = Payee::from_node_id($node_b.get_our_node_id()) + let payment_params = PaymentParameters::from_node_id($node_b.get_our_node_id()) .with_features(InvoiceFeatures::known()); - let scorer = Scorer::with_fixed_penalty(0); - let route = get_route(&$node_a.get_our_node_id(), &payee, &dummy_graph, + let scorer = test_utils::TestScorer::with_penalty(0); + let route = get_route(&$node_a.get_our_node_id(), &payment_params, &dummy_graph, Some(&usable_channels.iter().map(|r| r).collect::>()), 10_000, TEST_FINAL_CLTV, &logger_a, &scorer).unwrap(); let mut payment_preimage = PaymentPreimage([0; 32]);