/// Time at which this HTLC expires - blocks with a header time above this value will result in
/// this payment being removed.
expiry_time: u64,
+ /// Arbitrary identifier the user specifies (or not)
+ user_payment_id: u64,
// Other required attributes of the payment, optionally enforced:
payment_preimage: Option<PaymentPreimage>,
min_value_msat: Option<u64>,
} else if total_value == payment_data.total_msat {
new_events.push(events::Event::PaymentReceived {
payment_hash,
- payment_secret: Some(payment_data.payment_secret),
+ payment_secret: payment_data.payment_secret,
amt: total_value,
+ user_payment_id: inbound_payment.get().user_payment_id,
});
// Only ever generate at most one PaymentReceived
// per registered payment_hash, even if it isn't
/// along the path (including in our own channel on which we received it).
/// Returns false if no payment was found to fail backwards, true if the process of failing the
/// HTLC backwards has been started.
- pub fn fail_htlc_backwards(&self, payment_hash: &PaymentHash, _payment_secret: &Option<PaymentSecret>) -> bool {
+ pub fn fail_htlc_backwards(&self, payment_hash: &PaymentHash) -> bool {
let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
let mut channel_state = Some(self.channel_state.lock().unwrap());
/// generating message events for the net layer to claim the payment, if possible. Thus, you
/// should probably kick the net layer to go send messages if this returns true!
///
- /// You must specify the expected amounts for this HTLC, and we will only claim HTLCs
- /// available within a few percent of the expected amount. This is critical for several
- /// reasons : a) it avoids providing senders with `proof-of-payment` (in the form of the
- /// payment_preimage without having provided the full value and b) it avoids certain
- /// privacy-breaking recipient-probing attacks which may reveal payment activity to
- /// motivated attackers.
- ///
- /// Note that the privacy concerns in (b) are not relevant in payments with a payment_secret
- /// set. Thus, for such payments we will claim any payments which do not under-pay.
+ /// Note that if you did not set an `amount_msat` when calling [`create_inbound_payment`] or
+ /// [`create_inbound_payment_for_hash`] you must check that the amount in the `PaymentReceived`
+ /// event matches your expectation. If you fail to do so and call this method, you may provide
+ /// the sender "proof-of-payment" when they did not fulfill the full expected payment.
///
/// May panic if called except in response to a PaymentReceived event.
- pub fn claim_funds(&self, payment_preimage: PaymentPreimage, _payment_secret: &Option<PaymentSecret>, expected_amount: u64) -> bool {
+ ///
+ /// [`create_inbound_payment`]: Self::create_inbound_payment
+ /// [`create_inbound_payment_for_hash`]: Self::create_inbound_payment_for_hash
+ pub fn claim_funds(&self, payment_preimage: PaymentPreimage) -> bool {
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
// we got all the HTLCs and then a channel closed while we were waiting for the user to
// provide the preimage, so worrying too much about the optimal handling isn't worth
// it.
-
- let is_mpp = true;
- let mut valid_mpp = sources[0].payment_data.total_msat >= expected_amount;
-
+ let mut valid_mpp = true;
for htlc in sources.iter() {
- if !is_mpp || !valid_mpp { break; }
if let None = channel_state.as_ref().unwrap().short_to_id.get(&htlc.prev_hop.short_channel_id) {
valid_mpp = false;
+ break;
}
}
let mut errs = Vec::new();
let mut claimed_any_htlcs = false;
for htlc in sources.drain(..) {
- if channel_state.is_none() { channel_state = Some(self.channel_state.lock().unwrap()); }
- if (is_mpp && !valid_mpp) || (!is_mpp && (htlc.value < expected_amount || htlc.value > expected_amount * 2)) {
+ if !valid_mpp {
+ if channel_state.is_none() { channel_state = Some(self.channel_state.lock().unwrap()); }
let mut htlc_msat_height_data = byte_utils::be64_to_array(htlc.value).to_vec();
htlc_msat_height_data.extend_from_slice(&byte_utils::be32_to_array(
self.best_block.read().unwrap().height()));
claimed_any_htlcs = true;
} else { errs.push(e); }
},
- Err(None) if is_mpp => unreachable!("We already checked for channel existence, we can't fail here!"),
- Err(None) => {
- log_warn!(self.logger, "Channel we expected to claim an HTLC from was closed.");
- },
+ Err(None) => unreachable!("We already checked for channel existence, we can't fail here!"),
Ok(()) => claimed_any_htlcs = true,
}
}
}
}
- fn set_payment_hash_secret_map(&self, payment_hash: PaymentHash, payment_preimage: Option<PaymentPreimage>, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32) -> Result<PaymentSecret, APIError> {
+ fn set_payment_hash_secret_map(&self, payment_hash: PaymentHash, payment_preimage: Option<PaymentPreimage>, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32, user_payment_id: u64) -> Result<PaymentSecret, APIError> {
assert!(invoice_expiry_delta_secs <= 60*60*24*365); // Sadly bitcoin timestamps are u32s, so panic before 2106
let payment_secret = PaymentSecret(self.keys_manager.get_secure_random_bytes());
match payment_secrets.entry(payment_hash) {
hash_map::Entry::Vacant(e) => {
e.insert(PendingInboundPayment {
- payment_secret, min_value_msat, payment_preimage,
+ payment_secret, min_value_msat, user_payment_id, payment_preimage,
// We assume that highest_seen_timestamp is pretty close to the current time -
// its updated when we receive a new block with the maximum time we've seen in
// a header. It should never be more than two hours in the future.
/// See [`create_inbound_payment_for_hash`] for detailed documentation on behavior and requirements.
///
/// [`create_inbound_payment_for_hash`]: Self::create_inbound_payment_for_hash
- pub fn create_inbound_payment(&self, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32) -> (PaymentHash, PaymentSecret) {
+ pub fn create_inbound_payment(&self, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32, user_payment_id: u64) -> (PaymentHash, PaymentSecret) {
let payment_preimage = PaymentPreimage(self.keys_manager.get_secure_random_bytes());
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
(payment_hash,
- self.set_payment_hash_secret_map(payment_hash, Some(payment_preimage), min_value_msat, invoice_expiry_delta_secs)
+ self.set_payment_hash_secret_map(payment_hash, Some(payment_preimage), min_value_msat, invoice_expiry_delta_secs, user_payment_id)
.expect("RNG Generated Duplicate PaymentHash"))
}
/// The [`PaymentHash`] (and corresponding [`PaymentPreimage`]) must be globally unique. This
/// method may return an Err if another payment with the same payment_hash is still pending.
///
+ /// `user_payment_id` will be provided back in [`PaymentReceived::user_payment_id`] events to
+ /// allow tracking of which events correspond with which calls to this and
+ /// [`create_inbound_payment`]. `user_payment_id` has no meaning inside of LDK, it is simply
+ /// copied to events and otherwise ignored. It may be used to correlate PaymentReceived events
+ /// with invoice metadata stored elsewhere.
+ ///
/// `min_value_msat` should be set if the invoice being generated contains a value. Any payment
/// received for the returned [`PaymentHash`] will be required to be at least `min_value_msat`
/// before a [`PaymentReceived`] event will be generated, ensuring that we do not provide the
///
/// [`create_inbound_payment`]: Self::create_inbound_payment
/// [`PaymentReceived`]: events::Event::PaymentReceived
- pub fn create_inbound_payment_for_hash(&self, payment_hash: PaymentHash, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32) -> Result<PaymentSecret, APIError> {
- self.set_payment_hash_secret_map(payment_hash, None, min_value_msat, invoice_expiry_delta_secs)
+ /// [`PaymentReceived::user_payment_id`]: events::Event::PaymentReceived::user_payment_id
+ pub fn create_inbound_payment_for_hash(&self, payment_hash: PaymentHash, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32, user_payment_id: u64) -> Result<PaymentSecret, APIError> {
+ self.set_payment_hash_secret_map(payment_hash, None, min_value_msat, invoice_expiry_delta_secs, user_payment_id)
}
}
impl_writeable!(PendingInboundPayment, 0, {
payment_secret,
expiry_time,
+ user_payment_id,
payment_preimage,
min_value_msat
});
payment_preimage.0[0..8].copy_from_slice(&payment_count.to_le_bytes());
payment_count += 1;
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner());
- let payment_secret = $node_b.create_inbound_payment_for_hash(payment_hash, None, 7200).unwrap();
+ let payment_secret = $node_b.create_inbound_payment_for_hash(payment_hash, None, 7200, 0).unwrap();
$node_a.send_payment(&route, payment_hash, &Some(payment_secret)).unwrap();
let payment_event = SendEvent::from_event($node_a.get_and_clear_pending_msg_events().pop().unwrap());
expect_pending_htlcs_forwardable!(NodeHolder { node: &$node_b });
expect_payment_received!(NodeHolder { node: &$node_b }, payment_hash, payment_secret, 10_000);
- assert!($node_b.claim_funds(payment_preimage, &Some(payment_secret), 10_000));
+ assert!($node_b.claim_funds(payment_preimage));
match $node_b.get_and_clear_pending_msg_events().pop().unwrap() {
MessageSendEvent::UpdateHTLCs { node_id, updates } => {