X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannelmanager.rs;h=4ac575ff6f4c13270c0a27604c5860453d40ba3a;hb=61629bc00ef7d64b56b3dad18d40d29c8037e068;hp=0ae0f8c3e8096e34970bd6f2e42452365d86c1cf;hpb=8dca0b47795db0eeee968d7a03ee0b1595484a52;p=rust-lightning diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 0ae0f8c3..4ac575ff 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}; @@ -42,20 +40,20 @@ use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitor use chain::transaction::{OutPoint, TransactionData}; // Since this struct is returned in `list_channels` methods, expose it here in case users want to // construct one themselves. -use ln::{PaymentHash, PaymentPreimage, PaymentSecret}; +use ln::{inbound_payment, PaymentHash, PaymentPreimage, PaymentSecret}; use ln::channel::{Channel, ChannelError, ChannelUpdateStatus, UpdateFulfillCommitFetch}; -use ln::features::{InitFeatures, NodeFeatures}; +use ln::features::{ChannelTypeFeatures, InitFeatures, NodeFeatures}; 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, MAX_VALUE_MSAT, OptionalField}; -use chain::keysinterface::{Sign, KeysInterface, KeysManager, InMemorySigner}; +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::ser::{BigSize, FixedLengthReader, Readable, ReadableArgs, MaybeReadable, Writeable, Writer}; -use util::chacha20::{ChaCha20, ChaChaReader}; +use util::scid_utils::fake_scid; +use util::ser::{BigSize, FixedLengthReader, Readable, ReadableArgs, MaybeReadable, Writeable, Writer, VecWriter}; use util::logger::{Level, Logger}; use util::errors::APIError; @@ -63,7 +61,7 @@ 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; @@ -71,294 +69,7 @@ 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::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 { - hkdf_extract_expand(b"LDK Inbound Payment Key Expansion", &key_material) - } - } - - 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)) - } - - fn hkdf_extract_expand(salt: &[u8], ikm: &KeyMaterial) -> ExpandedKey { - let mut hmac = HmacEngine::::new(salt); - hmac.input(&ikm.0); - let prk = Hmac::from_engine(hmac).into_inner(); - let mut hmac = HmacEngine::::new(&prk[..]); - hmac.input(&[1; 1]); - let metadata_key = Hmac::from_engine(hmac).into_inner(); - - let mut hmac = HmacEngine::::new(&prk[..]); - hmac.input(&metadata_key); - hmac.input(&[2; 1]); - let ldk_pmt_hash_key = Hmac::from_engine(hmac).into_inner(); - - let mut hmac = HmacEngine::::new(&prk[..]); - hmac.input(&ldk_pmt_hash_key); - hmac.input(&[3; 1]); - let user_pmt_hash_key = Hmac::from_engine(hmac).into_inner(); - - ExpandedKey { - metadata_key, - ldk_pmt_hash_key, - user_pmt_hash_key, - } - } -} +use util::crypto::sign; // We hold various information about HTLC relay in the HTLC objects in Channel itself: // @@ -378,7 +89,7 @@ mod inbound_payment { // 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 @@ -386,6 +97,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, @@ -395,8 +107,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, @@ -439,6 +151,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. @@ -459,6 +172,7 @@ struct ClaimableHTLC { cltv_expiry: u32, value: u64, onion_payload: OnionPayload, + timer_ticks: u8, } /// A payment identifier used to uniquely identify a payment to LDK. @@ -514,6 +228,7 @@ impl core::hash::Hash for HTLCSource { } } } +#[cfg(not(feature = "grind_signatures"))] #[cfg(test)] impl HTLCSource { pub fn dummy() -> Self { @@ -539,6 +254,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, @@ -672,8 +393,16 @@ pub(super) enum RAACommitmentOrder { // Note this is only exposed in cfg(test): pub(super) struct ChannelHolder { pub(super) by_id: HashMap<[u8; 32], Channel>, + /// SCIDs (and outbound SCID aliases) to the real channel id. Outbound SCID aliases are added + /// here once the channel is available for normal use, with SCIDs being added once the funding + /// transaction is confirmed at the channel's required confirmation depth. pub(super) short_to_id: HashMap, - /// short channel id -> forward infos. Key of 0 means payments received + /// SCID/SCID Alias -> forward infos. Key of 0 means payments received. + /// + /// Note that because we may have an SCID Alias as the key we can have two entries per channel, + /// though in practice we probably won't be receiving HTLCs for a channel both via the alias + /// and via the classic SCID. + /// /// Note that while this is held in the same mutex as the channels themselves, no consistency /// guarantees are made about the existence of a channel with the short id here, nor the short /// ids in the PendingHTLCInfo! @@ -890,6 +619,8 @@ impl PendingOutboundPayment { /// issues such as overly long function definitions. Note that the ChannelManager can take any /// type that implements KeysInterface for its keys manager, but this type alias chooses the /// concrete type of the KeysManager. +/// +/// (C-not exported) as Arcs don't make sense in bindings pub type SimpleArcChannelManager = ChannelManager, Arc, Arc, Arc, Arc>; /// SimpleRefChannelManager is a type alias for a ChannelManager reference, and is the reference @@ -900,6 +631,8 @@ pub type SimpleArcChannelManager = ChannelManager = ChannelManager; /// Manager which keeps track of a number of channels and sends messages to the appropriate @@ -983,11 +716,24 @@ pub struct ChannelManager>, + /// The set of outbound SCID aliases across all our channels, including unconfirmed channels + /// and some closed channels which reached a usable state prior to being closed. This is used + /// only to avoid duplicates, and is not persisted explicitly to disk, but rebuilt from the + /// active channel list on load. + outbound_scid_aliases: Mutex>, + our_network_key: SecretKey, our_network_pubkey: PublicKey, inbound_payment_key: inbound_payment::ExpandedKey, + /// LDK puts the [fake scids] that it generates into namespaces, to identify the type of an + /// incoming payment. To make it harder for a third-party to identify the type of a payment, + /// we encrypt the namespace identifier using these bytes. + /// + /// [fake scids]: crate::util::scid_utils::fake_scid + fake_scid_rand_bytes: [u8; 32], + /// Used to track the last value sent in a node_announcement "timestamp" field. We ensure this /// value increases strictly since we don't assume access to a time source. last_node_announcement_serial: AtomicUsize, @@ -1139,6 +885,9 @@ const CHECK_CLTV_EXPIRY_SANITY_2: u32 = MIN_CLTV_EXPIRY_DELTA as u32 - LATENCY_G /// pending HTLCs in flight. pub(crate) const PAYMENT_EXPIRY_BLOCKS: u32 = 3; +/// The number of ticks of [`ChannelManager::timer_tick_occurred`] until expiry of incomplete MPPs +pub(crate) const MPP_TIMEOUT_TICKS: u8 = 3; + /// Information needed for constructing an invoice route hint for this channel. #[derive(Clone, Debug, PartialEq)] pub struct CounterpartyForwardingInfo { @@ -1173,6 +922,12 @@ pub struct ChannelCounterparty { /// Information on the fees and requirements that the counterparty requires when forwarding /// payments to us through this channel. pub forwarding_info: Option, + /// The smallest value HTLC (in msat) the remote peer will accept, for this channel. This field + /// is only `None` before we have received either the `OpenChannel` or `AcceptChannel` message + /// from the remote peer, or for `ChannelCounterparty` objects serialized prior to LDK 0.0.107. + pub outbound_htlc_minimum_msat: Option, + /// The largest value HTLC (in msat) the remote peer currently will accept, for this channel. + pub outbound_htlc_maximum_msat: Option, } /// Details of a channel, as returned by ChannelManager::list_channels and ChannelManager::list_usable_channels @@ -1191,9 +946,29 @@ pub struct ChannelDetails { /// Note that, if this has been set, `channel_id` will be equivalent to /// `funding_txo.unwrap().to_channel_id()`. pub funding_txo: Option, + /// The features which this channel operates with. See individual features for more info. + /// + /// `None` until negotiation completes and the channel type is finalized. + pub channel_type: Option, /// The position of the funding transaction in the chain. None if the funding transaction has /// not yet been confirmed and the channel fully opened. + /// + /// Note that if [`inbound_scid_alias`] is set, it must be used for invoices and inbound + /// payments instead of this. See [`get_inbound_payment_scid`]. + /// + /// [`inbound_scid_alias`]: Self::inbound_scid_alias + /// [`get_inbound_payment_scid`]: Self::get_inbound_payment_scid pub short_channel_id: Option, + /// An optional [`short_channel_id`] alias for this channel, randomly generated by our + /// counterparty and usable in place of [`short_channel_id`] in invoice route hints. Our + /// counterparty will recognize the alias provided here in place of the [`short_channel_id`] + /// when they see a payment to be routed to us. + /// + /// Our counterparty may choose to rotate this value at any time, though will always recognize + /// previous values for inbound payment forwarding. + /// + /// [`short_channel_id`]: Self::short_channel_id + pub inbound_scid_alias: Option, /// The value, in satoshis, of this channel as appears in the funding output pub channel_value_satoshis: u64, /// The value, in satoshis, that must always be held in the channel for us. This value ensures @@ -1230,6 +1005,13 @@ pub struct ChannelDetails { /// 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 outbound capacity for sending a single HTLC to the remote peer. This is + /// similar to [`ChannelDetails::outbound_capacity_msat`] but it may be further restricted by + /// the current state and per-HTLC limit(s). This is intended for use when routing, allowing us + /// to use a limit as close as possible to the HTLC limit we can currently send. + /// + /// See also [`ChannelDetails::balance_msat`] and [`ChannelDetails::outbound_capacity_msat`]. + pub next_outbound_htlc_limit_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, whose balance is not /// available for inclusion in new inbound HTLCs). @@ -1277,6 +1059,23 @@ pub struct ChannelDetails { pub is_usable: bool, /// True if this channel is (or will be) publicly-announced. pub is_public: bool, + /// The smallest value HTLC (in msat) we will accept, for this channel. This field + /// is only `None` for `ChannelDetails` objects serialized prior to LDK 0.0.107 + pub inbound_htlc_minimum_msat: Option, + /// The largest value HTLC (in msat) we currently will accept, for this channel. + pub inbound_htlc_maximum_msat: Option, +} + +impl ChannelDetails { + /// Gets the current SCID which should be used to identify this channel for inbound payments. + /// This should be used for providing invoice hints or in any other context where our + /// counterparty will forward a payment to us. + /// + /// This is either the [`ChannelDetails::inbound_scid_alias`], if set, or the + /// [`ChannelDetails::short_channel_id`]. See those for more information. + pub fn get_inbound_payment_scid(&self) -> Option { + self.inbound_scid_alias.or(self.short_channel_id) + } } /// If a payment fails to send, it can be in one of several states. This enum is returned as the @@ -1324,6 +1123,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 { @@ -1374,6 +1187,24 @@ macro_rules! handle_error { } } +macro_rules! update_maps_on_chan_removal { + ($self: expr, $short_to_id: expr, $channel: expr) => { + if let Some(short_id) = $channel.get_short_channel_id() { + $short_to_id.remove(&short_id); + } else { + // If the channel was never confirmed on-chain prior to its closure, remove the + // outbound SCID alias we used for it from the collision-prevention set. While we + // generally want to avoid ever re-using an outbound SCID alias across all channels, we + // also don't want a counterparty to be able to trivially cause a memory leak by simply + // opening a million channels with us which are closed before we ever reach the funding + // stage. + let alias_removed = $self.outbound_scid_aliases.lock().unwrap().remove(&$channel.outbound_scid_alias()); + debug_assert!(alias_removed); + } + $short_to_id.remove(&$channel.outbound_scid_alias()); + } +} + /// Returns (boolean indicating if we should remove the Channel object from memory, a mapped error) macro_rules! convert_chan_err { ($self: ident, $err: expr, $short_to_id: expr, $channel: expr, $channel_id: expr) => { @@ -1386,18 +1217,14 @@ macro_rules! convert_chan_err { }, ChannelError::Close(msg) => { log_error!($self.logger, "Closing channel {} due to close-required error: {}", log_bytes!($channel_id[..]), msg); - if let Some(short_id) = $channel.get_short_channel_id() { - $short_to_id.remove(&short_id); - } + update_maps_on_chan_removal!($self, $short_to_id, $channel); let shutdown_res = $channel.force_shutdown(true); (true, MsgHandleErrInternal::from_finish_shutdown(msg, *$channel_id, $channel.get_user_id(), shutdown_res, $self.get_channel_update_for_broadcast(&$channel).ok())) }, ChannelError::CloseDelayBroadcast(msg) => { log_error!($self.logger, "Channel {} need to be shutdown but closing transactions not broadcast due to {}", log_bytes!($channel_id[..]), msg); - if let Some(short_id) = $channel.get_short_channel_id() { - $short_to_id.remove(&short_id); - } + update_maps_on_chan_removal!($self, $short_to_id, $channel); let shutdown_res = $channel.force_shutdown(false); (true, MsgHandleErrInternal::from_finish_shutdown(msg, *$channel_id, $channel.get_user_id(), shutdown_res, $self.get_channel_update_for_broadcast(&$channel).ok())) @@ -1437,28 +1264,21 @@ macro_rules! try_chan_entry { } macro_rules! remove_channel { - ($channel_state: expr, $entry: expr) => { + ($self: expr, $channel_state: expr, $entry: expr) => { { let channel = $entry.remove_entry().1; - if let Some(short_id) = channel.get_short_channel_id() { - $channel_state.short_to_id.remove(&short_id); - } + update_maps_on_chan_removal!($self, $channel_state.short_to_id, channel); channel } } } macro_rules! handle_monitor_err { - ($self: ident, $err: expr, $channel_state: expr, $entry: expr, $action_type: path, $resend_raa: expr, $resend_commitment: expr) => { - handle_monitor_err!($self, $err, $channel_state, $entry, $action_type, $resend_raa, $resend_commitment, Vec::new(), Vec::new()) - }; ($self: ident, $err: expr, $short_to_id: expr, $chan: expr, $action_type: path, $resend_raa: expr, $resend_commitment: expr, $failed_forwards: expr, $failed_fails: expr, $failed_finalized_fulfills: expr, $chan_id: expr) => { match $err { ChannelMonitorUpdateErr::PermanentFailure => { log_error!($self.logger, "Closing channel {} due to monitor update ChannelMonitorUpdateErr::PermanentFailure", log_bytes!($chan_id[..])); - if let Some(short_id) = $chan.get_short_channel_id() { - $short_to_id.remove(&short_id); - } + update_maps_on_chan_removal!($self, $short_to_id, $chan); // TODO: $failed_fails is dropped here, which will cause other channels to hit the // chain in a confused state! We need to move them into the ChannelMonitor which // will be responsible for failing backwards once things confirm on-chain. @@ -1504,9 +1324,19 @@ macro_rules! handle_monitor_err { } res } }; + ($self: ident, $err: expr, $channel_state: expr, $entry: expr, $action_type: path, $chan_id: expr, COMMITMENT_UPDATE_ONLY) => { { + debug_assert!($action_type == RAACommitmentOrder::CommitmentFirst); + handle_monitor_err!($self, $err, $channel_state, $entry, $action_type, false, true, Vec::new(), Vec::new(), Vec::new(), $chan_id) + } }; + ($self: ident, $err: expr, $channel_state: expr, $entry: expr, $action_type: path, $chan_id: expr, NO_UPDATE) => { + handle_monitor_err!($self, $err, $channel_state, $entry, $action_type, false, false, Vec::new(), Vec::new(), Vec::new(), $chan_id) + }; + ($self: ident, $err: expr, $channel_state: expr, $entry: expr, $action_type: path, $resend_raa: expr, $resend_commitment: expr) => { + handle_monitor_err!($self, $err, $channel_state, $entry, $action_type, $resend_raa, $resend_commitment, Vec::new(), Vec::new(), Vec::new()) + }; ($self: ident, $err: expr, $channel_state: expr, $entry: expr, $action_type: path, $resend_raa: expr, $resend_commitment: expr, $failed_forwards: expr, $failed_fails: expr) => { handle_monitor_err!($self, $err, $channel_state, $entry, $action_type, $resend_raa, $resend_commitment, $failed_forwards, $failed_fails, Vec::new()) - } + }; } macro_rules! return_monitor_err { @@ -1530,15 +1360,34 @@ macro_rules! maybe_break_monitor_err { } } +macro_rules! send_funding_locked { + ($short_to_id: expr, $pending_msg_events: expr, $channel: expr, $funding_locked_msg: expr) => { + $pending_msg_events.push(events::MessageSendEvent::SendFundingLocked { + node_id: $channel.get_counterparty_node_id(), + msg: $funding_locked_msg, + }); + // Note that we may send a funding locked multiple times for a channel if we reconnect, so + // we allow collisions, but we shouldn't ever be updating the channel ID pointed to. + let outbound_alias_insert = $short_to_id.insert($channel.outbound_scid_alias(), $channel.channel_id()); + assert!(outbound_alias_insert.is_none() || outbound_alias_insert.unwrap() == $channel.channel_id(), + "SCIDs should never collide - ensure you weren't behind the chain tip by a full month when creating channels"); + if let Some(real_scid) = $channel.get_short_channel_id() { + let scid_insert = $short_to_id.insert(real_scid, $channel.channel_id()); + assert!(scid_insert.is_none() || scid_insert.unwrap() == $channel.channel_id(), + "SCIDs should never collide - ensure you weren't behind the chain tip by a full month when creating channels"); + } + } +} + 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, $announcement_sigs: expr) => { { let mut htlc_forwards = None; - let counterparty_node_id = $channel_entry.get().get_counterparty_node_id(); let chanmon_update: Option = $chanmon_update; // Force type-checking to resolve let chanmon_update_is_none = chanmon_update.is_none(); + let counterparty_node_id = $channel_entry.get().get_counterparty_node_id(); let res = loop { let forwards: Vec<(PendingHTLCInfo, u64)> = $pending_forwards; // Force type-checking to resolve if !forwards.is_empty() { @@ -1564,11 +1413,7 @@ macro_rules! handle_chan_restoration_locked { // Similar to the above, this implies that we're letting the funding_locked fly // before it should be allowed to. assert!(chanmon_update.is_none()); - $channel_state.pending_msg_events.push(events::MessageSendEvent::SendFundingLocked { - node_id: counterparty_node_id, - msg, - }); - $channel_state.short_to_id.insert($channel_entry.get().get_short_channel_id().unwrap(), $channel_entry.get().channel_id()); + send_funding_locked!($channel_state.short_to_id, $channel_state.pending_msg_events, $channel_entry.get(), msg); } if let Some(msg) = $announcement_sigs { $channel_state.pending_msg_events.push(events::MessageSendEvent::SendAnnouncementSignatures { @@ -1697,14 +1542,16 @@ impl ChannelMana claimable_htlcs: HashMap::new(), pending_msg_events: Vec::new(), }), + outbound_scid_aliases: Mutex::new(HashSet::new()), 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), @@ -1727,6 +1574,25 @@ impl ChannelMana &self.default_configuration } + fn create_and_insert_outbound_scid_alias(&self) -> u64 { + let height = self.best_block.read().unwrap().height(); + let mut outbound_scid_alias = 0; + let mut i = 0; + loop { + if cfg!(fuzzing) { // fuzzing chacha20 doesn't use the key at all so we always get the same alias + outbound_scid_alias += 1; + } else { + outbound_scid_alias = fake_scid::Namespace::OutboundAlias.get_fake_scid(height, &self.genesis_hash, &self.fake_scid_rand_bytes, &self.keys_manager); + } + if outbound_scid_alias != 0 && self.outbound_scid_aliases.lock().unwrap().insert(outbound_scid_alias) { + break; + } + i += 1; + if i > 1_000_000 { panic!("Your RNG is busted or we ran out of possible outbound SCID aliases (which should never happen before we run out of memory to store channels"); } + } + outbound_scid_alias + } + /// Creates a new outbound channel to the given remote node and with the given value. /// /// `user_channel_id` will be provided back as in @@ -1762,11 +1628,20 @@ impl ChannelMana let per_peer_state = self.per_peer_state.read().unwrap(); match per_peer_state.get(&their_network_key) { Some(peer_state) => { + let outbound_scid_alias = self.create_and_insert_outbound_scid_alias(); let peer_state = peer_state.lock().unwrap(); let their_features = &peer_state.latest_features; let config = if override_config.is_some() { override_config.as_ref().unwrap() } else { &self.default_configuration }; - Channel::new_outbound(&self.fee_estimator, &self.keys_manager, their_network_key, their_features, - channel_value_satoshis, push_msat, user_channel_id, config, self.best_block.read().unwrap().height())? + match Channel::new_outbound(&self.fee_estimator, &self.keys_manager, their_network_key, + their_features, channel_value_satoshis, push_msat, user_channel_id, config, + self.best_block.read().unwrap().height(), outbound_scid_alias) + { + Ok(res) => res, + Err(e) => { + self.outbound_scid_aliases.lock().unwrap().remove(&outbound_scid_alias); + return Err(e); + }, + } }, None => return Err(APIError::ChannelUnavailable { err: format!("Not connected to node: {}", their_network_key) }), } @@ -1781,7 +1656,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???"); @@ -1802,8 +1677,7 @@ impl ChannelMana let channel_state = self.channel_state.lock().unwrap(); 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 balance = channel.get_available_balances(); let (to_remote_reserve_satoshis, to_self_reserve_satoshis) = channel.get_holder_counterparty_selected_channel_reserve_satoshis(); res.push(ChannelDetails { @@ -1813,14 +1687,27 @@ impl ChannelMana features: InitFeatures::empty(), unspendable_punishment_reserve: to_remote_reserve_satoshis, forwarding_info: channel.counterparty_forwarding_info(), + // Ensures that we have actually received the `htlc_minimum_msat` value + // from the counterparty through the `OpenChannel` or `AcceptChannel` + // message (as they are always the first message from the counterparty). + // Else `Channel::get_counterparty_htlc_minimum_msat` could return the + // default `0` value set by `Channel::new_outbound`. + outbound_htlc_minimum_msat: if channel.have_received_message() { + Some(channel.get_counterparty_htlc_minimum_msat()) } else { None }, + outbound_htlc_maximum_msat: channel.get_counterparty_htlc_maximum_msat(), }, funding_txo: channel.get_funding_txo(), + // Note that accept_channel (or open_channel) is always the first message, so + // `have_received_message` indicates that type negotiation has completed. + channel_type: if channel.have_received_message() { Some(channel.get_channel_type().clone()) } else { None }, short_channel_id: channel.get_short_channel_id(), + inbound_scid_alias: channel.latest_inbound_scid_alias(), channel_value_satoshis: channel.get_value_satoshis(), unspendable_punishment_reserve: to_self_reserve_satoshis, - balance_msat, - inbound_capacity_msat, - outbound_capacity_msat, + balance_msat: balance.balance_msat, + inbound_capacity_msat: balance.inbound_capacity_msat, + outbound_capacity_msat: balance.outbound_capacity_msat, + next_outbound_htlc_limit_msat: balance.next_outbound_htlc_limit_msat, user_channel_id: channel.get_user_id(), confirmations_required: channel.minimum_depth(), force_close_spend_delay: channel.get_counterparty_selected_contest_delay(), @@ -1828,6 +1715,8 @@ impl ChannelMana is_funding_locked: channel.is_usable(), is_usable: channel.is_live(), is_public: channel.should_announce(), + inbound_htlc_minimum_msat: Some(channel.get_holder_htlc_minimum_msat()), + inbound_htlc_maximum_msat: channel.get_holder_htlc_maximum_msat() }); } } @@ -1901,9 +1790,9 @@ impl ChannelMana if let Some(monitor_update) = monitor_update { if let Err(e) = self.chain_monitor.update_channel(chan_entry.get().get_funding_txo().unwrap(), monitor_update) { let (result, is_permanent) = - handle_monitor_err!(self, e, channel_state.short_to_id, chan_entry.get_mut(), RAACommitmentOrder::CommitmentFirst, false, false, Vec::new(), Vec::new(), Vec::new(), chan_entry.key()); + handle_monitor_err!(self, e, channel_state.short_to_id, chan_entry.get_mut(), RAACommitmentOrder::CommitmentFirst, chan_entry.key(), NO_UPDATE); if is_permanent { - remove_channel!(channel_state, chan_entry); + remove_channel!(self, channel_state, chan_entry); break result; } } @@ -1915,7 +1804,7 @@ impl ChannelMana }); if chan_entry.get().is_shutdown() { - let channel = remove_channel!(channel_state, chan_entry); + let channel = remove_channel!(self, channel_state, chan_entry); if let Ok(channel_update) = self.get_channel_update_for_broadcast(&channel) { channel_state.pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate { msg: channel_update @@ -2009,9 +1898,6 @@ impl ChannelMana return Err(APIError::ChannelUnavailable{err: "No such channel".to_owned()}); } } - if let Some(short_id) = chan.get().get_short_channel_id() { - channel_state.short_to_id.remove(&short_id); - } if peer_node_id.is_some() { if let Some(peer_msg) = peer_msg { self.issue_channel_close_events(chan.get(),ClosureReason::CounterpartyForceClosed { peer_msg: peer_msg.to_string() }); @@ -2019,7 +1905,7 @@ impl ChannelMana } else { self.issue_channel_close_events(chan.get(),ClosureReason::HolderForceClosed); } - chan.remove_entry().1 + remove_channel!(self, channel_state, chan) } else { return Err(APIError::ChannelUnavailable{err: "No such channel".to_owned()}); } @@ -2064,6 +1950,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) => { @@ -2088,7 +2071,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 @@ -2100,13 +2082,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) => { @@ -2124,164 +2099,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()); @@ -2292,48 +2173,63 @@ 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(); + 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(("Refusing to forward to a private channel based on our config.", 0x4000 | 10, None)); + } + if chan.get_channel_type().supports_scid_privacy() && *short_channel_id != chan.outbound_scid_alias() { + // `option_scid_alias` (referred to in LDK as `scid_privacy`) means + // "refuse to forward unless the SCID alias was used", so we pretend + // we don't have the channel here. + break Some(("Refusing to forward over real channel SCID as our counterparty requested.", 0x4000 | 10, None)); + } + let chan_update_opt = self.get_channel_update_for_onion(*short_channel_id, chan).ok(); + + // 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) }; - 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, 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)); @@ -2347,27 +2243,28 @@ 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; } { - let mut res = Vec::with_capacity(8 + 128); + let mut res = VecWriter(Vec::with_capacity(chan_update.serialized_length() + 8 + 2)); if let Some(chan_update) = chan_update { if code == 0x1000 | 11 || code == 0x1000 | 12 { - res.extend_from_slice(&byte_utils::be64_to_array(msg.amount_msat)); + msg.amount_msat.write(&mut res).expect("Writes cannot fail"); } else if code == 0x1000 | 13 { - res.extend_from_slice(&byte_utils::be32_to_array(msg.cltv_expiry)); + msg.cltv_expiry.write(&mut res).expect("Writes cannot fail"); } else if code == 0x1000 | 20 { // TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791 - res.extend_from_slice(&byte_utils::be16_to_array(0)); + 0u16.write(&mut res).expect("Writes cannot fail"); } - res.extend_from_slice(&chan_update.encode_with_len()[..]); + (chan_update.serialized_length() as u16).write(&mut res).expect("Writes cannot fail"); + chan_update.write(&mut res).expect("Writes cannot fail"); } - return_err!(err, code, &res[..]); + return_err!(err, code, &res.0[..]); } } } @@ -2403,6 +2300,10 @@ impl ChannelMana Some(id) => id, }; + self.get_channel_update_for_onion(short_channel_id, chan) + } + fn get_channel_update_for_onion(&self, short_channel_id: u64, chan: &Channel) -> Result { + log_trace!(self.logger, "Generating channel update for channel {}", log_bytes!(chan.channel_id())); let were_node_one = PublicKey::from_secret_key(&self.secp_ctx, &self.our_network_key).serialize()[..] < chan.get_counterparty_node_id().serialize()[..]; let unsigned = msgs::UnsignedChannelUpdate { @@ -2941,7 +2842,7 @@ impl ChannelMana excess_data: Vec::new(), }; let msghash = hash_to_message!(&Sha256dHash::hash(&announcement.encode()[..])[..]); - let node_announce_sig = self.secp_ctx.sign(&msghash, &self.our_network_key); + let node_announce_sig = sign(&self.secp_ctx, &msghash, &self.our_network_key); let mut channel_state_lock = self.channel_state.lock().unwrap(); let channel_state = &mut *channel_state_lock; @@ -2983,6 +2884,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(); @@ -2993,21 +2895,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 @@ -3035,6 +2983,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) => { @@ -3043,9 +2993,9 @@ impl ChannelMana } else { panic!("Stated return value requirements in send_htlc() were not met"); } - let chan_update = self.get_channel_update_for_unicast(chan.get()).unwrap(); + let (failure_code, data) = self.get_htlc_temp_fail_err_and_data(0x1000|7, short_chan_id, chan.get()); failed_forwards.push((htlc_source, payment_hash, - HTLCFailReason::Reason { failure_code: 0x1000 | 7, data: chan_update.encode_with_len() } + HTLCFailReason::Reason { failure_code, data } )); continue; }, @@ -3111,12 +3061,9 @@ impl ChannelMana } ChannelError::Close(msg) => { log_trace!(self.logger, "Closing channel {} due to Close-required error: {}", log_bytes!(chan.key()[..]), msg); - let (channel_id, mut channel) = chan.remove_entry(); - if let Some(short_id) = channel.get_short_channel_id() { - channel_state.short_to_id.remove(&short_id); - } + let mut channel = remove_channel!(self, channel_state, chan); // ChannelClosed event is generated by handle_error for us. - Err(MsgHandleErrInternal::from_finish_shutdown(msg, channel_id, channel.get_user_id(), channel.force_shutdown(true), self.get_channel_update_for_broadcast(&channel).ok())) + Err(MsgHandleErrInternal::from_finish_shutdown(msg, channel.channel_id(), channel.get_user_id(), channel.force_shutdown(true), self.get_channel_update_for_broadcast(&channel).ok())) }, ChannelError::CloseDelayBroadcast(_) => { panic!("Wait is only generated on receipt of channel_reestablish, which is handled by try_chan_entry, we don't bother to support it here"); } }; @@ -3151,11 +3098,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"); } @@ -3166,8 +3113,10 @@ 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, + timer_ticks: 0, cltv_expiry, onion_payload, }; @@ -3183,6 +3132,7 @@ 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 } )); @@ -3191,7 +3141,6 @@ impl ChannelMana macro_rules! check_total_value { ($payment_data_total_msat: expr, $payment_secret: expr, $payment_preimage: expr) => {{ - let mut total_value = 0; let mut payment_received_generated = false; let htlcs = channel_state.claimable_htlcs.entry(payment_hash) .or_insert(Vec::new()); @@ -3202,7 +3151,7 @@ impl ChannelMana continue } } - htlcs.push(claimable_htlc); + let mut total_value = claimable_htlc.value; for htlc in htlcs.iter() { total_value += htlc.value; match &htlc.onion_payload { @@ -3220,10 +3169,9 @@ impl ChannelMana 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); - } + 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 { @@ -3237,6 +3185,7 @@ impl ChannelMana // 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 }} @@ -3319,6 +3268,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); @@ -3388,7 +3338,7 @@ impl ChannelMana let ret_err = match res { Ok(Some((update_fee, commitment_signed, monitor_update))) => { if let Err(e) = self.chain_monitor.update_channel(chan.get_funding_txo().unwrap(), monitor_update) { - let (res, drop) = handle_monitor_err!(self, e, short_to_id, chan, RAACommitmentOrder::CommitmentFirst, false, true, Vec::new(), Vec::new(), Vec::new(), chan_id); + let (res, drop) = handle_monitor_err!(self, e, short_to_id, chan, RAACommitmentOrder::CommitmentFirst, chan_id, COMMITMENT_UPDATE_ONLY); if drop { retain_channel = false; } res } else { @@ -3461,6 +3411,7 @@ impl ChannelMana let new_feerate = self.fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal); let mut handle_errors = Vec::new(); + let mut timed_out_mpp_htlcs = Vec::new(); { let mut channel_state_lock = self.channel_state.lock().unwrap(); let channel_state = &mut *channel_state_lock; @@ -3509,6 +3460,32 @@ impl ChannelMana true }); + + channel_state.claimable_htlcs.retain(|payment_hash, htlcs| { + if htlcs.is_empty() { + // This should be unreachable + debug_assert!(false); + return false; + } + if let OnionPayload::Invoice(ref final_hop_data) = htlcs[0].onion_payload { + // Check if we've received all the parts we need for an MPP (the value of the parts adds to total_msat). + // In this case we're not going to handle any timeouts of the parts here. + if final_hop_data.total_msat == htlcs.iter().fold(0, |total, htlc| total + htlc.value) { + return true; + } else if htlcs.into_iter().any(|htlc| { + htlc.timer_ticks += 1; + return htlc.timer_ticks >= MPP_TIMEOUT_TICKS + }) { + timed_out_mpp_htlcs.extend(htlcs.into_iter().map(|htlc| (htlc.prev_hop.clone(), payment_hash.clone()))); + return false; + } + } + true + }); + } + + for htlc_source in timed_out_mpp_htlcs.drain(..) { + self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), HTLCSource::PreviousHopData(htlc_source.0), &htlc_source.1, HTLCFailReason::Reason { failure_code: 23, data: Vec::new() }); } for (err, counterparty_node_id) in handle_errors.drain(..) { @@ -3542,6 +3519,51 @@ impl ChannelMana } else { false } } + /// Gets an HTLC onion failure code and error data for an `UPDATE` error, given the error code + /// that we want to return and a channel. + /// + /// This is for failures on the channel on which the HTLC was *received*, not failures + /// forwarding + fn get_htlc_inbound_temp_fail_err_and_data(&self, desired_err_code: u16, chan: &Channel) -> (u16, Vec) { + // We can't be sure what SCID was used when relaying inbound towards us, so we have to + // guess somewhat. If its a public channel, we figure best to just use the real SCID (as + // we're not leaking that we have a channel with the counterparty), otherwise we try to use + // an inbound SCID alias before the real SCID. + let scid_pref = if chan.should_announce() { + chan.get_short_channel_id().or(chan.latest_inbound_scid_alias()) + } else { + chan.latest_inbound_scid_alias().or(chan.get_short_channel_id()) + }; + if let Some(scid) = scid_pref { + self.get_htlc_temp_fail_err_and_data(desired_err_code, scid, chan) + } else { + (0x4000|10, Vec::new()) + } + } + + + /// Gets an HTLC onion failure code and error data for an `UPDATE` error, given the error code + /// that we want to return and a channel. + fn get_htlc_temp_fail_err_and_data(&self, desired_err_code: u16, scid: u64, chan: &Channel) -> (u16, Vec) { + debug_assert_eq!(desired_err_code & 0x1000, 0x1000); + if let Ok(upd) = self.get_channel_update_for_onion(scid, chan) { + let mut enc = VecWriter(Vec::with_capacity(upd.serialized_length() + 4)); + if desired_err_code == 0x1000 | 20 { + // TODO: underspecified, follow https://github.com/lightning/bolts/issues/791 + 0u16.write(&mut enc).expect("Writes cannot fail"); + } + (upd.serialized_length() as u16).write(&mut enc).expect("Writes cannot fail"); + upd.write(&mut enc).expect("Writes cannot fail"); + (desired_err_code, enc.0) + } else { + // If we fail to get a unicast channel_update, it implies we don't yet have an SCID, + // which means we really shouldn't have gotten a payment to be forwarded over this + // channel yet, or if we did it's from a route hint. Either way, returning an error of + // PERM|no_such_channel should be fine. + (0x4000|10, Vec::new()) + } + } + // Fail a list of HTLCs that were just freed from the holding cell. The HTLCs need to be // failed backwards or, if they were one of our outgoing HTLCs, then their failure needs to // be surfaced to the user. @@ -3552,11 +3574,7 @@ impl ChannelMana let (failure_code, onion_failure_data) = match self.channel_state.lock().unwrap().by_id.entry(channel_id) { hash_map::Entry::Occupied(chan_entry) => { - if let Ok(upd) = self.get_channel_update_for_unicast(&chan_entry.get()) { - (0x1000|7, upd.encode_with_len()) - } else { - (0x4000|10, Vec::new()) - } + self.get_htlc_inbound_temp_fail_err_and_data(0x1000|7, &chan_entry.get()) }, hash_map::Entry::Vacant(_) => (0x4000|10, Vec::new()) }; @@ -3722,12 +3740,18 @@ impl ChannelMana 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)); @@ -4026,7 +4050,10 @@ impl ChannelMana } else { None }; let mut pending_events = self.pending_events.lock().unwrap(); + + let source_channel_id = Some(prev_outpoint.to_channel_id()); pending_events.push(events::Event::PaymentForwarded { + source_channel_id, fee_earned_msat, claim_from_onchain_tx: from_onchain, }); @@ -4063,10 +4090,12 @@ impl ChannelMana // 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(), - }) + if let Ok(msg) = self.get_channel_update_for_unicast(channel.get()) { + Some(events::MessageSendEvent::SendChannelUpdate { + node_id: channel.get().get_counterparty_node_id(), + msg, + }) + } else { None } } 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, updates.announcement_sigs); if let Some(upd) = channel_update { @@ -4086,8 +4115,13 @@ impl ChannelMana /// /// 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> { + /// For inbound channels, the `user_channel_id` parameter will be provided back in + /// [`Event::ChannelClosed::user_channel_id`] to allow tracking of which events correspond + /// with which `accept_inbound_channel` call. + /// + /// [`Event::OpenChannelRequest`]: events::Event::OpenChannelRequest + /// [`Event::ChannelClosed::user_channel_id`]: events::Event::ChannelClosed::user_channel_id + pub fn accept_inbound_channel(&self, temporary_channel_id: &[u8; 32], user_channel_id: u64) -> 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(); @@ -4099,7 +4133,7 @@ impl ChannelMana } channel_state.pending_msg_events.push(events::MessageSendEvent::SendAcceptChannel { node_id: channel.get().get_counterparty_node_id(), - msg: channel.get_mut().accept_inbound_channel(), + msg: channel.get_mut().accept_inbound_channel(user_channel_id), }); } hash_map::Entry::Vacant(_) => { @@ -4118,18 +4152,29 @@ impl ChannelMana return Err(MsgHandleErrInternal::send_err_msg_no_close("No inbound channels accepted".to_owned(), msg.temporary_channel_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 outbound_scid_alias = self.create_and_insert_outbound_scid_alias(); + let mut channel = match 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, outbound_scid_alias) + { + Err(e) => { + self.outbound_scid_aliases.lock().unwrap().remove(&outbound_scid_alias); + return Err(MsgHandleErrInternal::from_chan_no_close(e, msg.temporary_channel_id)); + }, + Ok(res) => res + }; let mut channel_state_lock = self.channel_state.lock().unwrap(); let channel_state = &mut *channel_state_lock; 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::Occupied(_) => { + self.outbound_scid_aliases.lock().unwrap().remove(&outbound_scid_alias); + return Err(MsgHandleErrInternal::send_err_msg_no_close("temporary_channel_id collision!".to_owned(), msg.temporary_channel_id.clone())) + }, hash_map::Entry::Vacant(entry) => { 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(), + msg: channel.accept_inbound_channel(0), }); } else { let mut pending_events = self.pending_events.lock().unwrap(); @@ -4139,6 +4184,7 @@ impl ChannelMana counterparty_node_id: counterparty_node_id.clone(), funding_satoshis: msg.funding_satoshis, push_msat: msg.push_msat, + channel_type: channel.get_channel_type().clone(), } ); } @@ -4290,10 +4336,12 @@ impl ChannelMana // 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(), - }); + if let Ok(msg) = self.get_channel_update_for_unicast(chan.get()) { + channel_state.pending_msg_events.push(events::MessageSendEvent::SendChannelUpdate { + node_id: counterparty_node_id.clone(), + msg, + }); + } } Ok(()) }, @@ -4326,9 +4374,9 @@ impl ChannelMana if let Some(monitor_update) = monitor_update { if let Err(e) = self.chain_monitor.update_channel(chan_entry.get().get_funding_txo().unwrap(), monitor_update) { let (result, is_permanent) = - handle_monitor_err!(self, e, channel_state.short_to_id, chan_entry.get_mut(), RAACommitmentOrder::CommitmentFirst, false, false, Vec::new(), Vec::new(), Vec::new(), chan_entry.key()); + handle_monitor_err!(self, e, channel_state.short_to_id, chan_entry.get_mut(), RAACommitmentOrder::CommitmentFirst, chan_entry.key(), NO_UPDATE); if is_permanent { - remove_channel!(channel_state, chan_entry); + remove_channel!(self, channel_state, chan_entry); break result; } } @@ -4376,10 +4424,7 @@ impl ChannelMana // also implies there are no pending HTLCs left on the channel, so we can // fully delete it from tracking (the channel monitor is still around to // watch for old state broadcasts)! - if let Some(short_id) = chan_entry.get().get_short_channel_id() { - channel_state.short_to_id.remove(&short_id); - } - (tx, Some(chan_entry.remove_entry().1)) + (tx, Some(remove_channel!(self, channel_state, chan_entry))) } else { (tx, None) } }, hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel".to_owned(), msg.channel_id)) @@ -4427,26 +4472,8 @@ impl ChannelMana match pending_forward_info { PendingHTLCStatus::Forward(PendingHTLCInfo { ref incoming_shared_secret, .. }) => { let reason = if (error_code & 0x1000) != 0 { - if let Ok(upd) = self.get_channel_update_for_unicast(chan) { - 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)); - res.extend_from_slice(&upd.encode_with_len()[..]); - res - }[..]) - } else { - // The only case where we'd be unable to - // successfully get a channel update is if the - // channel isn't in the fully-funded state yet, - // implying our counterparty is trying to route - // payments over the channel back to themselves - // (because no one else should know the short_id - // is a lightning channel yet). We should have - // no problem just calling this - // unknown_next_peer (0x4000|10). - onion_utils::build_first_hop_failure_packet(incoming_shared_secret, 0x4000|10, &[]) - } + let (real_code, error_data) = self.get_htlc_inbound_temp_fail_err_and_data(error_code, chan); + onion_utils::build_first_hop_failure_packet(incoming_shared_secret, real_code, &error_data) } else { onion_utils::build_first_hop_failure_packet(incoming_shared_secret, error_code, &[]) }; @@ -4768,10 +4795,12 @@ impl ChannelMana // If the channel is in a usable state (ie the channel is not being shut // down), send a unicast channel_update to our counterparty to make sure // they have the latest channel parameters. - channel_update = Some(events::MessageSendEvent::SendChannelUpdate { - node_id: chan.get().get_counterparty_node_id(), - msg: self.get_channel_update_for_unicast(chan.get()).unwrap(), - }); + if let Ok(msg) = self.get_channel_update_for_unicast(chan.get()) { + channel_update = Some(events::MessageSendEvent::SendChannelUpdate { + node_id: chan.get().get_counterparty_node_id(), + msg, + }); + } } let need_lnd_workaround = chan.get_mut().workaround_lnd_bug_4006.take(); chan_restoration_res = handle_chan_restoration_locked!( @@ -4815,12 +4844,9 @@ impl ChannelMana let mut channel_lock = self.channel_state.lock().unwrap(); let channel_state = &mut *channel_lock; let by_id = &mut channel_state.by_id; - let short_to_id = &mut channel_state.short_to_id; let pending_msg_events = &mut channel_state.pending_msg_events; - if let Some(mut chan) = by_id.remove(&funding_outpoint.to_channel_id()) { - if let Some(short_id) = chan.get_short_channel_id() { - short_to_id.remove(&short_id); - } + if let hash_map::Entry::Occupied(chan_entry) = by_id.entry(funding_outpoint.to_channel_id()) { + let mut chan = remove_channel!(self, channel_state, chan_entry); failed_channels.push(chan.force_shutdown(false)); if let Ok(update) = self.get_channel_update_for_broadcast(&chan) { pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate { @@ -4857,7 +4883,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(); } @@ -4890,7 +4916,7 @@ impl ChannelMana if let Some((commitment_update, monitor_update)) = commitment_opt { if let Err(e) = self.chain_monitor.update_channel(chan.get_funding_txo().unwrap(), monitor_update) { has_monitor_update = true; - let (res, close_channel) = handle_monitor_err!(self, e, short_to_id, chan, RAACommitmentOrder::CommitmentFirst, false, true, Vec::new(), Vec::new(), Vec::new(), channel_id); + let (res, close_channel) = handle_monitor_err!(self, e, short_to_id, chan, RAACommitmentOrder::CommitmentFirst, channel_id, COMMITMENT_UPDATE_ONLY); handle_errors.push((chan.get_counterparty_node_id(), res)); if close_channel { return false; } } else { @@ -4949,10 +4975,6 @@ impl ChannelMana if let Some(tx) = tx_opt { // We're done with this channel. We got a closing_signed and sent back // a closing_signed with a closing transaction to broadcast. - if let Some(short_id) = chan.get_short_channel_id() { - short_to_id.remove(&short_id); - } - if let Ok(update) = self.get_channel_update_for_broadcast(&chan) { pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate { msg: update @@ -4963,6 +4985,7 @@ impl ChannelMana log_info!(self.logger, "Broadcasting {}", log_tx!(tx)); self.tx_broadcaster.broadcast_transaction(&tx); + update_maps_on_chan_removal!(self, short_to_id, chan); false } else { true } }, @@ -5070,6 +5093,8 @@ impl ChannelMana /// 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. /// + /// May panic if `invoice_expiry_delta_secs` is greater than one year. + /// /// # Note /// This method is deprecated and will be removed soon. /// @@ -5110,8 +5135,6 @@ impl ChannelMana /// If you need exact expiry semantics, you should enforce them upon receipt of /// [`PaymentReceived`]. /// - /// 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`]. /// @@ -5134,6 +5157,8 @@ impl ChannelMana /// 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. /// + /// May panic if `invoice_expiry_delta_secs` is greater than one year. + /// /// # Note /// This method is deprecated and will be removed soon. /// @@ -5151,7 +5176,35 @@ impl ChannelMana inbound_payment::get_payment_preimage(payment_hash, payment_secret, &self.inbound_payment_key) } - #[cfg(any(test, feature = "fuzztarget", feature = "_test_utils"))] + /// 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::Namespace::Phantom.get_fake_scid(best_block.height(), &self.genesis_hash, &self.fake_scid_rand_bytes, &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()); @@ -5306,6 +5359,12 @@ where 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.genesis_hash.clone(), self.get_our_node_id(), &self.logger) .map(|(a, b)| (a, Vec::new(), b))); + + let last_best_block_height = self.best_block.read().unwrap().height(); + if height < last_best_block_height { + let timestamp = self.highest_seen_timestamp.load(Ordering::Acquire); + self.do_chain_event(Some(last_best_block_height), |channel| channel.best_block_updated(last_best_block_height, timestamp as u32, self.genesis_hash.clone(), self.get_our_node_id(), &self.logger)); + } } fn best_block_updated(&self, header: &BlockHeader, height: u32) { @@ -5412,27 +5471,24 @@ where let res = f(channel); 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 { - failure_code: 0x1000 | 14, // expiry_too_soon, or at least it is now - data: chan_update, + let (failure_code, data) = self.get_htlc_inbound_temp_fail_err_and_data(0x1000|14 /* expiry_too_soon */, &channel); + timed_out_htlcs.push((source, payment_hash, HTLCFailReason::Reason { + failure_code, data, })); } 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, - }); + send_funding_locked!(short_to_id, pending_msg_events, channel, funding_locked); 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(), - }); + if let Ok(msg) = self.get_channel_update_for_unicast(channel) { + pending_msg_events.push(events::MessageSendEvent::SendChannelUpdate { + node_id: channel.get_counterparty_node_id(), + msg, + }); + } } else { 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())); @@ -5452,9 +5508,7 @@ where } } } else if let Err(reason) = res { - if let Some(short_id) = channel.get_short_channel_id() { - short_to_id.remove(&short_id); - } + update_maps_on_chan_removal!(self, short_to_id, channel); // It looks like our counterparty went on-chain or funding transaction was // reorged out of the main chain. Close the channel. failed_channels.push(channel.force_shutdown(true)); @@ -5644,15 +5698,13 @@ impl { let mut channel_state_lock = self.channel_state.lock().unwrap(); let channel_state = &mut *channel_state_lock; - let short_to_id = &mut channel_state.short_to_id; let pending_msg_events = &mut channel_state.pending_msg_events; + let short_to_id = &mut channel_state.short_to_id; if no_connection_possible { log_debug!(self.logger, "Failing all channels with {} due to no_connection_possible", log_pubkey!(counterparty_node_id)); channel_state.by_id.retain(|_, chan| { if chan.get_counterparty_node_id() == *counterparty_node_id { - if let Some(short_id) = chan.get_short_channel_id() { - short_to_id.remove(&short_id); - } + update_maps_on_chan_removal!(self, short_to_id, chan); failed_channels.push(chan.force_shutdown(true)); if let Ok(update) = self.get_channel_update_for_broadcast(&chan) { pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate { @@ -5671,9 +5723,7 @@ impl if chan.get_counterparty_node_id() == *counterparty_node_id { chan.remove_uncommitted_htlcs_and_mark_paused(&self.logger); if chan.is_shutdown() { - if let Some(short_id) = chan.get_short_channel_id() { - short_to_id.remove(&short_id); - } + update_maps_on_chan_removal!(self, short_to_id, chan); self.issue_channel_close_events(chan, ClosureReason::DisconnectedPeer); return false; } else { @@ -5704,6 +5754,7 @@ impl &events::MessageSendEvent::SendChannelRangeQuery { .. } => false, &events::MessageSendEvent::SendShortIdsQuery { .. } => false, &events::MessageSendEvent::SendReplyChannelRange { .. } => false, + &events::MessageSendEvent::SendGossipTimestampFilter { .. } => false, } }); } @@ -5769,6 +5820,23 @@ impl } } } else { + { + // First check if we can advance the channel type and try again. + let mut channel_state = self.channel_state.lock().unwrap(); + if let Some(chan) = channel_state.by_id.get_mut(&msg.channel_id) { + if chan.get_counterparty_node_id() != *counterparty_node_id { + return; + } + if let Ok(msg) = chan.maybe_handle_error_without_close(self.genesis_hash) { + channel_state.pending_msg_events.push(events::MessageSendEvent::SendOpenChannel { + node_id: *counterparty_node_id, + msg, + }); + return; + } + } + } + // Untrusted messages from peer, we throw away the error if id points to a non-existent channel let _ = self.force_close_channel_with_peer(&msg.channel_id, Some(counterparty_node_id), Some(&msg.data)); } @@ -5849,6 +5917,53 @@ 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), + (9, outbound_htlc_minimum_msat, option), + (11, outbound_htlc_maximum_msat, option), +}); + +impl_writeable_tlv_based!(ChannelDetails, { + (1, inbound_scid_alias, option), + (2, channel_id, required), + (3, channel_type, option), + (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), + // Note that by the time we get past the required read above, outbound_capacity_msat will be + // filled in, so we can safely unwrap it here. + (19, next_outbound_htlc_limit_msat, (default_value, outbound_capacity_msat.0.unwrap())), + (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), + (33, inbound_htlc_minimum_msat, option), + (35, inbound_htlc_maximum_msat, option), +}); + +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), @@ -5856,6 +5971,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) => { @@ -5947,6 +6063,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) @@ -6003,6 +6120,7 @@ impl Readable for ClaimableHTLC { }; Ok(Self { prev_hop: prev_hop.0.unwrap(), + timer_ticks: 0, value, onion_payload, cltv_expiry, @@ -6250,7 +6368,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) + (5, self.our_network_pubkey, required), + (7, self.fake_scid_rand_bytes, required), }); Ok(()) @@ -6546,11 +6665,16 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> 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) + (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); @@ -6614,7 +6738,11 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> pending_events_read.append(&mut channel_closures); } - let our_network_pubkey = PublicKey::from_secret_key(&secp_ctx, &args.keys_manager.get_node_secret()); + 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."); @@ -6622,6 +6750,32 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> } } + let mut outbound_scid_aliases = HashSet::new(); + for (chan_id, chan) in by_id.iter_mut() { + if chan.outbound_scid_alias() == 0 { + let mut outbound_scid_alias; + loop { + outbound_scid_alias = fake_scid::Namespace::OutboundAlias + .get_fake_scid(best_block_height, &genesis_hash, fake_scid_rand_bytes.as_ref().unwrap(), &args.keys_manager); + if outbound_scid_aliases.insert(outbound_scid_alias) { break; } + } + chan.set_outbound_scid_alias(outbound_scid_alias); + } else if !outbound_scid_aliases.insert(chan.outbound_scid_alias()) { + // Note that in rare cases its possible to hit this while reading an older + // channel if we just happened to pick a colliding outbound alias above. + log_error!(args.logger, "Got duplicate outbound SCID alias; {}", chan.outbound_scid_alias()); + return Err(DecodeError::InvalidValue); + } + if chan.is_usable() { + if short_to_id.insert(chan.outbound_scid_alias(), *chan_id).is_some() { + // Note that in rare cases its possible to hit this while reading an older + // channel if we just happened to pick a colliding outbound alias above. + log_error!(args.logger, "Got duplicate outbound SCID alias; {}", chan.outbound_scid_alias()); + 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 { @@ -6643,7 +6797,10 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> pending_inbound_payments: Mutex::new(pending_inbound_payments), pending_outbound_payments: Mutex::new(pending_outbound_payments.unwrap()), - our_network_key: args.keys_manager.get_node_secret(), + outbound_scid_aliases: Mutex::new(outbound_scid_aliases), + fake_scid_rand_bytes: fake_scid_rand_bytes.unwrap(), + + our_network_key, our_network_pubkey, secp_ctx, @@ -6690,6 +6847,7 @@ mod tests { use util::errors::APIError; use util::events::{Event, MessageSendEvent, MessageSendEventsProvider}; use util::test_utils; + use chain::keysinterface::KeysInterface; #[cfg(feature = "std")] #[test] @@ -6943,6 +7101,7 @@ mod tests { 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_penalty(0); + let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes(); // To start (1), send a regular payment but don't claim it. let expected_route = [&nodes[1]]; @@ -6956,7 +7115,7 @@ mod tests { }; let route = find_route( &nodes[0].node.get_our_node_id(), &route_params, nodes[0].network_graph, None, - nodes[0].logger, &scorer + nodes[0].logger, &scorer, &random_seed_bytes ).unwrap(); nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage)).unwrap(); check_added_monitors!(nodes[0], 1); @@ -6987,7 +7146,7 @@ mod tests { let payment_preimage = PaymentPreimage([42; 32]); let route = find_route( &nodes[0].node.get_our_node_id(), &route_params, nodes[0].network_graph, None, - nodes[0].logger, &scorer + nodes[0].logger, &scorer, &random_seed_bytes ).unwrap(); let (payment_hash, _) = nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage)).unwrap(); check_added_monitors!(nodes[0], 1); @@ -7036,8 +7195,8 @@ mod tests { let payer_pubkey = nodes[0].node.get_our_node_id(); let payee_pubkey = nodes[1].node.get_our_node_id(); - nodes[0].node.peer_connected(&payee_pubkey, &msgs::Init { features: InitFeatures::known() }); - nodes[1].node.peer_connected(&payer_pubkey, &msgs::Init { features: InitFeatures::known() }); + nodes[0].node.peer_connected(&payee_pubkey, &msgs::Init { features: InitFeatures::known(), remote_network_address: None }); + nodes[1].node.peer_connected(&payer_pubkey, &msgs::Init { features: InitFeatures::known(), remote_network_address: None }); let _chan = create_chan_between_nodes(&nodes[0], &nodes[1], InitFeatures::known(), InitFeatures::known()); let route_params = RouteParameters { @@ -7048,9 +7207,10 @@ mod tests { let network_graph = nodes[0].network_graph; let first_hops = nodes[0].node.list_usable_channels(); let scorer = test_utils::TestScorer::with_penalty(0); + let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes(); let route = find_route( &payer_pubkey, &route_params, network_graph, Some(&first_hops.iter().collect::>()), - nodes[0].logger, &scorer + nodes[0].logger, &scorer, &random_seed_bytes ).unwrap(); let test_preimage = PaymentPreimage([42; 32]); @@ -7079,8 +7239,8 @@ mod tests { let payer_pubkey = nodes[0].node.get_our_node_id(); let payee_pubkey = nodes[1].node.get_our_node_id(); - nodes[0].node.peer_connected(&payee_pubkey, &msgs::Init { features: InitFeatures::known() }); - nodes[1].node.peer_connected(&payer_pubkey, &msgs::Init { features: InitFeatures::known() }); + nodes[0].node.peer_connected(&payee_pubkey, &msgs::Init { features: InitFeatures::known(), remote_network_address: None }); + nodes[1].node.peer_connected(&payer_pubkey, &msgs::Init { features: InitFeatures::known(), remote_network_address: None }); let _chan = create_chan_between_nodes(&nodes[0], &nodes[1], InitFeatures::known(), InitFeatures::known()); let route_params = RouteParameters { @@ -7091,9 +7251,10 @@ mod tests { let network_graph = nodes[0].network_graph; let first_hops = nodes[0].node.list_usable_channels(); let scorer = test_utils::TestScorer::with_penalty(0); + let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes(); let route = find_route( &payer_pubkey, &route_params, network_graph, Some(&first_hops.iter().collect::>()), - nodes[0].logger, &scorer + nodes[0].logger, &scorer, &random_seed_bytes ).unwrap(); let test_preimage = PaymentPreimage([42; 32]); @@ -7164,7 +7325,7 @@ mod tests { 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); + nodes[0].logger.assert_log_contains("lightning::ln::inbound_payment".to_string(), "Failing HTLC with user-generated payment_hash".to_string(), 1); } } @@ -7173,11 +7334,11 @@ mod tests { } } -#[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}; - use chain::keysinterface::{KeysManager, InMemorySigner}; + use chain::keysinterface::{KeysManager, KeysInterface, InMemorySigner}; use ln::channelmanager::{BestBlock, ChainParameters, ChannelManager, PaymentHash, PaymentPreimage}; use ln::features::{InitFeatures, InvoiceFeatures}; use ln::functional_test_utils::*; @@ -7186,7 +7347,7 @@ pub mod bench { use routing::router::{PaymentParameters, get_route}; use util::test_utils; use util::config::UserConfig; - use util::events::{Event, MessageSendEvent, MessageSendEventsProvider, PaymentPurpose}; + use util::events::{Event, MessageSendEvent, MessageSendEventsProvider}; use bitcoin::hashes::Hash; use bitcoin::hashes::sha256::Hash as Sha256; @@ -7244,8 +7405,8 @@ pub mod bench { }); let node_b_holder = NodeHolder { node: &node_b }; - node_a.peer_connected(&node_b.get_our_node_id(), &Init { features: InitFeatures::known() }); - node_b.peer_connected(&node_a.get_our_node_id(), &Init { features: InitFeatures::known() }); + node_a.peer_connected(&node_b.get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None }); + node_b.peer_connected(&node_a.get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None }); node_a.create_channel(node_b.get_our_node_id(), 8_000_000, 100_000_000, 42, None).unwrap(); node_b.handle_open_channel(&node_a.get_our_node_id(), InitFeatures::known(), &get_event_msg!(node_a_holder, MessageSendEvent::SendOpenChannel, node_b.get_our_node_id())); node_a.handle_accept_channel(&node_b.get_our_node_id(), InitFeatures::known(), &get_event_msg!(node_b_holder, MessageSendEvent::SendAcceptChannel, node_a.get_our_node_id())); @@ -7294,8 +7455,11 @@ pub mod bench { let payment_params = PaymentParameters::from_node_id($node_b.get_our_node_id()) .with_features(InvoiceFeatures::known()); 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 seed = [3u8; 32]; + let keys_manager = KeysManager::new(&seed, 42, 42); + let random_seed_bytes = keys_manager.get_secure_random_bytes(); + let route = get_route(&$node_a.get_our_node_id(), &payment_params, &dummy_graph.read_only(), + Some(&usable_channels.iter().map(|r| r).collect::>()), 10_000, TEST_FINAL_CLTV, &logger_a, &scorer, &random_seed_bytes).unwrap(); let mut payment_preimage = PaymentPreimage([0; 32]); payment_preimage.0[0..8].copy_from_slice(&payment_count.to_le_bytes());