mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-04 03:03:51 +01:00
wallet: simplify payments lookup so sqlite3 uses index.
Filtering by status is rare, so we can do it in the caller; just let sqlite3 filter by payment_hash. With ~650,000 payments in db: Before: ``` 129/300000 complete 5.60/sec (33078 invs, 169 pays, 0 retries) in 30 seconds. 19 hours-14 hours remaining. 201/300000 complete 7.20/sec (43519 invs, 241 pays, 0 retries) in 40 seconds. 16 hours-11 hours remaining. 257/300000 complete 5.60/sec (54568 invs, 289 pays, 0 retries) in 50 seconds. 16 hours-14 hours remaining. 305/300000 complete 4.80/sec (65772 invs, 337 pays, 0 retries) in 60 seconds. 16 hours-17 hours remaining. 361/300000 complete 5.60/sec (75875 invs, 401 pays, 0 retries) in 70 seconds. 16 hours-14 hours remaining. ``` After: ``` 760/300000 complete 40.00/sec (19955 invs, 824 pays, 0 retries) in 20 seconds. 2 hours-2 hours remaining. 1176/300000 complete 41.60/sec (30082 invs, 1224 pays, 0 retries) in 30 seconds. 2 hours-119 minutes remaining. 1584/300000 complete 40.80/sec (40224 invs, 1640 pays, 0 retries) in 40 seconds. 2 hours-2 hours remaining. 1984/300000 complete 40.00/sec (49938 invs, 2048 pays, 0 retries) in 50 seconds. 2 hours-2 hours remaining. ``` Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
2a5660b3bc
commit
2022e4a7a9
4 changed files with 91 additions and 72 deletions
|
@ -285,7 +285,7 @@ static struct command_result *prev_payment(struct command *cmd,
|
|||
bool prev_paid = false;
|
||||
|
||||
assert(!invreq->payer_info);
|
||||
payments = wallet_payment_list(cmd, cmd->ld->wallet, NULL, NULL);
|
||||
payments = wallet_payment_list(cmd, cmd->ld->wallet, NULL);
|
||||
|
||||
for (size_t i = 0; i < tal_count(payments); i++) {
|
||||
const struct tlv_invoice *inv;
|
||||
|
|
|
@ -37,15 +37,16 @@ struct sendpay_command {
|
|||
struct command *cmd;
|
||||
};
|
||||
|
||||
static bool string_to_payment_status(const char *status_str, enum wallet_payment_status *status)
|
||||
static bool string_to_payment_status(const char *status_str, size_t len,
|
||||
enum wallet_payment_status *status)
|
||||
{
|
||||
if (streq(status_str, "complete")) {
|
||||
if (memeqstr(status_str, len, "complete")) {
|
||||
*status = PAYMENT_COMPLETE;
|
||||
return true;
|
||||
} else if (streq(status_str, "pending")) {
|
||||
} else if (memeqstr(status_str, len, "pending")) {
|
||||
*status = PAYMENT_PENDING;
|
||||
return true;
|
||||
} else if (streq(status_str, "failed")) {
|
||||
} else if (memeqstr(status_str, len, "failed")) {
|
||||
*status = PAYMENT_FAILED;
|
||||
return true;
|
||||
}
|
||||
|
@ -883,7 +884,7 @@ send_payment_core(struct lightningd *ld,
|
|||
bool have_complete = false;
|
||||
|
||||
/* Now, do we already have one or more payments? */
|
||||
payments = wallet_payment_list(tmpctx, ld->wallet, rhash, NULL);
|
||||
payments = wallet_payment_list(tmpctx, ld->wallet, rhash);
|
||||
for (size_t i = 0; i < tal_count(payments); i++) {
|
||||
log_debug(ld->log, "Payment %zu/%zu: %s %s",
|
||||
i, tal_count(payments),
|
||||
|
@ -1545,6 +1546,22 @@ static const struct json_command waitsendpay_command = {
|
|||
};
|
||||
AUTODATA(json_command, &waitsendpay_command);
|
||||
|
||||
static struct command_result *param_payment_status(struct command *cmd,
|
||||
const char *name,
|
||||
const char *buffer,
|
||||
const jsmntok_t *tok,
|
||||
enum wallet_payment_status **status)
|
||||
{
|
||||
*status = tal(cmd, enum wallet_payment_status);
|
||||
if (string_to_payment_status(buffer + tok->start,
|
||||
tok->end - tok->start,
|
||||
*status))
|
||||
return NULL;
|
||||
|
||||
return command_fail_badparam(cmd, name, buffer, tok,
|
||||
"should be an invoice status");
|
||||
}
|
||||
|
||||
static struct command_result *json_listsendpays(struct command *cmd,
|
||||
const char *buffer,
|
||||
const jsmntok_t *obj UNNEEDED,
|
||||
|
@ -1553,13 +1570,14 @@ static struct command_result *json_listsendpays(struct command *cmd,
|
|||
const struct wallet_payment **payments;
|
||||
struct json_stream *response;
|
||||
struct sha256 *rhash;
|
||||
const char *invstring, *status_str;
|
||||
const char *invstring;
|
||||
enum wallet_payment_status *status;
|
||||
|
||||
if (!param(cmd, buffer, params,
|
||||
/* FIXME: parameter should be invstring now */
|
||||
p_opt("bolt11", param_string, &invstring),
|
||||
p_opt("payment_hash", param_sha256, &rhash),
|
||||
p_opt("status", param_string, &status_str),
|
||||
p_opt("status", param_payment_status, &status),
|
||||
NULL))
|
||||
return command_param_failed();
|
||||
|
||||
|
@ -1591,19 +1609,13 @@ static struct command_result *json_listsendpays(struct command *cmd,
|
|||
}
|
||||
}
|
||||
|
||||
if (status_str) {
|
||||
enum wallet_payment_status status;
|
||||
|
||||
if (!string_to_payment_status(status_str, &status))
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "Unrecognized status: %s", status_str);
|
||||
payments = wallet_payment_list(cmd, cmd->ld->wallet, rhash, &status);
|
||||
} else
|
||||
payments = wallet_payment_list(cmd, cmd->ld->wallet, rhash, NULL);
|
||||
|
||||
payments = wallet_payment_list(cmd, cmd->ld->wallet, rhash);
|
||||
response = json_stream_success(cmd);
|
||||
|
||||
json_array_start(response, "payments");
|
||||
for (size_t i = 0; i < tal_count(payments); i++) {
|
||||
if (status && payments[i]->status != *status)
|
||||
continue;
|
||||
json_object_start(response, NULL);
|
||||
json_add_payment_fields(response, payments[i]);
|
||||
json_object_end(response);
|
||||
|
@ -1629,40 +1641,36 @@ static struct command_result *json_delpay(struct command *cmd,
|
|||
{
|
||||
struct json_stream *response;
|
||||
const struct wallet_payment **payments;
|
||||
const char *status_str;
|
||||
enum wallet_payment_status status;
|
||||
enum wallet_payment_status *status;
|
||||
struct sha256 *payment_hash;
|
||||
|
||||
if (!param(cmd, buffer, params,
|
||||
p_req("payment_hash", param_sha256, &payment_hash),
|
||||
p_req("status", param_string, &status_str),
|
||||
p_req("status", param_payment_status, &status),
|
||||
NULL))
|
||||
return command_param_failed();
|
||||
|
||||
if (!string_to_payment_status(status_str, &status))
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "Unrecognized status: %s", status_str);
|
||||
|
||||
switch(status){
|
||||
switch (*status) {
|
||||
case PAYMENT_COMPLETE:
|
||||
case PAYMENT_FAILED:
|
||||
break;
|
||||
case PAYMENT_PENDING:
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "Invalid status: %s",
|
||||
payment_status_to_string(status));
|
||||
payment_status_to_string(*status));
|
||||
}
|
||||
|
||||
payments = wallet_payment_list(cmd, cmd->ld->wallet, payment_hash, NULL);
|
||||
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) {
|
||||
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));
|
||||
payment_status_to_string(*status));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3518,8 +3518,7 @@ void wallet_payment_set_failinfo(struct wallet *wallet,
|
|||
const struct wallet_payment **
|
||||
wallet_payment_list(const tal_t *ctx,
|
||||
struct wallet *wallet,
|
||||
const struct sha256 *payment_hash,
|
||||
enum wallet_payment_status *status)
|
||||
const struct sha256 *payment_hash)
|
||||
{
|
||||
const struct wallet_payment **payments;
|
||||
struct db_stmt *stmt;
|
||||
|
@ -3528,9 +3527,7 @@ wallet_payment_list(const tal_t *ctx,
|
|||
|
||||
payments = tal_arr(ctx, const struct wallet_payment *, 0);
|
||||
|
||||
u8 enable_payment_hash = payment_hash != NULL ? 0 : 1;
|
||||
u8 enable_status = status != NULL ? 0 : 1;
|
||||
|
||||
if (payment_hash) {
|
||||
stmt = db_prepare_v2(wallet->db, SQL("SELECT"
|
||||
" id"
|
||||
", status"
|
||||
|
@ -3554,21 +3551,34 @@ wallet_payment_list(const tal_t *ctx,
|
|||
", completed_at"
|
||||
" FROM payments"
|
||||
" WHERE"
|
||||
" (payment_hash = ? OR 1=?) AND"
|
||||
" (status = ? OR 1=?)"
|
||||
" payment_hash = ?"
|
||||
" ORDER BY id;"));
|
||||
|
||||
if (payment_hash)
|
||||
db_bind_sha256(stmt, 0, payment_hash);
|
||||
else
|
||||
db_bind_null(stmt, 0);
|
||||
db_bind_int(stmt, 1, enable_payment_hash);
|
||||
if (status)
|
||||
db_bind_int(stmt, 2, wallet_payment_status_in_db(*status));
|
||||
else
|
||||
db_bind_null(stmt, 2);
|
||||
db_bind_int(stmt, 3, enable_status);
|
||||
|
||||
} else {
|
||||
stmt = db_prepare_v2(wallet->db, SQL("SELECT"
|
||||
" id"
|
||||
", status"
|
||||
", destination"
|
||||
", msatoshi"
|
||||
", payment_hash"
|
||||
", timestamp"
|
||||
", payment_preimage"
|
||||
", path_secrets"
|
||||
", route_nodes"
|
||||
", route_channels"
|
||||
", msatoshi_sent"
|
||||
", description"
|
||||
", bolt11"
|
||||
", paydescription"
|
||||
", failonionreply"
|
||||
", total_msat"
|
||||
", partid"
|
||||
", local_offer_id"
|
||||
", groupid"
|
||||
", completed_at"
|
||||
" FROM payments"
|
||||
" ORDER BY id;"));
|
||||
}
|
||||
db_query_prepared(stmt);
|
||||
|
||||
for (i = 0; db_step(stmt); i++) {
|
||||
|
|
|
@ -1183,8 +1183,9 @@ void wallet_payment_set_failinfo(struct wallet *wallet,
|
|||
*/
|
||||
const struct wallet_payment **wallet_payment_list(const tal_t *ctx,
|
||||
struct wallet *wallet,
|
||||
const struct sha256 *payment_hash,
|
||||
enum wallet_payment_status *status);
|
||||
const struct sha256 *payment_hash)
|
||||
NON_NULL_ARGS(2);
|
||||
|
||||
|
||||
/**
|
||||
* wallet_payments_by_offer - Retrieve a list of payments for this local_offer_id
|
||||
|
|
Loading…
Add table
Reference in a new issue