Skip to content

Commit

Permalink
fetchinvoice: return the next period for recurring offers.
Browse files Browse the repository at this point in the history
This is useful for the caller to know when to call again.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
  • Loading branch information
rustyrussell committed Dec 14, 2020
1 parent 018ca05 commit b8fefa4
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 0 deletions.
47 changes: 47 additions & 0 deletions plugins/fetchinvoice.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,15 @@ static struct command_result *recv_onion_message(struct command *cmd,
} else
expected_amount = NULL;

/* BOLT-offers #12:
* - if the offer contained `recurrence`:
* - MUST reject the invoice if `recurrence_basetime` is not set.
*/
if (sent->invreq->recurrence_counter && !inv->recurrence_basetime) {
badfield = "recurrence_basetime";
goto badinv;
}

/* BOLT-offers #12:
* - SHOULD confirm authorization if the `description` does not exactly
* match the `offer`
Expand Down Expand Up @@ -252,6 +261,44 @@ static struct command_result *recv_onion_message(struct command *cmd,
amount_msat(*inv->amount));
json_object_end(out);

/* We tell them about next period at this point, if any. */
if (sent->offer->recurrence) {
u64 next_counter, next_period_idx;
u64 paywindow_start, paywindow_end;

next_counter = *sent->invreq->recurrence_counter + 1;
if (sent->invreq->recurrence_start)
next_period_idx = *sent->invreq->recurrence_start
+ next_counter;
else
next_period_idx = next_counter;

/* If this was the last, don't tell them about a next! */
if (!sent->offer->recurrence_limit
|| next_period_idx <= *sent->offer->recurrence_limit) {
json_object_start(out, "next_period");
json_add_u64(out, "counter", next_counter);
json_add_u64(out, "starttime",
offer_period_start(*inv->recurrence_basetime,
next_period_idx,
sent->offer->recurrence));
json_add_u64(out, "endtime",
offer_period_start(*inv->recurrence_basetime,
next_period_idx + 1,
sent->offer->recurrence) - 1);

offer_period_paywindow(sent->offer->recurrence,
sent->offer->recurrence_paywindow,
sent->offer->recurrence_base,
*inv->recurrence_basetime,
next_period_idx,
&paywindow_start, &paywindow_end);
json_add_u64(out, "paywindow_start", paywindow_start);
json_add_u64(out, "paywindow_end", paywindow_end);
json_object_end(out);
}
}

discard_result(command_finished(sent->cmd, out));
return command_hook_success(cmd);

Expand Down
15 changes: 15 additions & 0 deletions tests/test_pay.py
Original file line number Diff line number Diff line change
Expand Up @@ -3856,6 +3856,8 @@ def test_fetchinvoice(node_factory, bitcoind):
inv1 = l1.rpc.call('fetchinvoice', {'offer': offer})
inv2 = l1.rpc.call('fetchinvoice', {'offer': offer})
assert inv1 != inv2
assert 'next_period' not in inv1
assert 'next_period' not in inv2
l1.rpc.pay(inv1['invoice'])
l1.rpc.pay(inv2['invoice'])

Expand All @@ -3868,6 +3870,8 @@ def test_fetchinvoice(node_factory, bitcoind):
inv1 = l1.rpc.call('fetchinvoice', {'offer': offer})
inv2 = l1.rpc.call('fetchinvoice', {'offer': offer})
assert inv1 != inv2
assert 'next_period' not in inv1
assert 'next_period' not in inv2

l1.rpc.pay(inv1['invoice'])

Expand All @@ -3890,12 +3894,23 @@ def test_fetchinvoice(node_factory, bitcoind):
'recurrence_counter': 0,
'recurrence_label': 'test recurrence'})
print(ret)
period1 = ret['next_period']
assert period1['counter'] == 1
assert period1['endtime'] == period1['starttime'] + 59
assert period1['paywindow_start'] == period1['starttime'] - 60
assert period1['paywindow_end'] == period1['endtime']

l1.rpc.pay(ret['invoice'], label='test recurrence')

ret = l1.rpc.call('fetchinvoice', {'offer': offer,
'recurrence_counter': 1,
'recurrence_label': 'test recurrence'})
print(ret)
period2 = ret['next_period']
assert period2['counter'] == 2
assert period2['starttime'] == period1['endtime'] + 1
assert period2['endtime'] == period2['starttime'] + 59
assert period2['paywindow_start'] == period2['starttime'] - 60
assert period2['paywindow_end'] == period2['endtime']

l1.rpc.pay(ret['invoice'], label='test recurrence')

0 comments on commit b8fefa4

Please sign in to comment.