diff --git a/doc/lightningd-config.5.md b/doc/lightningd-config.5.md index f846ba808..61c038b82 100644 --- a/doc/lightningd-config.5.md +++ b/doc/lightningd-config.5.md @@ -437,6 +437,30 @@ accepted, and ignored. Perform search for things to clean every *SECONDS* seconds (default 3600, or 1 hour, which is usually sufficient). +* **autoclean-succeededforwards-age**=*SECONDS* [plugin `autoclean`] + + How old successful forwards (`settled` in listforwards `status`) have to be before deletion (default 0, meaning never). + +* **autoclean-failedforwards-age**=*SECONDS* [plugin `autoclean`] + + How old failed forwards (`failed` or `local_failed` in listforwards `status`) have to be before deletion (default 0, meaning never). + +* **autoclean-succeededpays-age**=*SECONDS* [plugin `autoclean`] + + How old successful payments (`complete` in listpays `status`) have to be before deletion (default 0, meaning never). + +* **autoclean-failedpays-age**=*SECONDS* [plugin `autoclean`] + + How old failed payment attempts (`failed` in listpays `status`) have to be before deletion (default 0, meaning never). + +* **autoclean-paidinvoices-age**=*SECONDS* [plugin `autoclean`] + + How old invoices which were paid (`paid` in listinvoices `status`) have to be before deletion (default 0, meaning never). + +* **autoclean-expiredinvoices-age**=*SECONDS* [plugin `autoclean`] + + How old invoices which were not paid (and cannot be) (`expired` in listinvoices `status`) before deletion (default 0, meaning never). + ### Payment control options: * **disable-mpp** [plugin `pay`] diff --git a/plugins/autoclean.c b/plugins/autoclean.c index a7fdf4908..12e7bf889 100644 --- a/plugins/autoclean.c +++ b/plugins/autoclean.c @@ -16,6 +16,7 @@ enum subsystem { EXPIREDINVOICES, #define NUM_SUBSYSTEM (EXPIREDINVOICES + 1) }; + static const char *subsystem_str[] = { "succeededforwards", "failedforwards", @@ -366,23 +367,6 @@ static struct command_result *json_autocleaninvoice(struct command *cmd, return command_finished(cmd, response); } -static struct command_result *param_age(struct command *cmd, const char *name, - const char *buffer, const jsmntok_t *tok, - uint64_t **num) -{ - *num = tal(cmd, uint64_t); - if (json_to_u64(buffer, tok, *num) && *num != 0) - return NULL; - - if (json_tok_streq(buffer, tok, "never")) { - **num = 0; - return NULL; - } - - return command_fail_badparam(cmd, name, buffer, tok, - "should be an positive 64 bit integer or 'never'"); -} - static struct command_result *param_subsystem(struct command *cmd, const char *name, const char *buffer, @@ -431,28 +415,6 @@ static struct command_result *json_autoclean_status(struct command *cmd, return json_success_subsystems(cmd, subsystem); } -static struct command_result *json_autoclean(struct command *cmd, - const char *buffer, - const jsmntok_t *params) -{ - enum subsystem *subsystem; - u64 *age; - - if (!param(cmd, buffer, params, - p_req("subsystem", param_subsystem, &subsystem), - p_req("age", param_age, &age), - NULL)) - return command_param_failed(); - - subsystem_age[*subsystem] = *age; - jsonrpc_set_datastore_string(cmd->plugin, cmd, - datastore_path(tmpctx, *subsystem, "age"), - tal_fmt(tmpctx, "%"PRIu64, *age), - "create-or-replace", NULL, NULL, NULL); - - return json_success_subsystems(cmd, subsystem); -} - static const char *init(struct plugin *p, const char *buf UNUSED, const jsmntok_t *config UNUSED) { @@ -463,21 +425,6 @@ static const char *init(struct plugin *p, return NULL; } else cycle_seconds = deprecated_cycle_seconds; - } else { - bool active = false; - for (enum subsystem i = 0; i < NUM_SUBSYSTEM; i++) { - if (!rpc_scan_datastore_str(p, datastore_path(tmpctx, i, "age"), - JSON_SCAN(json_to_u64, &subsystem_age[i]))) - continue; - if (subsystem_age[i]) { - /* Only print this once! */ - if (!active) - plugin_log(p, LOG_INFORM, "autocleaning every %"PRIu64" seconds", cycle_seconds); - active = true; - plugin_log(p, LOG_INFORM, "cleaning %s when age > %"PRIu64" seconds", - subsystem_to_str(i), subsystem_age[i]); - } - } } cleantimer = plugin_timer(p, time_from_sec(cycle_seconds), do_clean, p); @@ -498,12 +445,6 @@ static const struct plugin_command commands[] = { { json_autocleaninvoice, true, /* deprecated! */ }, { - "autoclean", - "utility", - "Automatic deletion of old data (invoices, pays, forwards).", - "Takes {subsystem} and {age} in seconds ", - json_autoclean, - }, { "autoclean-status", "utility", "Show status of autocleaning", @@ -529,9 +470,33 @@ int main(int argc, char *argv[]) " this given seconds are cleaned", u64_option, &subsystem_age[EXPIREDINVOICES]), plugin_option("autoclean-cycle", - "string", + "int", "Perform cleanup every" " given seconds", u64_option, &cycle_seconds), + plugin_option("autoclean-succeededforwards-age", + "int", + "How old do successful forwards have to be before deletion (0 = never)", + u64_option, &subsystem_age[SUCCEEDEDFORWARDS]), + plugin_option("autoclean-failedforwards-age", + "int", + "How old do failed forwards have to be before deletion (0 = never)", + u64_option, &subsystem_age[FAILEDFORWARDS]), + plugin_option("autoclean-succeededpays-age", + "int", + "How old do successful pays have to be before deletion (0 = never)", + u64_option, &subsystem_age[SUCCEEDEDPAYS]), + plugin_option("autoclean-failedpays-age", + "int", + "How old do failed pays have to be before deletion (0 = never)", + u64_option, &subsystem_age[FAILEDPAYS]), + plugin_option("autoclean-paidinvoices-age", + "int", + "How old do paid invoices have to be before deletion (0 = never)", + u64_option, &subsystem_age[PAIDINVOICES]), + plugin_option("autoclean-expiredinvoices-age", + "int", + "How old do expired invoices have to be before deletion (0 = never)", + u64_option, &subsystem_age[EXPIREDINVOICES]), NULL); } diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 89849b6a8..2d874595a 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -2955,7 +2955,10 @@ def test_autoclean(node_factory): l3.rpc.invoice(amount_msat=12300, label='inv3', description='description3', expiry=20) inv4 = l3.rpc.invoice(amount_msat=12300, label='inv4', description='description4', expiry=2000) inv5 = l3.rpc.invoice(amount_msat=12300, label='inv5', description='description5', expiry=2000) - l3.rpc.autoclean(subsystem='expiredinvoices', age=2) + + l3.stop() + l3.daemon.opts['autoclean-expiredinvoices-age'] = 2 + l3.start() assert l3.rpc.autoclean_status()['autoclean']['expiredinvoices']['enabled'] is True assert l3.rpc.autoclean_status()['autoclean']['expiredinvoices']['age'] == 2 @@ -2979,7 +2982,9 @@ def test_autoclean(node_factory): assert l3.rpc.autoclean_status()['autoclean']['expiredinvoices']['cleaned'] == 1 # Disabling works - l3.rpc.autoclean(subsystem='expiredinvoices', age='never') + l3.stop() + l3.daemon.opts['autoclean-expiredinvoices-age'] = 0 + l3.start() assert l3.rpc.autoclean_status()['autoclean']['expiredinvoices']['enabled'] is False assert 'age' not in l3.rpc.autoclean_status()['autoclean']['expiredinvoices'] @@ -2997,7 +3002,9 @@ def test_autoclean(node_factory): assert 'age' not in l3.rpc.autoclean_status()['autoclean']['expiredinvoices'] # Now enable: they will get autocleaned - l3.rpc.autoclean(subsystem='expiredinvoices', age=2) + l3.stop() + l3.daemon.opts['autoclean-expiredinvoices-age'] = 2 + l3.start() wait_for(lambda: len(l3.rpc.listinvoices()['invoices']) == 2) assert l3.rpc.autoclean_status()['autoclean']['expiredinvoices']['cleaned'] == 3 @@ -3012,7 +3019,9 @@ def test_autoclean(node_factory): assert l3.rpc.autoclean_status()['autoclean']['paidinvoices']['enabled'] is False assert l3.rpc.autoclean_status()['autoclean']['paidinvoices']['cleaned'] == 0 - l3.rpc.autoclean(subsystem='paidinvoices', age=1) + l3.stop() + l3.daemon.opts['autoclean-paidinvoices-age'] = 1 + l3.start() assert l3.rpc.autoclean_status()['autoclean']['paidinvoices']['enabled'] is True wait_for(lambda: l3.rpc.listinvoices()['invoices'] == []) @@ -3021,13 +3030,17 @@ def test_autoclean(node_factory): assert only_one(l1.rpc.listpays(inv5['bolt11'])['pays'])['status'] == 'failed' assert only_one(l1.rpc.listpays(inv4['bolt11'])['pays'])['status'] == 'complete' - l1.rpc.autoclean(subsystem='failedpays', age=2) + l1.stop() + l1.daemon.opts['autoclean-failedpays-age'] = 1 + l1.start() wait_for(lambda: l1.rpc.listpays(inv5['bolt11'])['pays'] == []) assert l1.rpc.autoclean_status()['autoclean']['failedpays']['cleaned'] == 1 assert l1.rpc.autoclean_status()['autoclean']['succeededpays']['cleaned'] == 0 - l1.rpc.autoclean(subsystem='succeededpays', age=2) + l1.stop() + l1.daemon.opts['autoclean-succeededpays-age'] = 2 + l1.start() wait_for(lambda: l1.rpc.listpays(inv4['bolt11'])['pays'] == []) assert l1.rpc.listsendpays() == {'payments': []} @@ -3037,7 +3050,9 @@ def test_autoclean(node_factory): assert len(l2.rpc.listforwards()['forwards']) == 2 # Clean failed ones. - l2.rpc.autoclean(subsystem='failedforwards', age=2) + l2.stop() + l2.daemon.opts['autoclean-failedforwards-age'] = 2 + l2.start() wait_for(lambda: l2.rpc.listforwards(status='failed')['forwards'] == []) assert len(l2.rpc.listforwards(status='settled')['forwards']) == 1 @@ -3045,7 +3060,9 @@ def test_autoclean(node_factory): assert l2.rpc.autoclean_status()['autoclean']['succeededforwards']['cleaned'] == 0 # Clean succeeded ones - l2.rpc.autoclean(subsystem='succeededforwards', age=2) + l2.stop() + l2.daemon.opts['autoclean-succeededforwards-age'] = 2 + l2.start() wait_for(lambda: l2.rpc.listforwards(status='settled')['forwards'] == []) assert l2.rpc.listforwards() == {'forwards': []} assert l2.rpc.autoclean_status()['autoclean']['failedforwards']['cleaned'] == 1