From 660c9af1d9e1966080cfe066924abdc39e380301 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 19 Sep 2022 10:19:52 +0930 Subject: [PATCH] autoclean: allow cleaning of paid invoices too. Signed-off-by: Rusty Russell --- plugins/autoclean.c | 28 ++++++++++++++++++++-------- tests/test_plugin.py | 17 ++++++++++++++++- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/plugins/autoclean.c b/plugins/autoclean.c index f91b10008..cdbbc81cf 100644 --- a/plugins/autoclean.c +++ b/plugins/autoclean.c @@ -8,10 +8,12 @@ #include enum subsystem { + PAIDINVOICES, EXPIREDINVOICES, #define NUM_SUBSYSTEM (EXPIREDINVOICES + 1) }; static const char *subsystem_str[] = { + "paidinvoices", "expiredinvoices", }; @@ -94,9 +96,9 @@ static struct command_result *clean_finished_one(struct command *cmd) static struct command_result *del_done(struct command *cmd, const char *buf, const jsmntok_t *result, - ptrint_t *unused) + ptrint_t *subsystemp) { - num_cleaned[EXPIREDINVOICES]++; + num_cleaned[ptr2int(subsystemp)]++; return clean_finished_one(cmd); } @@ -124,11 +126,20 @@ static struct command_result *listinvoices_done(struct command *cmd, json_for_each_arr(i, t, inv) { const jsmntok_t *status = json_get_member(buf, t, "status"); const jsmntok_t *time; + enum subsystem subsys; u64 invtime; - if (json_tok_streq(buf, status, "expired")) + if (json_tok_streq(buf, status, "expired")) { + subsys = EXPIREDINVOICES; time = json_get_member(buf, t, "expires_at"); - else + } else if (json_tok_streq(buf, status, "paid")) { + subsys = PAIDINVOICES; + time = json_get_member(buf, t, "paid_at"); + } else + continue; + + /* Continue if we don't care. */ + if (subsystem_age[subsys] == 0) continue; if (!json_to_u64(buf, time, &invtime)) { @@ -137,17 +148,17 @@ static struct command_result *listinvoices_done(struct command *cmd, json_tok_full(buf, time)); } - if (invtime <= now - subsystem_age[EXPIREDINVOICES]) { + if (invtime <= now - subsystem_age[subsys]) { struct out_req *req; const jsmntok_t *label = json_get_member(buf, t, "label"); req = jsonrpc_request_start(plugin, NULL, "delinvoice", del_done, del_failed, - int2ptr(EXPIREDINVOICES)); + int2ptr(subsys)); json_add_tok(req->js, "label", label, buf); json_add_tok(req->js, "status", status, buf); send_outreq(plugin, req); - plugin_log(plugin, LOG_DBG, "Expiring %.*s", + plugin_log(plugin, LOG_DBG, "Cleaning up %.*s", json_tok_full_len(label), json_tok_full(buf, label)); cleanup_reqs_remaining++; } @@ -163,7 +174,8 @@ static void do_clean(void *unused) struct out_req *req = NULL; assert(cleanup_reqs_remaining == 0); - if (subsystem_age[EXPIREDINVOICES] != 0) { + if (subsystem_age[EXPIREDINVOICES] != 0 + || subsystem_age[PAIDINVOICES] != 0) { req = jsonrpc_request_start(plugin, NULL, "listinvoices", listinvoices_done, cmd_failed, (char *)"listinvoices"); diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 32cb13bf8..a9d83a9e4 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -2935,12 +2935,14 @@ def test_commando_badrune(node_factory): def test_autoclean(node_factory): - l1 = node_factory.get_node(options={'autoclean-cycle': 10}) + l0, l1 = node_factory.line_graph(2, opts={'autoclean-cycle': 10, + 'may_reconnect': True}) assert l1.rpc.autoclean_status('expiredinvoices')['autoclean']['expiredinvoices']['enabled'] is False l1.rpc.invoice(amount_msat=12300, label='inv1', description='description1', expiry=5) l1.rpc.invoice(amount_msat=12300, label='inv2', description='description2', expiry=20) l1.rpc.invoice(amount_msat=12300, label='inv3', description='description3', expiry=20) + inv4 = l1.rpc.invoice(amount_msat=12300, label='inv4', description='description4', expiry=2000) l1.rpc.autoclean(subsystem='expiredinvoices', age=2) assert l1.rpc.autoclean_status()['autoclean']['expiredinvoices']['enabled'] is True assert l1.rpc.autoclean_status()['autoclean']['expiredinvoices']['age'] == 2 @@ -2983,8 +2985,21 @@ def test_autoclean(node_factory): # Now enable: they will get autocleaned l1.rpc.autoclean(subsystem='expiredinvoices', age=2) + wait_for(lambda: len(l1.rpc.listinvoices()['invoices']) == 1) + assert l1.rpc.autoclean_status()['autoclean']['expiredinvoices']['cleaned'] == 3 + + # Reconnect, l0 pays invoice, we test paid expiry. + l1.rpc.connect(l0.info['id'], 'localhost', l0.port) + l0.rpc.pay(inv4['bolt11']) + + assert l1.rpc.autoclean_status()['autoclean']['paidinvoices']['enabled'] is False + assert l1.rpc.autoclean_status()['autoclean']['paidinvoices']['cleaned'] == 0 + l1.rpc.autoclean(subsystem='paidinvoices', age=1) + assert l1.rpc.autoclean_status()['autoclean']['paidinvoices']['enabled'] is True + wait_for(lambda: l1.rpc.listinvoices()['invoices'] == []) assert l1.rpc.autoclean_status()['autoclean']['expiredinvoices']['cleaned'] == 3 + assert l1.rpc.autoclean_status()['autoclean']['paidinvoices']['cleaned'] == 1 def test_block_added_notifications(node_factory, bitcoind):