diff --git a/common/jsonrpc_errors.h b/common/jsonrpc_errors.h index 64a3aa4b4..ccc7c791c 100644 --- a/common/jsonrpc_errors.h +++ b/common/jsonrpc_errors.h @@ -40,6 +40,7 @@ static const errcode_t PAY_INVOICE_EXPIRED = 207; static const errcode_t PAY_NO_SUCH_PAYMENT = 208; static const errcode_t PAY_UNSPECIFIED_ERROR = 209; static const errcode_t PAY_STOPPED_RETRYING = 210; +static const errcode_t PAY_STATUS_UNEXPECTED = 211; /* `fundchannel` or `withdraw` errors */ static const errcode_t FUND_MAX_EXCEEDED = 300; diff --git a/doc/Makefile b/doc/Makefile index 8d3b056c6..8cdbb511a 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -16,6 +16,7 @@ MANPAGES := doc/lightning-cli.1 \ doc/lightning-decodepay.7 \ doc/lightning-delexpiredinvoice.7 \ doc/lightning-delinvoice.7 \ + doc/lightning-delpay.7 \ doc/lightning-dev-sendcustommsg.7 \ doc/lightning-disconnect.7 \ doc/lightning-feerates.7 \ diff --git a/doc/index.rst b/doc/index.rst index b720bf464..60ab06900 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -38,6 +38,7 @@ c-lightning Documentation lightning-decodepay lightning-delexpiredinvoice lightning-delinvoice + lightning-delpay lightning-dev-sendcustommsg lightning-disconnect lightning-feerates diff --git a/doc/lightning-delpay.7 b/doc/lightning-delpay.7 new file mode 100644 index 000000000..93f63ce37 --- /dev/null +++ b/doc/lightning-delpay.7 @@ -0,0 +1,91 @@ +.TH "LIGHTNING-DELPAY" "7" "" "" "lightning-delpay" +.SH NAME +lightning-delpay - Command for removing a completed or failed payment +.SH SYNOPSIS + +\fBdelpay\fR \fIpayment_hash\fR [status] + +.SH DESCRIPTION + +The \fBdelpay\fR RPC command removes a payment as given in \fBlistsendpays\fR or \fBlistpays\fR with a complete or failed +status\. However, the command doesn't permit to remove a pending payment\. + +.RS +.IP \[bu] +\fIpayment_hash\fR: Rapresents the unique identifier of a payment\. To find it, you can run \fBlistpays\fR or \fBlistsendpays\fR; +.IP \[bu] +\fIstatus\fR is the expected status of the payment\. It can be \fIcomplete\fR or \fIfailed\fR\. +Only delete if the payment status matches\. If not specified, defaults to \fIcomplete\fR\. + +.RE +.SH EXAMPLE JSON REQUEST +.nf +.RS +{ + "id": 82, + "method": "delpay", + "params": { + "payment_hash": "4fa2f1b001067ec06d7f95b8695b8acd9ef04c1b4d1110e3b94e1fa0687bb1e0", + "status": "complete" + } +} +.RE + +.fi +.SH RETURN VALUE + +On success, the command will return a payment object, such as the \fBlistsendpays\fR\. In addition, if the payment is a MPP (Multi part payment) the command return a list of +payments; a payment object for each partid\. + + +On failure, an error is returned and any payment is deleted\. If the lightning process fails before responding, the +caller should use \fBlightning-listsentpays\fR(7) or \fBlightning-listpays\fR(7) to query whether this payment was deleted or not\. + + +The following error codes may occur: + +.RS +.IP \[bu] +-32602: Some parameter missed or some parameter is malformed; +.IP \[bu] +211: Payment with payment_hash have a wrong status\. To check the correct status run the command \fBpaystatus\fR; +.IP \[bu] +208: Payment with payment_hash not found\. + +.RE +.SH EXAMPLE JSON RESPONSE +.nf +.RS +{ + "payments": [ + { + "id": 2, + "payment_hash": "8dfd6538eeb33811c9114a75f792a143728d7f05643f38c3d574d3097e8910c0", + "destination": "0219f8900ee78a89f050c24d8b69492954f9fdbabed753710845eb75d3a75a5880", + "msatoshi": 1000, + "amount_msat": "1000msat", + "msatoshi_sent": 1000, + "amount_sent_msat": "1000msat", + "created_at": 1596224858, + "status": "complete", + "payment_preimage": "35bd4e2b481a1a84a22215b5372672cf81460a671816960ddb206464359e1822", + "bolt11": "lntb10n1p0jga20pp53h7k2w8wkvuprjg3ff6l0y4pgdeg6lc9vsln3s74wnfsjl5fzrqqdqdw3jhxazldahx2xqyjw5qcqp2sp5wut5jnhr6n7jd5747ky2g5flmw7hgx9yjnqzu60ps2jf6f7tc0us9qy9qsqu2a0k37nckl62005p69xavlkydkvhnypk4dphffy4x09zltwh9437ad7xkl83tefdarzhu5t30ju5s56wlrg97qkx404pq3srfc425cq3ke9af" + } + ] +} +.RE + +.fi +.SH AUTHOR + +Vincenzo Palazzo \fI is mainly responsible\. + +.SH SEE ALSO + +\fBlightning-listpays\fR(7), \fBlightning-listsendpays\fR(7), \fBlightning-paystatus\fR(7)\. + +.SH RESOURCES + +Main web site: \fIhttps://github.com/ElementsProject/lightning\fR + +\" SHA256STAMP:57aa95a96bb9be2cd66df3f71e9260985a53d7126862b7973179323236e3d113 diff --git a/doc/lightning-delpay.7.md b/doc/lightning-delpay.7.md new file mode 100644 index 000000000..b578ef549 --- /dev/null +++ b/doc/lightning-delpay.7.md @@ -0,0 +1,84 @@ +lightning-delpay -- Command for removing a completed or failed payment +============================================================ + +SYNOPSIS +-------- + +**delpay** *payment\_hash* \[status\] + +DESCRIPTION +----------- + +The **delpay** RPC command removes a payment as given in **listsendpays** or **listpays** with a complete or failed +status. However, the command doesn't permit to remove a pending payment. + +- *payment\_hash*: Rapresents the unique identifier of a payment. To find it, you can run **listpays** or **listsendpays**; +- *status* is the expected status of the payment. It can be *complete* or *failed*. +Only delete if the payment status matches. If not specified, defaults to *complete*. + +EXAMPLE JSON REQUEST +------------ +```json +{ + "id": 82, + "method": "delpay", + "params": { + "payment_hash": "4fa2f1b001067ec06d7f95b8695b8acd9ef04c1b4d1110e3b94e1fa0687bb1e0", + "status": "complete" + } +} +``` + +RETURN VALUE +------------ + +On success, the command will return a payment object, such as the **listsendpays**. In addition, if the payment is a MPP (Multi part payment) the command return a list of +payments; a payment object for each partid. + +On failure, an error is returned and any payment is deleted. If the lightning process fails before responding, the +caller should use lightning-listsentpays(7) or lightning-listpays(7) to query whether this payment was deleted or not. + +The following error codes may occur: + +- -32602: Some parameter missed or some parameter is malformed; +- 211: Payment with payment\_hash have a wrong status. To check the correct status run the command **paystatus**; +- 208: Payment with payment\_hash not found. + +EXAMPLE JSON RESPONSE +----- +```json +{ + "payments": [ + { + "id": 2, + "payment_hash": "8dfd6538eeb33811c9114a75f792a143728d7f05643f38c3d574d3097e8910c0", + "destination": "0219f8900ee78a89f050c24d8b69492954f9fdbabed753710845eb75d3a75a5880", + "msatoshi": 1000, + "amount_msat": "1000msat", + "msatoshi_sent": 1000, + "amount_sent_msat": "1000msat", + "created_at": 1596224858, + "status": "complete", + "payment_preimage": "35bd4e2b481a1a84a22215b5372672cf81460a671816960ddb206464359e1822", + "bolt11": "lntb10n1p0jga20pp53h7k2w8wkvuprjg3ff6l0y4pgdeg6lc9vsln3s74wnfsjl5fzrqqdqdw3jhxazldahx2xqyjw5qcqp2sp5wut5jnhr6n7jd5747ky2g5flmw7hgx9yjnqzu60ps2jf6f7tc0us9qy9qsqu2a0k37nckl62005p69xavlkydkvhnypk4dphffy4x09zltwh9437ad7xkl83tefdarzhu5t30ju5s56wlrg97qkx404pq3srfc425cq3ke9af" + } + ] +} + +``` + + +AUTHOR +------ + +Vincenzo Palazzo <> is mainly responsible. + +SEE ALSO +-------- + +lightning-listpays(7), lightning-listsendpays(7), lightning-paystatus(7). + +RESOURCES +--------- + +Main web site: diff --git a/lightningd/pay.c b/lightningd/pay.c index 321ae2634..40ae9b93e 100644 --- a/lightningd/pay.c +++ b/lightningd/pay.c @@ -42,6 +42,34 @@ struct sendpay_command { struct command *cmd; }; +static bool string_to_payment_status(const char *status_str, enum wallet_payment_status *status) +{ + if (streq(status_str, "complete")) { + *status = PAYMENT_COMPLETE; + return true; + } else if (streq(status_str, "pending")) { + *status = PAYMENT_PENDING; + return true; + } else if (streq(status_str, "failed")) { + *status = PAYMENT_FAILED; + return true; + } + return false; +} + +static const char *payment_status_to_string(const enum wallet_payment_status status) +{ + switch (status) { + case PAYMENT_COMPLETE: + return "complete"; + case PAYMENT_FAILED: + return "failed"; + default: + return "pending"; + } +} + + static void destroy_sendpay_command(struct sendpay_command *pc) { list_del(&pc->list); @@ -1486,6 +1514,73 @@ static const struct json_command listsendpays_command = { }; AUTODATA(json_command, &listsendpays_command); + +static struct command_result *json_delpay(struct command *cmd, + const char *buffer, + const jsmntok_t *obj UNNEEDED, + const jsmntok_t *params) +{ + struct json_stream *response; + const struct wallet_payment **payments; + const char *status_str; + enum wallet_payment_status status; + struct sha256 *payment_hash; + + if (!param(cmd, buffer, params, + p_req("payment_hash", param_sha256, &payment_hash), + p_opt("status", param_string, &status_str), + NULL)) + return command_param_failed(); + + if (!status_str) + status_str = "complete"; + + if (!string_to_payment_status(status_str, &status)) + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, + "Unrecognized status: %s", status_str); + + if (status == PAYMENT_PENDING) + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "Invalid status: %s", + payment_status_to_string(status)); + + payments = wallet_payment_list(cmd, cmd->ld->wallet, payment_hash); + + if (tal_count(payments) == 0) + return command_fail(cmd, PAY_NO_SUCH_PAYMENT, + "Unknown payment with payment_hash: %s", + type_to_string(tmpctx, struct sha256, payment_hash)); + + for (int i = 0; i < tal_count(payments); i++) { + if (payments[i]->status != status) { + return command_fail(cmd, PAY_STATUS_UNEXPECTED, + "Payment with hash %s has %s status but it should be %s", + type_to_string(tmpctx, struct sha256, payment_hash), + payment_status_to_string(payments[i]->status), + payment_status_to_string(status)); + } + } + + wallet_payment_delete_by_hash(cmd->ld->wallet, payment_hash); + + response = json_stream_success(cmd); + json_array_start(response, "payments"); + for (int i = 0; i < tal_count(payments); i++) { + json_object_start(response, NULL); + json_add_payment_fields(response, payments[i]); + json_object_end(response); + } + json_array_end(response); + return command_success(cmd, response); +} + +static const struct json_command delpay_command = { + "delpay", + "payment", + json_delpay, + "Delete payment with {payment_hash} and {status}", +}; +AUTODATA(json_command, &delpay_command); + static struct command_result *json_createonion(struct command *cmd, const char *buffer, const jsmntok_t *obj UNNEEDED, diff --git a/tests/test_pay.py b/tests/test_pay.py index 562be8b90..8cf725272 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -3263,6 +3263,107 @@ def test_mpp_presplit_routehint_conflict(node_factory, bitcoind): l1.rpc.pay(inv) +def test_delpay_argument_invalid(node_factory, bitcoind): + """ + This test includes all possible combination of input error inside the + delpay command. + """ + + l1, l2 = node_factory.get_nodes(2) + + with pytest.raises(RpcError): + l2.rpc.delpay() + + # invoice unpayed + inv = l1.rpc.invoice(10 ** 5, 'inv', 'inv') + payment_hash = inv["payment_hash"] + with pytest.raises(RpcError): + l2.rpc.delpay(payment_hash) + + # payment unpayed with wrong status (pending status is a illegal input) + with pytest.raises(RpcError): + l2.rpc.delpay(payment_hash, 'pending') + + with pytest.raises(RpcError): + l2.rpc.delpay(payment_hash, 'invalid_status') + + l2.rpc.connect(l1.info['id'], 'localhost', l1.port) + l2.fund_channel(l1, 10 ** 6) + + bitcoind.generate_block(6) + sync_blockheight(bitcoind, [l1, l2]) + + wait_for(lambda: len(l2.rpc.listchannels()['channels']) == 2) + + l2.rpc.pay(inv['bolt11']) + + with pytest.raises(RpcError): + l2.rpc.delpay(payment_hash, 'failed') + + with pytest.raises(RpcError): + l2.rpc.delpay(payment_hash, 'pending') + + assert len(l2.rpc.listpays()['pays']) == 1 + + # test if the node is still ready + payments = l2.rpc.delpay(payment_hash, 'complete') + + assert payments['payments'][0]['bolt11'] == inv['bolt11'] + assert len(payments['payments']) == 1 + assert len(l2.rpc.listpays()['pays']) == 0 + + +def test_delpay(node_factory, bitcoind): + """ + This unit test try to catch some error inside the command + delpay when it receives the correct input from the user + """ + + l1, l2 = node_factory.get_nodes(2) + + amount_sat = 10 ** 6 + + # create l2->l1 channel. + l2.fundwallet(amount_sat * 5) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + l2.rpc.fundchannel(l1.info['id'], amount_sat * 3) + + # Let the channel confirm. + bitcoind.generate_block(6) + sync_blockheight(bitcoind, [l1, l2]) + + invl1 = l1.rpc.invoice(Millisatoshi(amount_sat * 2 * 1000), "j", "j") + l2.rpc.pay(invl1["bolt11"]) + + before_del_pay = l2.rpc.listpays() + + l2.rpc.delpay(invl1["payment_hash"]) + + after_del_pay = l2.rpc.listpays()["pays"] + assert len(after_del_pay) == (len(before_del_pay) - 1) + + +def test_delpay_payment_split(node_factory, bitcoind): + """ + This test test the correct bheaivord of the commmand delpay with a mpp + """ + MPP_TARGET_SIZE = 10**7 # Taken from libpluin-pay.c + amt = 5 * MPP_TARGET_SIZE + + l1, l2, l3 = node_factory.line_graph( + 3, fundamount=10**8, wait_for_announce=True, + opts={'wumbo': None} + ) + + inv = l3.rpc.invoice(amt, 'lbl', 'desc') + l1.rpc.pay(inv['bolt11']) + + assert len(l1.rpc.listpays()['pays']) == 1 + delpay_result = l1.rpc.delpay(inv['payment_hash'], 'complete')['payments'] + assert len(delpay_result) >= 5 + assert len(l1.rpc.listpays()['pays']) == 0 + + def test_listpay_result_with_paymod(node_factory, bitcoind): """ The object of this test is to verify the correct behavior diff --git a/wallet/db_postgres_sqlgen.c b/wallet/db_postgres_sqlgen.c index 59054dd69..4c092bc4e 100644 --- a/wallet/db_postgres_sqlgen.c +++ b/wallet/db_postgres_sqlgen.c @@ -1358,6 +1358,12 @@ struct db_query db_postgres_queries[] = { .placeholders = 2, .readonly = false, }, + { + .name = "DELETE FROM payments WHERE payment_hash = ?", + .query = "DELETE FROM payments WHERE payment_hash = $1", + .placeholders = 1, + .readonly = false, + }, { .name = "SELECT id, status, destination, msatoshi, payment_hash, timestamp, payment_preimage, path_secrets, route_nodes, route_channels, msatoshi_sent, description, bolt11, failonionreply, total_msat, partid FROM payments WHERE payment_hash = ? AND partid = ?", .query = "SELECT id, status, destination, msatoshi, payment_hash, timestamp, payment_preimage, path_secrets, route_nodes, route_channels, msatoshi_sent, description, bolt11, failonionreply, total_msat, partid FROM payments WHERE payment_hash = $1 AND partid = $2", @@ -1642,10 +1648,10 @@ struct db_query db_postgres_queries[] = { }, }; -#define DB_POSTGRES_QUERY_COUNT 272 +#define DB_POSTGRES_QUERY_COUNT 273 #endif /* HAVE_POSTGRES */ #endif /* LIGHTNINGD_WALLET_GEN_DB_POSTGRES */ -// SHA256STAMP:4c9787464f33fe9bfd209efbd84daebeb5584d52daa1d83f4c34f9a0a6108b46 +// SHA256STAMP:849372d40a212ddb790eb4e3181c6b525dce234e48cda9b71b8909527bd48e33 diff --git a/wallet/db_sqlite3_sqlgen.c b/wallet/db_sqlite3_sqlgen.c index d8dbc441e..16eb53879 100644 --- a/wallet/db_sqlite3_sqlgen.c +++ b/wallet/db_sqlite3_sqlgen.c @@ -1358,6 +1358,12 @@ struct db_query db_sqlite3_queries[] = { .placeholders = 2, .readonly = false, }, + { + .name = "DELETE FROM payments WHERE payment_hash = ?", + .query = "DELETE FROM payments WHERE payment_hash = ?", + .placeholders = 1, + .readonly = false, + }, { .name = "SELECT id, status, destination, msatoshi, payment_hash, timestamp, payment_preimage, path_secrets, route_nodes, route_channels, msatoshi_sent, description, bolt11, failonionreply, total_msat, partid FROM payments WHERE payment_hash = ? AND partid = ?", .query = "SELECT id, status, destination, msatoshi, payment_hash, timestamp, payment_preimage, path_secrets, route_nodes, route_channels, msatoshi_sent, description, bolt11, failonionreply, total_msat, partid FROM payments WHERE payment_hash = ? AND partid = ?", @@ -1642,10 +1648,10 @@ struct db_query db_sqlite3_queries[] = { }, }; -#define DB_SQLITE3_QUERY_COUNT 272 +#define DB_SQLITE3_QUERY_COUNT 273 #endif /* HAVE_SQLITE3 */ #endif /* LIGHTNINGD_WALLET_GEN_DB_SQLITE3 */ -// SHA256STAMP:4c9787464f33fe9bfd209efbd84daebeb5584d52daa1d83f4c34f9a0a6108b46 +// SHA256STAMP:849372d40a212ddb790eb4e3181c6b525dce234e48cda9b71b8909527bd48e33 diff --git a/wallet/statements_gettextgen.po b/wallet/statements_gettextgen.po index 09d558dab..7190d2502 100644 --- a/wallet/statements_gettextgen.po +++ b/wallet/statements_gettextgen.po @@ -898,179 +898,183 @@ msgstr "" msgid "DELETE FROM payments WHERE payment_hash = ? AND partid = ?" msgstr "" -#: wallet/wallet.c:2581 +#: wallet/wallet.c:2497 +msgid "DELETE FROM payments WHERE payment_hash = ?" +msgstr "" + +#: wallet/wallet.c:2592 msgid "SELECT id, status, destination, msatoshi, payment_hash, timestamp, payment_preimage, path_secrets, route_nodes, route_channels, msatoshi_sent, description, bolt11, failonionreply, total_msat, partid FROM payments WHERE payment_hash = ? AND partid = ?" msgstr "" -#: wallet/wallet.c:2630 +#: wallet/wallet.c:2641 msgid "UPDATE payments SET status=? WHERE payment_hash=? AND partid=?" msgstr "" -#: wallet/wallet.c:2640 +#: wallet/wallet.c:2651 msgid "UPDATE payments SET payment_preimage=? WHERE payment_hash=? AND partid=?" msgstr "" -#: wallet/wallet.c:2650 +#: wallet/wallet.c:2661 msgid "UPDATE payments SET path_secrets = NULL , route_nodes = NULL , route_channels = NULL WHERE payment_hash = ? AND partid = ?;" msgstr "" -#: wallet/wallet.c:2682 +#: wallet/wallet.c:2693 msgid "SELECT failonionreply, faildestperm, failindex, failcode, failnode, failchannel, failupdate, faildetail, faildirection FROM payments WHERE payment_hash=? AND partid=?;" msgstr "" -#: wallet/wallet.c:2749 +#: wallet/wallet.c:2760 msgid "UPDATE payments SET failonionreply=? , faildestperm=? , failindex=? , failcode=? , failnode=? , failchannel=? , failupdate=? , faildetail=? , faildirection=? WHERE payment_hash=? AND partid=?;" msgstr "" -#: wallet/wallet.c:2808 +#: wallet/wallet.c:2819 msgid "SELECT id, status, destination, msatoshi, payment_hash, timestamp, payment_preimage, path_secrets, route_nodes, route_channels, msatoshi_sent, description, bolt11, failonionreply, total_msat, partid FROM payments WHERE payment_hash = ?;" msgstr "" -#: wallet/wallet.c:2829 +#: wallet/wallet.c:2840 msgid "SELECT id, status, destination, msatoshi, payment_hash, timestamp, payment_preimage, path_secrets, route_nodes, route_channels, msatoshi_sent, description, bolt11, failonionreply, total_msat, partid FROM payments ORDER BY id;" msgstr "" -#: wallet/wallet.c:2873 +#: wallet/wallet.c:2884 msgid "DELETE FROM htlc_sigs WHERE channelid = ?" msgstr "" -#: wallet/wallet.c:2880 +#: wallet/wallet.c:2891 msgid "INSERT INTO htlc_sigs (channelid, signature) VALUES (?, ?)" msgstr "" -#: wallet/wallet.c:2892 +#: wallet/wallet.c:2903 msgid "SELECT blobval FROM vars WHERE name='genesis_hash'" msgstr "" -#: wallet/wallet.c:2916 +#: wallet/wallet.c:2927 msgid "INSERT INTO vars (name, blobval) VALUES ('genesis_hash', ?);" msgstr "" -#: wallet/wallet.c:2932 +#: wallet/wallet.c:2943 msgid "DELETE FROM utxoset WHERE spendheight < ?" msgstr "" -#: wallet/wallet.c:2940 wallet/wallet.c:3050 +#: wallet/wallet.c:2951 wallet/wallet.c:3061 msgid "INSERT INTO blocks (height, hash, prev_hash) VALUES (?, ?, ?);" msgstr "" -#: wallet/wallet.c:2959 +#: wallet/wallet.c:2970 msgid "DELETE FROM blocks WHERE hash = ?" msgstr "" -#: wallet/wallet.c:2965 +#: wallet/wallet.c:2976 msgid "SELECT * FROM blocks WHERE height >= ?;" msgstr "" -#: wallet/wallet.c:2974 +#: wallet/wallet.c:2985 msgid "DELETE FROM blocks WHERE height > ?" msgstr "" -#: wallet/wallet.c:2986 +#: wallet/wallet.c:2997 msgid "UPDATE outputs SET spend_height = ?, status = ? WHERE prev_out_tx = ? AND prev_out_index = ?" msgstr "" -#: wallet/wallet.c:3003 +#: wallet/wallet.c:3014 msgid "UPDATE utxoset SET spendheight = ? WHERE txid = ? AND outnum = ?" msgstr "" -#: wallet/wallet.c:3025 wallet/wallet.c:3061 +#: wallet/wallet.c:3036 wallet/wallet.c:3072 msgid "INSERT INTO utxoset ( txid, outnum, blockheight, spendheight, txindex, scriptpubkey, satoshis) VALUES(?, ?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:3085 +#: wallet/wallet.c:3096 msgid "SELECT height FROM blocks WHERE height = ?" msgstr "" -#: wallet/wallet.c:3098 +#: wallet/wallet.c:3109 msgid "SELECT txid, spendheight, scriptpubkey, satoshis FROM utxoset WHERE blockheight = ? AND txindex = ? AND outnum = ? AND spendheight IS NULL" msgstr "" -#: wallet/wallet.c:3140 +#: wallet/wallet.c:3151 msgid "SELECT blockheight, txindex, outnum FROM utxoset WHERE spendheight = ?" msgstr "" -#: wallet/wallet.c:3171 wallet/wallet.c:3331 +#: wallet/wallet.c:3182 wallet/wallet.c:3342 msgid "SELECT blockheight FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3181 +#: wallet/wallet.c:3192 msgid "INSERT INTO transactions ( id, blockheight, txindex, rawtx) VALUES (?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:3202 +#: wallet/wallet.c:3213 msgid "UPDATE transactions SET blockheight = ?, txindex = ? WHERE id = ?" msgstr "" -#: wallet/wallet.c:3219 +#: wallet/wallet.c:3230 msgid "INSERT INTO transaction_annotations (txid, idx, location, type, channel) VALUES (?, ?, ?, ?, ?) ON CONFLICT(txid,idx) DO NOTHING;" msgstr "" -#: wallet/wallet.c:3251 +#: wallet/wallet.c:3262 msgid "SELECT type, channel_id FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3267 +#: wallet/wallet.c:3278 msgid "UPDATE transactions SET type = ?, channel_id = ? WHERE id = ?" msgstr "" -#: wallet/wallet.c:3286 +#: wallet/wallet.c:3297 msgid "SELECT type FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3309 +#: wallet/wallet.c:3320 msgid "SELECT rawtx FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3355 +#: wallet/wallet.c:3366 msgid "SELECT blockheight, txindex FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3383 +#: wallet/wallet.c:3394 msgid "SELECT id FROM transactions WHERE blockheight=?" msgstr "" -#: wallet/wallet.c:3402 +#: wallet/wallet.c:3413 msgid "INSERT INTO channeltxs ( channel_id, type, transaction_id, input_num, blockheight) VALUES (?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:3426 +#: wallet/wallet.c:3437 msgid "SELECT DISTINCT(channel_id) FROM channeltxs WHERE type = ?;" msgstr "" -#: wallet/wallet.c:3447 +#: wallet/wallet.c:3458 msgid "SELECT c.type, c.blockheight, t.rawtx, c.input_num, c.blockheight - t.blockheight + 1 AS depth, t.id as txid FROM channeltxs c JOIN transactions t ON t.id = c.transaction_id WHERE c.channel_id = ? ORDER BY c.id ASC;" msgstr "" -#: wallet/wallet.c:3492 +#: wallet/wallet.c:3503 msgid "UPDATE forwarded_payments SET in_msatoshi=?, out_msatoshi=?, state=?, resolved_time=?, failcode=? WHERE in_htlc_id=?" msgstr "" -#: wallet/wallet.c:3550 +#: wallet/wallet.c:3561 msgid "INSERT INTO forwarded_payments ( in_htlc_id, out_htlc_id, in_channel_scid, out_channel_scid, in_msatoshi, out_msatoshi, state, received_time, resolved_time, failcode) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:3609 +#: wallet/wallet.c:3620 msgid "SELECT CAST(COALESCE(SUM(in_msatoshi - out_msatoshi), 0) AS BIGINT)FROM forwarded_payments WHERE state = ?;" msgstr "" -#: wallet/wallet.c:3633 +#: wallet/wallet.c:3644 msgid "SELECT f.state, in_msatoshi, out_msatoshi, hin.payment_hash as payment_hash, in_channel_scid, out_channel_scid, f.received_time, f.resolved_time, f.failcode FROM forwarded_payments f LEFT JOIN channel_htlcs hin ON (f.in_htlc_id = hin.id)" msgstr "" -#: wallet/wallet.c:3721 +#: wallet/wallet.c:3732 msgid "SELECT t.id, t.rawtx, t.blockheight, t.txindex, t.type as txtype, c2.short_channel_id as txchan, a.location, a.idx as ann_idx, a.type as annotation_type, c.short_channel_id FROM transactions t LEFT JOIN transaction_annotations a ON (a.txid = t.id) LEFT JOIN channels c ON (a.channel = c.id) LEFT JOIN channels c2 ON (t.channel_id = c2.id) ORDER BY t.blockheight, t.txindex ASC" msgstr "" -#: wallet/wallet.c:3815 +#: wallet/wallet.c:3826 msgid "INSERT INTO penalty_bases ( channel_id, commitnum, txid, outnum, amount) VALUES (?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:3840 +#: wallet/wallet.c:3851 msgid "SELECT commitnum, txid, outnum, amount FROM penalty_bases WHERE channel_id = ?" msgstr "" -#: wallet/wallet.c:3864 +#: wallet/wallet.c:3875 msgid "DELETE FROM penalty_bases WHERE channel_id = ? AND commitnum = ?" msgstr "" @@ -1085,4 +1089,4 @@ msgstr "" #: wallet/test/run-wallet.c:1359 msgid "INSERT INTO channels (id) VALUES (1);" msgstr "" -# SHA256STAMP:108fcc46e6fa6e190b27773161a9c6bf9a83cb25e9d3164fa40e9de9e6f98644 +# SHA256STAMP:57b5cf2dddb562f248adabe071280e2a0f13075334451d6a91ba7d98f663b255 diff --git a/wallet/wallet.c b/wallet/wallet.c index 8c541e25a..e95c4f59e 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -2448,7 +2448,7 @@ void wallet_payment_store(struct wallet *wallet, if (payment->bolt11 != NULL) db_bind_text(stmt, 10, payment->bolt11); else - db_bind_null(stmt, 10); + db_bind_null(stmt, 10); db_bind_amount_msat(stmt, 11, &payment->total_msat); db_bind_u64(stmt, 12, payment->partid); @@ -2489,6 +2489,17 @@ void wallet_payment_delete(struct wallet *wallet, db_exec_prepared_v2(take(stmt)); } +void wallet_payment_delete_by_hash(struct wallet *wallet, + const struct sha256 *payment_hash) +{ + struct db_stmt *stmt; + stmt = db_prepare_v2( + wallet->db, SQL("DELETE FROM payments WHERE payment_hash = ?")); + + db_bind_sha256(stmt, 0, payment_hash); + db_exec_prepared_v2(take(stmt)); +} + static struct wallet_payment *wallet_stmt2payment(const tal_t *ctx, struct db_stmt *stmt) { diff --git a/wallet/wallet.h b/wallet/wallet.h index dc7f58cd1..033dc14a1 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -967,6 +967,15 @@ void wallet_payment_delete(struct wallet *wallet, const struct sha256 *payment_hash, u64 partid); +/** + * wallet_payment_delete_by_hash - Remove a payment + * + * Removes the payment from the database by hash; if it is a MPP payment + * it remove all parts with a single query. + */ +void wallet_payment_delete_by_hash(struct wallet *wallet, + const struct sha256 *payment_hash); + /** * wallet_local_htlc_out_delete - Remove a local outgoing failed HTLC *