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 util::events::{EventHandler, EventsProvider, MessageSendEvent, MessageSendEventsProvider, ClosureReason};
use util::{byte_utils, events};
use util::scid_utils::fake_scid;
-use util::ser::{BigSize, FixedLengthReader, Readable, ReadableArgs, MaybeReadable, Writeable, Writer};
+use util::ser::{BigSize, FixedLengthReader, Readable, ReadableArgs, MaybeReadable, Writeable, Writer, VecWriter};
use util::logger::{Level, Logger};
use util::errors::APIError;
#[cfg(any(test, feature = "std"))]
use std::time::Instant;
-
-mod inbound_payment {
- use alloc::string::ToString;
- use bitcoin::hashes::{Hash, HashEngine};
- use bitcoin::hashes::cmp::fixed_time_eq;
- use bitcoin::hashes::hmac::{Hmac, HmacEngine};
- use bitcoin::hashes::sha256::Hash as Sha256;
- use chain::keysinterface::{KeyMaterial, KeysInterface, Sign};
- use ln::{PaymentHash, PaymentPreimage, PaymentSecret};
- use ln::channelmanager::APIError;
- use ln::msgs;
- use ln::msgs::MAX_VALUE_MSAT;
- use util::chacha20::ChaCha20;
- use util::crypto::hkdf_extract_expand_thrice;
- use util::logger::Logger;
-
- use core::convert::TryInto;
- use core::ops::Deref;
-
- const IV_LEN: usize = 16;
- const METADATA_LEN: usize = 16;
- const METADATA_KEY_LEN: usize = 32;
- const AMT_MSAT_LEN: usize = 8;
- // Used to shift the payment type bits to take up the top 3 bits of the metadata bytes, or to
- // retrieve said payment type bits.
- const METHOD_TYPE_OFFSET: usize = 5;
-
- /// A set of keys that were HKDF-expanded from an initial call to
- /// [`KeysInterface::get_inbound_payment_key_material`].
- ///
- /// [`KeysInterface::get_inbound_payment_key_material`]: crate::chain::keysinterface::KeysInterface::get_inbound_payment_key_material
- pub(super) struct ExpandedKey {
- /// The key used to encrypt the bytes containing the payment metadata (i.e. the amount and
- /// expiry, included for payment verification on decryption).
- metadata_key: [u8; 32],
- /// The key used to authenticate an LDK-provided payment hash and metadata as previously
- /// registered with LDK.
- ldk_pmt_hash_key: [u8; 32],
- /// The key used to authenticate a user-provided payment hash and metadata as previously
- /// registered with LDK.
- user_pmt_hash_key: [u8; 32],
- }
-
- impl ExpandedKey {
- pub(super) fn new(key_material: &KeyMaterial) -> ExpandedKey {
- let (metadata_key, ldk_pmt_hash_key, user_pmt_hash_key) =
- hkdf_extract_expand_thrice(b"LDK Inbound Payment Key Expansion", &key_material.0);
- Self {
- metadata_key,
- ldk_pmt_hash_key,
- user_pmt_hash_key,
- }
- }
- }
-
- enum Method {
- LdkPaymentHash = 0,
- UserPaymentHash = 1,
- }
-
- impl Method {
- fn from_bits(bits: u8) -> Result<Method, u8> {
- 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<Signer: Sign, K: Deref>(keys: &ExpandedKey, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32, keys_manager: &K, highest_seen_timestamp: u64) -> Result<(PaymentHash, PaymentSecret), ()>
- where K::Target: KeysInterface<Signer = Signer>
- {
- 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::<Sha256>::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<u64>, payment_hash: PaymentHash, invoice_expiry_delta_secs: u32, highest_seen_timestamp: u64) -> Result<PaymentSecret, ()> {
- let metadata_bytes = construct_metadata_bytes(min_value_msat, Method::UserPaymentHash, invoice_expiry_delta_secs, highest_seen_timestamp)?;
-
- let mut hmac = HmacEngine::<Sha256>::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<u64>, 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<L: Deref>(payment_hash: PaymentHash, payment_data: msgs::FinalOnionHopData, highest_seen_timestamp: u64, keys: &ExpandedKey, logger: &L) -> Result<Option<PaymentPreimage>, ()>
- 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::<Sha256>::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<PaymentPreimage, APIError> {
- 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<PaymentPreimage, [u8; 32]> {
- let mut hmac = HmacEngine::<Sha256>::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))
- }
-}
+use util::crypto::sign;
// We hold various information about HTLC relay in the HTLC objects in Channel itself:
//
}
}
}
+#[cfg(not(feature = "grind_signatures"))]
#[cfg(test)]
impl HTLCSource {
pub fn dummy() -> Self {
/// Note that, if this has been set, `channel_id` will be equivalent to
/// `funding_txo.unwrap().to_channel_id()`.
pub funding_txo: Option<OutPoint>,
+ /// 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<ChannelTypeFeatures>,
/// The position of the funding transaction in the chain. None if the funding transaction has
/// not yet been confirmed and the channel fully opened.
///
/// 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<u64>,
/// The value, in satoshis, of this channel as appears in the funding output
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<u64>,
+ /// The largest value HTLC (in msat) we currently will accept, for this channel.
+ pub inbound_htlc_maximum_msat: Option<u64>,
}
impl ChannelDetails {
- /// Gets the 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.
+ /// 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<u64> {
self.inbound_scid_alias.or(self.short_channel_id)
}
forwarding_info: channel.counterparty_forwarding_info(),
},
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(),
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()
});
}
}
};
let (chan_update_opt, forwardee_cltv_expiry_delta) = if let Some(forwarding_id) = forwarding_id_opt {
let chan = channel_state.as_mut().unwrap().by_id.get_mut(&forwarding_id).unwrap();
- // Leave channel updates as None for private channels.
- let chan_update_opt = if chan.should_announce() {
- Some(self.get_channel_update_for_unicast(chan).unwrap()) } else { None };
if !chan.should_announce() && !self.default_configuration.accept_forwards_to_priv_channels {
// Note that the behavior here should be identical to the above block - we
// should NOT reveal the existence or non-existence of a private channel if
// we don't allow forwards outbound over them.
- break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
+ 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
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[..]);
}
}
}
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<Signer>) -> Result<msgs::ChannelUpdate, LightningError> {
+ 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 {
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;
} 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;
},
} 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<Signer>) -> (u16, Vec<u8>) {
+ // 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<Signer>) -> (u16, Vec<u8>) {
+ 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.
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())
};
// 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 {
///
/// 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();
}
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(_) => {
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();
counterparty_node_id: counterparty_node_id.clone(),
funding_satoshis: msg.funding_satoshis,
push_msat: msg.push_msat,
+ channel_type: channel.get_channel_type().clone(),
}
);
}
// 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(())
},
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
- if error_code == 0x1000 | 20 {
- 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, &[])
};
// 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!(
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 {
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()));
}
}
}
} 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));
}
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),
(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, {
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);
}
}