diff --git a/daemon/db.c b/daemon/db.c index e4ec2750b..9076d3509 100644 --- a/daemon/db.c +++ b/daemon/db.c @@ -1969,3 +1969,20 @@ bool db_resolve_invoice(struct lightningd_state *dstate, const struct rval *r) tal_free(ctx); return !errmsg; } + +bool db_remove_invoice(struct lightningd_state *dstate, + const char *label) +{ + const char *errmsg, *ctx = tal(dstate, char); + + log_debug(dstate->base_log, "%s", __func__); + + assert(!dstate->db->in_transaction); + + errmsg = db_exec(ctx, dstate, "DELETE FROM invoice WHERE label=x'%s';", + tal_hexstr(ctx, label, strlen(label))); + if (errmsg) + log_broken(dstate->base_log, "%s:%s", __func__, errmsg); + tal_free(ctx); + return !errmsg; +} diff --git a/daemon/db.h b/daemon/db.h index 6a5742068..d67bc6387 100644 --- a/daemon/db.h +++ b/daemon/db.h @@ -42,6 +42,9 @@ bool db_new_invoice(struct lightningd_state *dstate, const char *label, const struct rval *r); +bool db_remove_invoice(struct lightningd_state *dstate, + const char *label); + /* FIXME: save error handling until db_commit_transaction for calls * which have to be inside transaction anyway. */ diff --git a/daemon/invoice.c b/daemon/invoice.c index 70d8709c5..25a4e58e0 100644 --- a/daemon/invoice.c +++ b/daemon/invoice.c @@ -165,3 +165,51 @@ const struct json_command listinvoice_command = { "Returns an array of {label}, {rhash}, {msatoshi} and {complete} on success. " }; +static void json_delinvoice(struct command *cmd, + const char *buffer, const jsmntok_t *params) +{ + struct invoice *i; + jsmntok_t *labeltok; + struct json_result *response = new_json_result(cmd); + const char *label; + + if (!json_get_params(buffer, params, + "label", &labeltok, + NULL)) { + command_fail(cmd, "Invalid arguments"); + return; + } + + label = tal_strndup(cmd, buffer + labeltok->start, + labeltok->end - labeltok->start); + i = find_invoice_by_label(cmd->dstate, label); + if (!i) { + command_fail(cmd, "Unknown invoice"); + return; + } + if (i->complete) { + command_fail(cmd, "Invoice already paid"); + return; + } + if (!db_remove_invoice(cmd->dstate, i->label)) { + command_fail(cmd, "Database error"); + return; + } + list_del_from(&cmd->dstate->invoices, &i->list); + + json_object_start(response, NULL); + json_add_string(response, "label", i->label); + json_add_hex(response, "rhash", &i->rhash, sizeof(i->rhash)); + json_add_u64(response, "msatoshi", i->msatoshi); + json_object_end(response); + command_success(cmd, response); + tal_free(i); +} + +const struct json_command delinvoice_command = { + "delinvoice", + json_delinvoice, + "Delete unpaid invoice {label}))", + "Returns {label}, {rhash} and {msatoshi} on success. " +}; + diff --git a/daemon/jsonrpc.c b/daemon/jsonrpc.c index d9a22e15d..51e6a8dc1 100644 --- a/daemon/jsonrpc.c +++ b/daemon/jsonrpc.c @@ -291,6 +291,7 @@ static const struct json_command *cmdlist[] = { &newaddr_command, &invoice_command, &listinvoice_command, + &delinvoice_command, &getroute_command, &sendpay_command, &feerate_command, diff --git a/daemon/jsonrpc.h b/daemon/jsonrpc.h index 388d28de2..4f97d7766 100644 --- a/daemon/jsonrpc.h +++ b/daemon/jsonrpc.h @@ -73,6 +73,7 @@ extern const struct json_command signcommit_command; extern const struct json_command output_command; extern const struct json_command invoice_command; extern const struct json_command listinvoice_command; +extern const struct json_command delinvoice_command; extern const struct json_command add_route_command; extern const struct json_command routefail_command; extern const struct json_command getroute_command; diff --git a/daemon/test/test.sh b/daemon/test/test.sh index 64a017629..8356b02bd 100755 --- a/daemon/test/test.sh +++ b/daemon/test/test.sh @@ -1000,6 +1000,12 @@ HTLCID4=`lcli1 newhtlc $ID2 $(($HTLC_AMOUNT - 1)) $EXPIRY $RHASH4 | extract_id` check lcli2 "getlog | $FGREP 'Short payment for'" check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE "" +lcli2 delinvoice RHASH4 +if lcli2 delinvoice RHASH3 >/dev/null; then + echo "Should not be able to delete completed invoice!" >&2 + exit 1 +fi + if [ ! -n "$MANUALCOMMIT" ]; then # Test routing to a third node. P2SHADDR2=`$LCLI2 newaddr | sed -n 's/{ "address" : "\(.*\)" }/\1/p'`