Skip to content

Commit 31eb068

Browse files
committed
Track unknown BOLT11 manual claims
Gate manual claiming for unknown custom-hash BOLT11 payments behind a config flag. Nodes that do not opt in fail these payments back without storing or queueing user events. Co-Authored-By: HAL 9000
1 parent cb8848e commit 31eb068

7 files changed

Lines changed: 214 additions & 109 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
persisted by LDK Node v0.2.1 or earlier (which stored `payment_id` as
1313
optional) will fail to deserialize on read; users upgrading from those
1414
versions need to drain pending events before the upgrade.
15+
- Applications using the BOLT 11 manual-claiming receive APIs
16+
(`receive_*_for_hash`) now need to set
17+
`Config::manually_claim_unknown_bolt11_payments` to `true`. Otherwise
18+
matching inbound HTLCs will be failed back instead of emitting
19+
`Event::PaymentClaimable`.
1520

1621
## Feature and API updates
1722
- The Bitcoin Core RPC and REST chain-source builder methods now accept an optional

src/config.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ pub(crate) const LIQUIDITY_DISCOVERY_RETRY_MAX_DELAY: Duration = Duration::from_
155155
/// | `route_parameters` | None |
156156
/// | `tor_config` | None |
157157
/// | `hrn_config` | HumanReadableNamesConfig::default() |
158+
/// | `manually_claim_unknown_bolt11_payments` | false |
158159
///
159160
/// See [`AnchorChannelsConfig`] and [`RouteParametersConfig`] for more information regarding their
160161
/// respective default values.
@@ -219,6 +220,17 @@ pub struct Config {
219220
///
220221
/// [BIP 353]: https://github.com/bitcoin/bips/blob/master/bip-0353.mediawiki
221222
pub hrn_config: HumanReadableNamesConfig,
223+
/// Whether to emit [`Event::PaymentClaimable`] for unknown BOLT 11 payments that were created
224+
/// with a user-provided payment hash and therefore need to be manually claimed.
225+
///
226+
/// If disabled, such payments are failed back without being added to the payment store.
227+
///
228+
/// **Warning:** Enabling this may let any holder of a valid invoice generated by this node tie
229+
/// up inbound HTLC slots and grow the persisted event queue until the payment is claimed,
230+
/// failed, or times out.
231+
///
232+
/// [`Event::PaymentClaimable`]: crate::Event::PaymentClaimable
233+
pub manually_claim_unknown_bolt11_payments: bool,
222234
}
223235

224236
impl Default for Config {
@@ -235,6 +247,7 @@ impl Default for Config {
235247
route_parameters: None,
236248
node_alias: None,
237249
hrn_config: HumanReadableNamesConfig::default(),
250+
manually_claim_unknown_bolt11_payments: false,
238251
}
239252
}
240253
}

src/event.rs

Lines changed: 96 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -194,15 +194,21 @@ pub enum Event {
194194
/// The caveat described above the `total_fee_earned_msat` field applies here as well.
195195
outbound_amount_forwarded_msat: Option<u64>,
196196
},
197-
/// A payment for a previously-registered payment hash has been received.
197+
/// A BOLT 11 payment with a user-provided payment hash has been received.
198198
///
199199
/// This needs to be manually claimed by supplying the correct preimage to [`claim_for_hash`].
200200
///
201+
/// This event is only emitted for unknown payments if
202+
/// [`Config::manually_claim_unknown_bolt11_payments`] is enabled. Enabling it may let any
203+
/// holder of a valid invoice generated by this node tie up inbound HTLC slots and grow the
204+
/// persisted event queue until the payment is claimed, failed, or times out.
205+
///
201206
/// If the provided parameters don't match the expectations or the preimage can't be
202207
/// retrieved in time, should be failed-back via [`fail_for_hash`].
203208
///
204209
/// Note claiming will necessarily fail after the `claim_deadline` has been reached.
205210
///
211+
/// [`Config::manually_claim_unknown_bolt11_payments`]: crate::config::Config::manually_claim_unknown_bolt11_payments
206212
/// [`claim_for_hash`]: crate::payment::Bolt11Payment::claim_for_hash
207213
/// [`fail_for_hash`]: crate::payment::Bolt11Payment::fail_for_hash
208214
PaymentClaimable {
@@ -906,45 +912,99 @@ where
906912
}
907913
}
908914

909-
if let Some(info) = payment_info {
915+
let should_emit_payment_claimable = if let Some(info) = payment_info.as_ref() {
910916
// If this is known by the store but ChannelManager doesn't know the preimage,
911-
// the payment has been registered via `_for_hash` variants and needs to be manually claimed via
912-
// user interaction.
913-
match info.kind {
914-
PaymentKind::Bolt11 { preimage, .. } => {
915-
if purpose.preimage().is_none() {
916-
debug_assert!(
917-
preimage.is_none(),
918-
"We would have registered the preimage if we knew"
919-
);
917+
// the payment needs to be manually claimed via user interaction.
918+
match &info.kind {
919+
PaymentKind::Bolt11 { preimage, .. } if purpose.preimage().is_none() => {
920+
debug_assert!(
921+
preimage.is_none(),
922+
"We would have registered the preimage if we knew"
923+
);
924+
true
925+
},
926+
_ => false,
927+
}
928+
} else if let PaymentPurpose::Bolt11InvoicePayment {
929+
payment_preimage: None,
930+
payment_secret,
931+
..
932+
} = &purpose
933+
{
934+
if !self.config.manually_claim_unknown_bolt11_payments {
935+
log_info!(
936+
self.logger,
937+
"Refusing unknown BOLT11 payment with hash {} as manual claiming is disabled",
938+
hex_utils::to_string(&payment_hash.0),
939+
);
940+
self.channel_manager.fail_htlc_backwards(&payment_hash);
941+
return Ok(());
942+
}
920943

921-
let custom_records = onion_fields
922-
.map(|cf| {
923-
cf.custom_tlvs().into_iter().map(|tlv| tlv.into()).collect()
924-
})
925-
.unwrap_or_default();
926-
let event = Event::PaymentClaimable {
927-
payment_id,
928-
payment_hash,
929-
claimable_amount_msat: amount_msat,
930-
claim_deadline,
931-
custom_records,
932-
};
933-
match self.event_queue.add_event(event).await {
934-
Ok(_) => return Ok(()),
935-
Err(e) => {
936-
log_error!(
937-
self.logger,
938-
"Failed to push to event queue: {}",
939-
e
940-
);
941-
return Err(ReplayEvent());
942-
},
943-
};
944-
}
944+
let invoice_amount_msat =
945+
amount_msat.saturating_add(counterparty_skimmed_fee_msat);
946+
let kind = PaymentKind::Bolt11 {
947+
hash: payment_hash,
948+
preimage: None,
949+
secret: Some(*payment_secret),
950+
counterparty_skimmed_fee_msat: if counterparty_skimmed_fee_msat > 0 {
951+
Some(counterparty_skimmed_fee_msat)
952+
} else {
953+
None
954+
},
955+
};
956+
957+
let payment = PaymentDetails::new(
958+
payment_id,
959+
kind,
960+
Some(invoice_amount_msat),
961+
None,
962+
PaymentDirection::Inbound,
963+
PaymentStatus::Pending,
964+
);
965+
966+
match self.payment_store.insert(payment).await {
967+
Ok(false) => (),
968+
Ok(true) => {
969+
log_error!(
970+
self.logger,
971+
"Bolt11InvoicePayment with ID {} was previously known",
972+
payment_id,
973+
);
974+
debug_assert!(false);
975+
},
976+
Err(e) => {
977+
log_error!(
978+
self.logger,
979+
"Failed to insert payment with ID {}: {}",
980+
payment_id,
981+
e
982+
);
983+
return Err(ReplayEvent());
945984
},
946-
_ => {},
947985
}
986+
true
987+
} else {
988+
false
989+
};
990+
if should_emit_payment_claimable {
991+
let custom_records = onion_fields
992+
.map(|cf| cf.custom_tlvs().into_iter().map(|tlv| tlv.into()).collect())
993+
.unwrap_or_default();
994+
let event = Event::PaymentClaimable {
995+
payment_id,
996+
payment_hash,
997+
claimable_amount_msat: amount_msat,
998+
claim_deadline,
999+
custom_records,
1000+
};
1001+
match self.event_queue.add_event(event).await {
1002+
Ok(_) => return Ok(()),
1003+
Err(e) => {
1004+
log_error!(self.logger, "Failed to push to event queue: {}", e);
1005+
return Err(ReplayEvent());
1006+
},
1007+
};
9481008
}
9491009

9501010
log_info!(

0 commit comments

Comments
 (0)