Skip to content

Commit ebb7600

Browse files
committed
Add payment secret and preimage tracking in ChannelManager
This adds support for tracking payment secrets and (optionally) payment preimages in ChannelManager. This potentially makes client implementations much simper as they don't have to have external payment preimage tracking. This doesn't yet use such tracking anywhere.
1 parent 25ca616 commit ebb7600

File tree

1 file changed

+126
-0
lines changed

1 file changed

+126
-0
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,23 @@ struct PeerState {
353353
latest_features: InitFeatures,
354354
}
355355

356+
/// Stores a PaymentSecret and any other data we may need to validate an inbound payment is
357+
/// actually ours and not some duplicate HTLC sent to us by a node along the route.
358+
///
359+
/// For users who don't want to bother doing their own payment preimage storage, we also store that
360+
/// here.
361+
struct PendingInboundPayment {
362+
/// The payment secret which the sender must use for us to accept this payment
363+
payment_secret: PaymentSecret,
364+
/// Height at which this HTLC expires - block height above this value will result in this
365+
/// payment being removed. Note that we'll reject any payments within HTLC_FAIL_BACK_BUFFER of
366+
/// the height at which they are received.
367+
expiry_height: u32,
368+
// Other required attributes of the payment, optionally enforced:
369+
payment_preimage: Option<PaymentPreimage>,
370+
min_value_msat: Option<u64>,
371+
}
372+
356373
/// SimpleArcChannelManager is useful when you need a ChannelManager with a static lifetime, e.g.
357374
/// when you're using lightning-net-tokio (since tokio::spawn requires parameters with static
358375
/// lifetimes). Other times you can afford a reference, which is more efficient, in which case
@@ -431,6 +448,10 @@ pub struct ChannelManager<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref,
431448
pub(super) channel_state: Mutex<ChannelHolder<Signer>>,
432449
#[cfg(not(any(test, feature = "_test_utils")))]
433450
channel_state: Mutex<ChannelHolder<Signer>>,
451+
452+
/// Pending inbound payments by. Locked *after* channel_state.
453+
pending_inbound_payments: Mutex<HashMap<PaymentHash, PendingInboundPayment>>,
454+
434455
our_network_key: SecretKey,
435456
our_network_pubkey: PublicKey,
436457

@@ -853,6 +874,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
853874
claimable_htlcs: HashMap::new(),
854875
pending_msg_events: Vec::new(),
855876
}),
877+
pending_inbound_payments: Mutex::new(HashMap::new()),
878+
856879
our_network_key: keys_manager.get_node_secret(),
857880
our_network_pubkey: PublicKey::from_secret_key(&secp_ctx, &keys_manager.get_node_secret()),
858881
secp_ctx,
@@ -3321,6 +3344,85 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
33213344
self.finish_force_close_channel(failure);
33223345
}
33233346
}
3347+
3348+
/// Gets a payment secret and payment hash for use in an invoice given to a third party wishing
3349+
/// to pay us.
3350+
///
3351+
/// A [`PaymentReceived`] event will only be generated if the payment secret matches a payment
3352+
/// secret fetched via this method or [`get_payment_secret`], and which is at least the `value`
3353+
/// provided here, if one is provided.
3354+
///
3355+
/// `min_value_msat` should be set if the invoice being generated contains a value. Any payment
3356+
/// received for the returned PaymentHash will be required to be at least `min_value_msat`
3357+
/// before a [`PaymentReceived`] event will be generated, ensuring that we do not provide the
3358+
/// server "proof-of-payment" unless they have paid the required amount.
3359+
///
3360+
/// `invoice_expiry_delta_blocks describes` the number of blocks which the invoice is valid for,
3361+
/// in excess of the current block height. This should match the value set in the invoice.
3362+
///
3363+
/// May panic if `invoice_expiry_delta_blocks` is greater than one year of blocks (52,560).
3364+
///
3365+
/// [`get_payment_secret`]: Self::get_payment_secret
3366+
/// [`PaymentReceived`]: events::Event::PaymentReceived
3367+
pub fn get_payment_secret_preimage(&self, min_value_msat: Option<u64>, invoice_expiry_delta_blocks: u32) -> (PaymentHash, PaymentSecret) {
3368+
assert!(invoice_expiry_delta_blocks <= 6*24*365); // We may overflow later if this value is too large
3369+
3370+
let payment_secret = PaymentSecret(self.keys_manager.get_secure_random_bytes());
3371+
let payment_preimage = PaymentPreimage(self.keys_manager.get_secure_random_bytes());
3372+
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
3373+
3374+
let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
3375+
let mut payment_secrets = self.pending_inbound_payments.lock().unwrap();
3376+
if payment_secrets.insert(payment_hash, PendingInboundPayment {
3377+
payment_secret, min_value_msat,
3378+
expiry_height: self.best_block.read().unwrap().height() + invoice_expiry_delta_blocks,
3379+
payment_preimage: Some(payment_preimage)
3380+
}).is_some() {
3381+
panic!("RNG Generated Duplicate PaymentHash");
3382+
}
3383+
(payment_hash, payment_secret)
3384+
}
3385+
3386+
/// Gets a payment_secret for a given payment hash, for which the payment preimage is stored
3387+
/// external to LDK.
3388+
///
3389+
/// A [`PaymentReceived`] event will only be generated if the payment secret matches a payment
3390+
/// secret fetched via this method or [`get_payment_secret_preimage`], and which is at least
3391+
/// the `value` provided here, if one is provided.
3392+
///
3393+
/// The payment_hash (and corresponding payment preimage) must be globally unique. This method
3394+
/// may return an Err if another payment with the same payment_hash is still pending.
3395+
///
3396+
/// `min_value_msat` should be set if the invoice being generated contains a value. Any payment
3397+
/// received for the returned PaymentHash will be required to be at least `min_value_msat`
3398+
/// before a [`PaymentReceived`] event will be generated, ensuring that we do not provide the
3399+
/// server "proof-of-payment" unless they have paid the required amount.
3400+
///
3401+
/// `invoice_expiry_delta_blocks` describes the number of blocks which the invoice is valid for,
3402+
/// in excess of the current block height. This should match the value set in the invoice.
3403+
///
3404+
/// May panic if `invoice_expiry_delta_blocks` is greater than one year of blocks (52,560).
3405+
///
3406+
/// [`get_payment_secret_preimage`]: Self::get_payment_secret_preimage
3407+
/// [`PaymentReceived`]: events::Event::PaymentReceived
3408+
pub fn get_payment_secret(&self, payment_hash: PaymentHash, min_value_msat: Option<u64>, invoice_expiry_delta_blocks: u32) -> Result<PaymentSecret, APIError> {
3409+
assert!(invoice_expiry_delta_blocks <= 6*24*365); // We may overflow later if this value is too large
3410+
3411+
let payment_secret = PaymentSecret(self.keys_manager.get_secure_random_bytes());
3412+
3413+
let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
3414+
let mut payment_secrets = self.pending_inbound_payments.lock().unwrap();
3415+
match payment_secrets.entry(payment_hash) {
3416+
hash_map::Entry::Vacant(e) => {
3417+
e.insert(PendingInboundPayment {
3418+
payment_secret, min_value_msat, payment_preimage: None,
3419+
expiry_height: self.best_block.read().unwrap().height() + invoice_expiry_delta_blocks,
3420+
});
3421+
},
3422+
hash_map::Entry::Occupied(_) => return Err(APIError::APIMisuseError { err: "Duplicate payment hash".to_owned() }),
3423+
}
3424+
Ok(payment_secret)
3425+
}
33243426
}
33253427

33263428
impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> MessageSendEventsProvider for ChannelManager<Signer, M, T, K, F, L>
@@ -4116,6 +4218,13 @@ impl Readable for HTLCForwardInfo {
41164218
}
41174219
}
41184220

4221+
impl_writeable!(PendingInboundPayment, 0, {
4222+
payment_secret,
4223+
expiry_height,
4224+
payment_preimage,
4225+
min_value_msat
4226+
});
4227+
41194228
impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> Writeable for ChannelManager<Signer, M, T, K, F, L>
41204229
where M::Target: chain::Watch<Signer>,
41214230
T::Target: BroadcasterInterface,
@@ -4196,6 +4305,13 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> Writeable f
41964305

41974306
(self.last_node_announcement_serial.load(Ordering::Acquire) as u32).write(writer)?;
41984307

4308+
let pending_inbound_payments = self.pending_inbound_payments.lock().unwrap();
4309+
(pending_inbound_payments.len() as u64).write(writer)?;
4310+
for (hash, pending_payment) in pending_inbound_payments.iter() {
4311+
hash.write(writer)?;
4312+
pending_payment.write(writer)?;
4313+
}
4314+
41994315
Ok(())
42004316
}
42014317
}
@@ -4426,6 +4542,14 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
44264542

44274543
let last_node_announcement_serial: u32 = Readable::read(reader)?;
44284544

4545+
let pending_inbound_payment_count: u64 = Readable::read(reader)?;
4546+
let mut pending_inbound_payments: HashMap<PaymentHash, PendingInboundPayment> = HashMap::with_capacity(cmp::min(pending_inbound_payment_count as usize, MAX_ALLOC_SIZE/(3*32)));
4547+
for _ in 0..pending_inbound_payment_count {
4548+
if pending_inbound_payments.insert(Readable::read(reader)?, Readable::read(reader)?).is_some() {
4549+
return Err(DecodeError::InvalidValue);
4550+
}
4551+
}
4552+
44294553
let mut secp_ctx = Secp256k1::new();
44304554
secp_ctx.seeded_randomize(&args.keys_manager.get_secure_random_bytes());
44314555

@@ -4444,6 +4568,8 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
44444568
claimable_htlcs,
44454569
pending_msg_events: Vec::new(),
44464570
}),
4571+
pending_inbound_payments: Mutex::new(pending_inbound_payments),
4572+
44474573
our_network_key: args.keys_manager.get_node_secret(),
44484574
our_network_pubkey: PublicKey::from_secret_key(&secp_ctx, &args.keys_manager.get_node_secret()),
44494575
secp_ctx,

0 commit comments

Comments
 (0)