Skip to content

Commit 9179991

Browse files
Drop need to store pending inbound payments
and replace payment_secret with encrypted metadata See docs on verify_inbound_payment for details
1 parent 7e84c5c commit 9179991

File tree

3 files changed

+250
-18
lines changed

3 files changed

+250
-18
lines changed

lightning/src/ln/channelmanager.rs

+242-12
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ use ln::msgs;
5050
use ln::msgs::NetAddress;
5151
use ln::onion_utils;
5252
use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError, OptionalField};
53-
use chain::keysinterface::{Sign, KeysInterface, KeysManager, InMemorySigner};
53+
use chain::keysinterface::{Sign, KeyMaterial, KeysInterface, KeysManager, InMemorySigner};
5454
use util::config::UserConfig;
5555
use util::events::{EventHandler, EventsProvider, MessageSendEvent, MessageSendEventsProvider, ClosureReason};
5656
use util::{byte_utils, events};
@@ -65,6 +65,7 @@ use core::{cmp, mem};
6565
use core::cell::RefCell;
6666
use io::{Cursor, Read};
6767
use sync::{Arc, Condvar, Mutex, MutexGuard, RwLock, RwLockReadGuard};
68+
use core::convert::TryInto;
6869
use core::sync::atomic::{AtomicUsize, Ordering};
6970
use core::time::Duration;
7071
#[cfg(any(test, feature = "allow_wallclock_use"))]
@@ -642,6 +643,8 @@ pub struct ChannelManager<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref,
642643
our_network_key: SecretKey,
643644
our_network_pubkey: PublicKey,
644645

646+
inbound_payment_key: Mutex<(KeyMaterial, Option<([u8; 32], [u8; 32], [u8; 32])>)>,
647+
645648
/// Used to track the last value sent in a node_announcement "timestamp" field. We ensure this
646649
/// value increases strictly since we don't assume access to a time source.
647650
last_node_announcement_serial: AtomicUsize,
@@ -1342,6 +1345,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
13421345
our_network_pubkey: PublicKey::from_secret_key(&secp_ctx, &keys_manager.get_node_secret()),
13431346
secp_ctx,
13441347

1348+
inbound_payment_key: Mutex::new((keys_manager.get_inbound_payment_key_material(), None)),
1349+
13451350
last_node_announcement_serial: AtomicUsize::new(0),
13461351
highest_seen_timestamp: AtomicUsize::new(0),
13471352

@@ -2589,6 +2594,89 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
25892594
}
25902595
}
25912596

2597+
fn get_expanded_inbound_payment_key(&self) -> ([u8; 32], [u8; 32], [u8; 32]) {
2598+
let mut guard = self.inbound_payment_key.lock().unwrap();
2599+
let (ikm, keys_opt) = (guard.0, &mut guard.1);
2600+
if let Some(keys) = keys_opt {
2601+
return keys.clone()
2602+
}
2603+
let keys = hkdf_extract_expand(&vec![0], &ikm);
2604+
*keys_opt = Some(keys.clone());
2605+
keys
2606+
}
2607+
2608+
// Check that an inbound payment's `payment_data` field is sane.
2609+
//
2610+
// LDK does not store any data for pending inbound payments. Instead, we construct our payment
2611+
// secret (and, if supplied by LDK, our payment preimage) to include encrypted metadata about the
2612+
// payment.
2613+
//
2614+
// The metadata is constructed as:
2615+
// payment method (3 bits) || payment amount (8 bytes - 3 bits) || expiry (8 bytes)
2616+
//
2617+
// Then on payment receipt, we verify in this method that the payment preimage and payment secret
2618+
// match what was constructed.
2619+
fn verify_inbound_payment_data(&self, payment_hash: PaymentHash, payment_data: msgs::FinalOnionHopData) -> Result<Option<PaymentPreimage>, ()> {
2620+
let (metadata_key, user_pmt_hash_key, ldk_pmt_hash_key) = self.get_expanded_inbound_payment_key();
2621+
let (iv_bytes, encrypted_metadata_bytes) = payment_data.payment_secret.0.split_at(16);
2622+
2623+
let chacha_block = ChaCha20::get_single_block(&metadata_key, iv_bytes);
2624+
let mut metadata_bytes: [u8; 16] = [0; 16];
2625+
for i in 0..16 {
2626+
metadata_bytes[i] = chacha_block[i] ^ encrypted_metadata_bytes[i];
2627+
}
2628+
2629+
let payment_type: u8 = (metadata_bytes[0] & 0b1110_0000) >> 5;
2630+
let mut amt_msat_bytes = [0; 8];
2631+
amt_msat_bytes.copy_from_slice(&metadata_bytes[..8]);
2632+
// Zero out the bits reserved to indicate the payment type.
2633+
amt_msat_bytes[0] &= 0b00011111;
2634+
let min_amt_msat = u64::from_be_bytes(amt_msat_bytes.try_into().unwrap());
2635+
let expiry = u64::from_be_bytes(metadata_bytes[8..].try_into().unwrap());
2636+
let current_time = self.highest_seen_timestamp.load(Ordering::Acquire) as u64;
2637+
2638+
// Make sure to check to check the HMAC before doing the other checks below, to mitigate timing
2639+
// attacks.
2640+
let is_user_payment_hash = metadata_bytes[0] & 1 << 5 != 0;
2641+
let mut payment_preimage = None;
2642+
if is_user_payment_hash {
2643+
let mut hmac = HmacEngine::<Sha256>::new(&user_pmt_hash_key);
2644+
hmac.input(&metadata_bytes[..]);
2645+
hmac.input(&payment_hash.0);
2646+
if !fixed_time_eq(iv_bytes, &Hmac::from_engine(hmac).into_inner().split_at_mut(16).0) {
2647+
log_trace!(self.logger, "Failing HTLC with user-generated payment_hash {}: unexpected payment_secret", log_bytes!(payment_hash.0));
2648+
return Err(())
2649+
}
2650+
} else {
2651+
let mut hmac = HmacEngine::<Sha256>::new(&ldk_pmt_hash_key);
2652+
hmac.input(iv_bytes);
2653+
hmac.input(&metadata_bytes);
2654+
let decoded_payment_preimage = Hmac::from_engine(hmac).into_inner();
2655+
if !fixed_time_eq(&payment_hash.0, &Sha256::hash(&decoded_payment_preimage).into_inner()) {
2656+
log_trace!(self.logger, "Failing HTLC with payment_hash {}: payment preimage {} did not match", log_bytes!(payment_hash.0), log_bytes!(decoded_payment_preimage));
2657+
return Err(())
2658+
}
2659+
payment_preimage = Some(PaymentPreimage(decoded_payment_preimage));
2660+
}
2661+
2662+
if payment_type > 1 { // We only support payment method types of 0000 or 0001
2663+
log_trace!(self.logger, "Failing HTLC with payment hash {} due to unknown payment type {}", log_bytes!(payment_hash.0), payment_type);
2664+
return Err(());
2665+
}
2666+
2667+
if payment_data.total_msat < min_amt_msat {
2668+
log_trace!(self.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);
2669+
return Err(())
2670+
}
2671+
2672+
if expiry < current_time {
2673+
log_trace!(self.logger, "Failing HTLC with payment_hash {}: expired payment", log_bytes!(payment_hash.0));
2674+
return Err(())
2675+
}
2676+
2677+
Ok(payment_preimage)
2678+
}
2679+
25922680
/// Processes HTLCs which are pending waiting on random forward delay.
25932681
///
25942682
/// Should only really ever be called in response to a PendingHTLCsForwardable event.
@@ -2864,9 +2952,17 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
28642952
match payment_secrets.entry(payment_hash) {
28652953
hash_map::Entry::Vacant(_) => {
28662954
match claimable_htlc.onion_payload {
2867-
OnionPayload::Invoice(_) => {
2868-
log_trace!(self.logger, "Failing new HTLC with payment_hash {} as we didn't have a corresponding inbound payment.", log_bytes!(payment_hash.0));
2869-
fail_htlc!(claimable_htlc);
2955+
OnionPayload::Invoice(ref payment_data) => {
2956+
let payment_preimage = match self.verify_inbound_payment_data(payment_hash, payment_data.clone()) {
2957+
Ok(payment_preimage) => payment_preimage,
2958+
Err(()) => {
2959+
fail_htlc!(claimable_htlc);
2960+
continue
2961+
}
2962+
};
2963+
let payment_data_total_msat = payment_data.total_msat;
2964+
let payment_secret = payment_data.payment_secret.clone();
2965+
check_total_value!(payment_data_total_msat, payment_secret, payment_preimage);
28702966
},
28712967
OnionPayload::Spontaneous(preimage) => {
28722968
match channel_state.claimable_htlcs.entry(payment_hash) {
@@ -4558,25 +4654,82 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
45584654
/// to pay us.
45594655
///
45604656
/// This differs from [`create_inbound_payment_for_hash`] only in that it generates the
4561-
/// [`PaymentHash`] and [`PaymentPreimage`] for you, returning the first and storing the second.
4657+
/// [`PaymentHash`] and [`PaymentPreimage`] for you.
45624658
///
45634659
/// The [`PaymentPreimage`] will ultimately be returned to you in the [`PaymentReceived`], which
45644660
/// will have the [`PaymentReceived::payment_preimage`] field filled in. That should then be
45654661
/// passed directly to [`claim_funds`].
45664662
///
45674663
/// See [`create_inbound_payment_for_hash`] for detailed documentation on behavior and requirements.
45684664
///
4665+
/// Note that a malicious eavesdropper can intuit whether an inbound payment was created by
4666+
/// `create_inbound_payment` or `create_inbound_payment_for_hash` based on runtime.
4667+
///
4668+
/// # Note
4669+
///
4670+
/// If you register an inbound payment with this method, then serialize the `ChannelManager`, then
4671+
/// deserialize it with a node running 0.0.103 and earlier, the payment will fail to be received.
4672+
///
45694673
/// [`claim_funds`]: Self::claim_funds
45704674
/// [`PaymentReceived`]: events::Event::PaymentReceived
45714675
/// [`PaymentReceived::payment_preimage`]: events::Event::PaymentReceived::payment_preimage
45724676
/// [`create_inbound_payment_for_hash`]: Self::create_inbound_payment_for_hash
4677+
// For details on the implementation of this method, see `verify_inbound_payment_data`.
45734678
pub fn create_inbound_payment(&self, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32) -> (PaymentHash, PaymentSecret) {
4679+
let (metadata_key, _, ldk_pmt_hash_key) = self.get_expanded_inbound_payment_key();
4680+
let min_amt_msat_bytes: [u8; 8] = match min_value_msat {
4681+
Some(amt) => amt.to_be_bytes(),
4682+
None => [0; 8],
4683+
};
4684+
// We assume that highest_seen_timestamp is pretty close to the current time - its updated when
4685+
// we receive a new block with the maximum time we've seen in a header. It should never be more
4686+
// than two hours in the future. Thus, we add two hours here as a buffer to ensure we
4687+
// absolutely never fail a payment too early.
4688+
// Note that we assume that received blocks have reasonably up-to-date timestamps.
4689+
let expiry_bytes = (self.highest_seen_timestamp.load(Ordering::Acquire) as u64 + invoice_expiry_delta_secs as u64 + 7200).to_be_bytes();
4690+
let mut metadata_bytes: [u8; 16] = [0; 16];
4691+
{
4692+
let (min_amt_msat_slice, expiry_slice) = metadata_bytes.split_at_mut(8);
4693+
min_amt_msat_slice.copy_from_slice(&min_amt_msat_bytes);
4694+
expiry_slice.copy_from_slice(&expiry_bytes);
4695+
}
4696+
4697+
let rand_bytes = self.keys_manager.get_secure_random_bytes();
4698+
let iv_bytes = &rand_bytes[..16];
4699+
4700+
let mut hmac = HmacEngine::<Sha256>::new(&ldk_pmt_hash_key);
4701+
hmac.input(iv_bytes);
4702+
hmac.input(&metadata_bytes);
4703+
let payment_preimage_bytes = Hmac::from_engine(hmac).into_inner();
4704+
4705+
let mut payment_secret_bytes: [u8; 32] = [0; 32];
4706+
{
4707+
let (iv_slice, encrypted_metadata_slice) = payment_secret_bytes.split_at_mut(16);
4708+
iv_slice.copy_from_slice(iv_bytes);
4709+
4710+
let chacha_block = ChaCha20::get_single_block(&metadata_key, iv_bytes);
4711+
for i in 0..16 {
4712+
encrypted_metadata_slice[i] = chacha_block[i] ^ metadata_bytes[i];
4713+
}
4714+
}
4715+
4716+
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage_bytes).into_inner());
4717+
(payment_hash, PaymentSecret(payment_secret_bytes))
4718+
}
4719+
4720+
/// Legacy version of [`create_inbound_payment`]. Use this method if you wish to share
4721+
/// serialized state with LDK node(s) running 0.0.103 and earlier.
4722+
///
4723+
/// # Note
4724+
/// This method will be deprecated in the next few versions.
4725+
///
4726+
/// [`create_inbound_payment`]: Self::create_inbound_payment
4727+
pub fn create_inbound_payment_legacy(&self, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32) -> (PaymentHash, PaymentSecret) {
45744728
let payment_preimage = PaymentPreimage(self.keys_manager.get_secure_random_bytes());
45754729
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
4576-
45774730
(payment_hash,
4578-
self.set_payment_hash_secret_map(payment_hash, Some(payment_preimage), min_value_msat, invoice_expiry_delta_secs)
4579-
.expect("RNG Generated Duplicate PaymentHash"))
4731+
self.set_payment_hash_secret_map(payment_hash, Some(payment_preimage), min_value_msat, invoice_expiry_delta_secs)
4732+
.expect("RNG Generated Duplicate PaymentHash"))
45804733
}
45814734

45824735
/// Gets a [`PaymentSecret`] for a given [`PaymentHash`], for which the payment preimage is
@@ -4606,18 +4759,73 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
46064759
/// If you need exact expiry semantics, you should enforce them upon receipt of
46074760
/// [`PaymentReceived`].
46084761
///
4609-
/// Pending inbound payments are stored in memory and in serialized versions of this
4610-
/// [`ChannelManager`]. If potentially unbounded numbers of inbound payments may exist and
4611-
/// space is limited, you may wish to rate-limit inbound payment creation.
4612-
///
46134762
/// May panic if `invoice_expiry_delta_secs` is greater than one year.
46144763
///
46154764
/// Note that invoices generated for inbound payments should have their `min_final_cltv_expiry`
46164765
/// set to at least [`MIN_FINAL_CLTV_EXPIRY`].
46174766
///
4767+
/// Note that a malicious eavesdropper can intuit whether an inbound payment was created by
4768+
/// `create_inbound_payment` or `create_inbound_payment_for_hash` based on runtime.
4769+
///
4770+
/// # Note
4771+
///
4772+
/// If you register an inbound payment with this method, then serialize the `ChannelManager`, then
4773+
/// deserialize it with a node running 0.0.103 and earlier, the payment will fail to be received.
4774+
///
46184775
/// [`create_inbound_payment`]: Self::create_inbound_payment
46194776
/// [`PaymentReceived`]: events::Event::PaymentReceived
4777+
// For details on the implementation of this method, see `verify_inbound_payment_data`.
46204778
pub fn create_inbound_payment_for_hash(&self, payment_hash: PaymentHash, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32) -> Result<PaymentSecret, APIError> {
4779+
let (metadata_key, user_pmt_hash_key, _) = self.get_expanded_inbound_payment_key();
4780+
let mut min_amt_msat_bytes: [u8; 8] = match min_value_msat {
4781+
Some(amt) => amt.to_be_bytes(),
4782+
None => [0; 8],
4783+
};
4784+
// Set the payment method bits (the top 3 bits of the metadata bytes) to 001
4785+
// indicating the payment type is paying a user-generated payment hash.
4786+
min_amt_msat_bytes[0] |= 1 << 5;
4787+
4788+
// We assume that highest_seen_timestamp is pretty close to the current time - its updated when
4789+
// we receive a new block with the maximum time we've seen in a header. It should never be more
4790+
// than two hours in the future. Thus, we add two hours here as a buffer to ensure we
4791+
// absolutely never fail a payment too early.
4792+
// Note that we assume that received blocks have reasonably up-to-date timestamps.
4793+
let expiry_bytes = (self.highest_seen_timestamp.load(Ordering::Acquire) as u64 + invoice_expiry_delta_secs as u64 + 7200).to_be_bytes();
4794+
4795+
let mut metadata_bytes: [u8; 16] = [0; 16];
4796+
{
4797+
let (min_amt_msat_slice, expiry_slice) = metadata_bytes.split_at_mut(8);
4798+
min_amt_msat_slice.copy_from_slice(&min_amt_msat_bytes);
4799+
expiry_slice.copy_from_slice(&expiry_bytes);
4800+
}
4801+
4802+
let mut hmac = HmacEngine::<Sha256>::new(&user_pmt_hash_key);
4803+
hmac.input(&metadata_bytes);
4804+
hmac.input(&payment_hash.0);
4805+
let hmac_bytes = Hmac::from_engine(hmac).into_inner();
4806+
let iv_bytes = &hmac_bytes[..16];
4807+
4808+
let mut payment_secret_bytes: [u8; 32] = [0; 32];
4809+
{
4810+
let (iv_slice, encrypted_metadata_slice) = payment_secret_bytes.split_at_mut(16);
4811+
iv_slice.copy_from_slice(iv_bytes);
4812+
4813+
let chacha_block = ChaCha20::get_single_block(&metadata_key, iv_bytes);
4814+
for i in 0..16 {
4815+
encrypted_metadata_slice[i] = chacha_block[i] ^ metadata_bytes[i];
4816+
}
4817+
}
4818+
Ok(PaymentSecret(payment_secret_bytes))
4819+
}
4820+
4821+
/// Legacy version of [`create_inbound_payment_for_hash`]. Use this method if you wish to share
4822+
/// serialized state with LDK node(s) running 0.0.103 and earlier.
4823+
///
4824+
/// # Note
4825+
/// This method will be deprecated in the next few versions.
4826+
///
4827+
/// [`create_inbound_payment_for_hash`]: Self::create_inbound_payment_for_hash
4828+
pub fn create_inbound_payment_for_hash_legacy(&self, payment_hash: PaymentHash, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32) -> Result<PaymentSecret, APIError> {
46214829
self.set_payment_hash_secret_map(payment_hash, None, min_value_msat, invoice_expiry_delta_secs)
46224830
}
46234831

@@ -6066,6 +6274,7 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
60666274
claimable_htlcs,
60676275
pending_msg_events: Vec::new(),
60686276
}),
6277+
inbound_payment_key: Mutex::new((args.keys_manager.get_inbound_payment_key_material(), None)),
60696278
pending_inbound_payments: Mutex::new(pending_inbound_payments),
60706279
pending_outbound_payments: Mutex::new(pending_outbound_payments.unwrap()),
60716280

@@ -6099,6 +6308,27 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
60996308
}
61006309
}
61016310

6311+
fn hkdf_extract_expand(salt: &[u8], ikm: &KeyMaterial) -> ([u8; 32], [u8; 32], [u8; 32]) {
6312+
let mut hmac = HmacEngine::<Sha256>::new(salt);
6313+
hmac.input(&ikm.0);
6314+
let prk = Hmac::from_engine(hmac).into_inner();
6315+
let mut hmac = HmacEngine::<Sha256>::new(&prk[..]);
6316+
hmac.input(&[1; 1]);
6317+
let t1 = Hmac::from_engine(hmac).into_inner();
6318+
6319+
let mut hmac = HmacEngine::<Sha256>::new(&prk[..]);
6320+
hmac.input(&t1);
6321+
hmac.input(&[2; 1]);
6322+
let t2 = Hmac::from_engine(hmac).into_inner();
6323+
6324+
let mut hmac = HmacEngine::<Sha256>::new(&prk[..]);
6325+
hmac.input(&t2);
6326+
hmac.input(&[3; 1]);
6327+
let t3 = Hmac::from_engine(hmac).into_inner();
6328+
6329+
(t1, t2, t3)
6330+
}
6331+
61026332
#[cfg(test)]
61036333
mod tests {
61046334
use bitcoin::hashes::Hash;

lightning/src/ln/functional_tests.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -8102,19 +8102,20 @@ fn test_preimage_storage() {
81028102

81038103
#[test]
81048104
fn test_secret_timeout() {
8105-
// Simple test of payment secret storage time outs
8105+
// Simple test of payment secret storage time outs. After
8106+
// `create_inbound_payment(_for_hash)_legacy` is removed, this test will be removed as well.
81068107
let chanmon_cfgs = create_chanmon_cfgs(2);
81078108
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
81088109
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
81098110
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
81108111

81118112
create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
81128113

8113-
let (payment_hash, payment_secret_1) = nodes[1].node.create_inbound_payment(Some(100_000), 2);
8114+
let (payment_hash, payment_secret_1) = nodes[1].node.create_inbound_payment_legacy(Some(100_000), 2);
81148115

81158116
// We should fail to register the same payment hash twice, at least until we've connected a
81168117
// block with time 7200 + CHAN_CONFIRM_DEPTH + 1.
8117-
if let Err(APIError::APIMisuseError { err }) = nodes[1].node.create_inbound_payment_for_hash(payment_hash, Some(100_000), 2) {
8118+
if let Err(APIError::APIMisuseError { err }) = nodes[1].node.create_inbound_payment_for_hash_legacy(payment_hash, Some(100_000), 2) {
81188119
assert_eq!(err, "Duplicate payment hash");
81198120
} else { panic!(); }
81208121
let mut block = {
@@ -8129,7 +8130,7 @@ fn test_secret_timeout() {
81298130
}
81308131
};
81318132
connect_block(&nodes[1], &block);
8132-
if let Err(APIError::APIMisuseError { err }) = nodes[1].node.create_inbound_payment_for_hash(payment_hash, Some(100_000), 2) {
8133+
if let Err(APIError::APIMisuseError { err }) = nodes[1].node.create_inbound_payment_for_hash_legacy(payment_hash, Some(100_000), 2) {
81338134
assert_eq!(err, "Duplicate payment hash");
81348135
} else { panic!(); }
81358136

@@ -8138,7 +8139,7 @@ fn test_secret_timeout() {
81388139
block.header.prev_blockhash = block.header.block_hash();
81398140
block.header.time += 1;
81408141
connect_block(&nodes[1], &block);
8141-
let our_payment_secret = nodes[1].node.create_inbound_payment_for_hash(payment_hash, Some(100_000), 2).unwrap();
8142+
let our_payment_secret = nodes[1].node.create_inbound_payment_for_hash_legacy(payment_hash, Some(100_000), 2).unwrap();
81428143
assert_ne!(payment_secret_1, our_payment_secret);
81438144

81448145
{

lightning/src/util/events.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,8 @@ pub enum Event {
183183
/// [`ChannelManager::claim_funds`]: crate::ln::channelmanager::ChannelManager::claim_funds
184184
/// [`ChannelManager::fail_htlc_backwards`]: crate::ln::channelmanager::ChannelManager::fail_htlc_backwards
185185
PaymentReceived {
186-
/// The hash for which the preimage should be handed to the ChannelManager.
186+
/// The hash for which the preimage should be handed to the ChannelManager. Note that LDK will
187+
/// not stop you from registering duplicate payment hashes for inbound payments.
187188
payment_hash: PaymentHash,
188189
/// The value, in thousandths of a satoshi, that this payment is for.
189190
amt: u64,

0 commit comments

Comments
 (0)