@@ -15403,7 +15403,7 @@ where
1540315403 None => return None,
1540415404 };
1540515405
15406- let invoice_request = match self.flow.verify_invoice_request(invoice_request, context) {
15406+ let verified_invoice_request = match self.flow.verify_invoice_request(invoice_request, context) {
1540715407 Ok(InvreqResponseInstructions::SendInvoice(invoice_request)) => invoice_request,
1540815408 Ok(InvreqResponseInstructions::SendStaticInvoice { recipient_id, invoice_slot, invoice_request }) => {
1540915409 self.pending_events.lock().unwrap().push_back((Event::StaticInvoiceRequested {
@@ -15414,6 +15414,7 @@ where
1541415414 },
1541515415 Err(_) => return None,
1541615416 };
15417+ let invoice_request = verified_invoice_request.inner();
1541715418
1541815419 #[cfg(not(feature = "std"))]
1541915420 let created_at = Duration::from_secs(self.highest_seen_timestamp.load(Ordering::Acquire) as u64);
@@ -15422,6 +15423,82 @@ where
1542215423 .duration_since(std::time::SystemTime::UNIX_EPOCH)
1542315424 .expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH");
1542415425
15426+ // Recurrence checks
15427+ let recurrence_basetime = if let Some(recurrence_fields) = invoice_request.recurrence_fields() {
15428+ let payer_id = invoice_request.payer_signing_pubkey();
15429+ let mut sessions= self.active_recurrence_sessions.lock().unwrap();
15430+
15431+ // We first categorise the invoice request based on it's type.
15432+ let recurrence_counter = invoice_request.recurrence_counter();
15433+ let recurrence_cancel = invoice_request.recurrence_cancel();
15434+ let existing_session = sessions.get(&payer_id);
15435+
15436+ match (existing_session, recurrence_counter, recurrence_cancel) {
15437+ // This represents case where the payer, didn't support recurrence
15438+ // but we set recurrence optional so we allow payer to pay one-off
15439+ (None, None, None) => { None },
15440+ // It's the first invoice request in recurrence series
15441+ (None, Some(0), None) => {
15442+ let recurrence_basetime = recurrence_fields
15443+ .recurrence_base
15444+ .map(|base| base.basetime)
15445+ .unwrap_or(created_at.as_secs());
15446+
15447+ // Next we prepare recurrence_data to be stored in our recurrence session
15448+ let recurrence_data = RecurrenceData {
15449+ invoice_request_start: invoice_request.recurrence_start(),
15450+ next_payable_counter: 0,
15451+ recurrence_basetime,
15452+ };
15453+ // Now we store it in our active_recurrence_session
15454+ sessions.insert(payer_id, recurrence_data);
15455+
15456+ Some(recurrence_basetime)
15457+
15458+ },
15459+ // it's a successive invoice request in recurrence series
15460+ (Some(data), Some(counter), None) if counter > 0 => {
15461+ // We confirm all the data to ensure this is an expected successive invoice request
15462+ if data.invoice_request_start != invoice_request.recurrence_start()
15463+ || data.next_payable_counter != counter
15464+ {
15465+ return None
15466+ }
15467+
15468+ // Next we ensure that the successive invoice_request is received between the period's paywindow
15469+ if let Some(window) = recurrence_fields.recurrence_paywindow {
15470+ let period_index = data.invoice_request_start.unwrap_or(0) + counter;
15471+
15472+ let period_start = data.recurrence_basetime
15473+ + period_index as u64 * recurrence_fields.recurrence.period_length_secs().unwrap();
15474+
15475+ if created_at.as_secs() < period_start - window.seconds_before as u64
15476+ || created_at.as_secs() >= period_start + window.seconds_after as u64
15477+ {
15478+ return None
15479+ }
15480+ }
15481+
15482+ Some(data.recurrence_basetime)
15483+ },
15484+ // it's a cancel recurrence invoice request
15485+ (Some(_data), Some(counter), Some(())) if counter > 0 => {
15486+ // Here we simply remove the data from our sessions
15487+ sessions.remove(&payer_id);
15488+
15489+ // And since cancellation invoice request are stub invoice request,
15490+ // we don't respond to this invoice request
15491+ return None
15492+ },
15493+ _ => {
15494+ debug_assert!(false, "Should be unreachable, as all the invalid cases are handled during parsing");
15495+ return None
15496+ }
15497+ }
15498+ } else {
15499+ None
15500+ };
15501+
1542515502 let get_payment_info = |amount_msats, relative_expiry| {
1542615503 self.create_inbound_payment(
1542715504 Some(amount_msats),
@@ -15430,7 +15507,7 @@ where
1543015507 ).map_err(|_| Bolt12SemanticError::InvalidAmount)
1543115508 };
1543215509
15433- let (result, context) = match invoice_request {
15510+ let (result, context) = match verified_invoice_request {
1543415511 InvoiceRequestVerifiedFromOffer::DerivedKeys(request) => {
1543515512 let result = self.flow.create_invoice_builder_from_invoice_request_with_keys(
1543615513 &self.router,
@@ -15441,7 +15518,11 @@ where
1544115518 );
1544215519
1544315520 match result {
15444- Ok((builder, context)) => {
15521+ Ok((mut builder, context)) => {
15522+ recurrence_basetime.map(|basetime|
15523+ builder.set_invoice_recurrence_basetime(basetime)
15524+ );
15525+
1544515526 let res = builder
1544615527 .build_and_sign(&self.secp_ctx)
1544715528 .map_err(InvoiceError::from);
@@ -15466,7 +15547,10 @@ where
1546615547 );
1546715548
1546815549 match result {
15469- Ok((builder, context)) => {
15550+ Ok((mut builder, context)) => {
15551+ recurrence_basetime.map(|basetime|
15552+ builder.set_invoice_recurrence_basetime(basetime)
15553+ );
1547015554 let res = builder
1547115555 .build()
1547215556 .map_err(InvoiceError::from)
0 commit comments