diff --git a/plugins/bkpr/bookkeeper.c b/plugins/bkpr/bookkeeper.c index 77f40ac3c..b3c9354bf 100644 --- a/plugins/bkpr/bookkeeper.c +++ b/plugins/bkpr/bookkeeper.c @@ -219,7 +219,7 @@ getblockheight_done(struct command *cmd, /* Get the income events */ db_begin_transaction(bkpr->db); - apys = compute_channel_apys(cmd, bkpr, + apys = compute_channel_apys(cmd, bkpr, cmd, *req->start_time, *req->end_time, blockheight); @@ -314,7 +314,7 @@ static struct command_result *do_dump_income(struct command *cmd, /* Ok, go find me some income events! */ db_begin_transaction(bkpr->db); - evs = list_income_events(cmd, bkpr, *info->start_time, *info->end_time, + evs = list_income_events(cmd, bkpr, cmd, *info->start_time, *info->end_time, *info->consolidate_fees); db_commit_transaction(bkpr->db); @@ -366,7 +366,7 @@ static struct command_result *do_list_income(struct command *cmd, /* Ok, go find me some income events! */ db_begin_transaction(bkpr->db); - evs = list_income_events(cmd, bkpr, *info->start_time, *info->end_time, + evs = list_income_events(cmd, bkpr, cmd, *info->start_time, *info->end_time, *info->consolidate_fees); db_commit_transaction(bkpr->db); @@ -418,7 +418,7 @@ static struct command_result *do_inspect(struct command *cmd, acct_name); db_begin_transaction(bkpr->db); - find_txo_chain(cmd, bkpr, acct, &txos); + find_txo_chain(cmd, bkpr, cmd, acct, &txos); fee_sums = find_account_onchain_fees(cmd, bkpr, acct); db_commit_transaction(bkpr->db); @@ -625,22 +625,22 @@ static struct command_result *do_account_events(struct command *cmd, db_begin_transaction(bkpr->db); if (acct) { - channel_events = account_get_channel_events(cmd, bkpr->db, acct); - chain_events = account_get_chain_events(cmd, bkpr, acct); + channel_events = account_get_channel_events(cmd, bkpr, cmd, acct); + chain_events = account_get_chain_events(cmd, bkpr, cmd, acct); onchain_fees = account_get_chain_fees(tmpctx, bkpr, acct->name); } else if (info->payment_id != NULL) { - channel_events = get_channel_events_by_id(cmd, bkpr->db, info->payment_id); + channel_events = get_channel_events_by_id(cmd, bkpr, cmd, info->payment_id); tx_id = tal(cmd, struct bitcoin_txid); tx_id->shad.sha = *info->payment_id; /* Transaction ids are stored as big-endian in the database */ reverse_bytes(tx_id->shad.sha.u.u8, sizeof(tx_id->shad.sha.u.u8)); - chain_events = find_chain_events_bytxid(cmd, bkpr, tx_id); + chain_events = find_chain_events_bytxid(cmd, bkpr, cmd, tx_id); onchain_fees = get_chain_fees_by_txid(cmd, bkpr, tx_id); } else { - channel_events = list_channel_events(cmd, bkpr->db); - chain_events = list_chain_events(cmd, bkpr); + channel_events = list_channel_events(cmd, bkpr, cmd); + chain_events = list_chain_events(cmd, bkpr, cmd); onchain_fees = list_chain_fees(cmd, bkpr); } db_commit_transaction(bkpr->db); @@ -682,7 +682,7 @@ static struct command_result *do_edit_desc(struct command *cmd, db_begin_transaction(bkpr->db); add_utxo_description(cmd, bkpr, info->outpoint, info->new_desc); - chain_events = get_chain_events_by_outpoint(cmd, bkpr, info->outpoint, true); + chain_events = get_chain_events_by_outpoint(cmd, bkpr, cmd, info->outpoint); db_commit_transaction(bkpr->db); res = jsonrpc_stream_success(cmd); @@ -724,8 +724,8 @@ static struct command_result *do_edit_desc_payment(struct command *cmd, db_begin_transaction(bkpr->db); add_payment_hash_description(cmd, bkpr, info->identifier, info->new_desc); - chain_events = get_chain_events_by_id(cmd, bkpr, info->identifier); - channel_events = get_channel_events_by_id(cmd, bkpr->db, info->identifier); + chain_events = get_chain_events_by_id(cmd, bkpr, cmd, info->identifier); + channel_events = get_channel_events_by_id(cmd, bkpr, cmd, info->identifier); db_commit_transaction(bkpr->db); res = jsonrpc_stream_success(cmd); @@ -768,7 +768,7 @@ static struct command_result *do_list_balances(struct command *cmd, struct amount_msat credit, debit, balance; bool has_events; - has_events = account_get_credit_debit(cmd->plugin, bkpr->db, + has_events = account_get_credit_debit(bkpr, cmd, accts[i]->name, &credit, &debit); if (!amount_msat_sub(&balance, credit, debit)) { @@ -845,7 +845,7 @@ static void try_update_open_fees(struct command *cmd, struct bkpr *bkpr = bkpr_of(cmd->plugin); assert(acct->closed_event_db_id); - ev = find_chain_event_by_id(cmd, bkpr, *acct->closed_event_db_id); + ev = find_chain_event_by_id(cmd, bkpr, cmd, *acct->closed_event_db_id); assert(ev); err = maybe_update_onchain_fees(cmd, cmd, bkpr, ev->spending_txid); @@ -1163,7 +1163,7 @@ static char *do_account_close_checks(struct command *cmd, } else if (!is_channel_account(acct->name) && !e->spending_txid) { const char *acctname; - acctname = find_close_account_name(tmpctx, bkpr->db, &e->outpoint.txid); + acctname = find_close_account_name(tmpctx, bkpr, cmd, &e->outpoint.txid); if (acctname) { closed_acct = find_account(bkpr, acctname); } else { @@ -1175,7 +1175,7 @@ static char *do_account_close_checks(struct command *cmd, if (closed_acct && closed_acct->closed_event_db_id) { - u64 closeheight = account_onchain_closeheight(bkpr, closed_acct); + u64 closeheight = account_onchain_closeheight(bkpr, cmd, closed_acct); if (closeheight != 0) { char *err; account_update_closeheight(cmd, closed_acct, closeheight); @@ -1398,7 +1398,7 @@ listpeerchannels_done(struct command *cmd, info->acct, info->ev->timestamp)) { db_begin_transaction(bkpr->db); - account_get_credit_debit(cmd->plugin, bkpr->db, info->acct->name, + account_get_credit_debit(bkpr, cmd, info->acct->name, &credit, &debit); db_commit_transaction(bkpr->db); diff --git a/plugins/bkpr/channelsapy.c b/plugins/bkpr/channelsapy.c index cc311c48e..ed7f85b90 100644 --- a/plugins/bkpr/channelsapy.c +++ b/plugins/bkpr/channelsapy.c @@ -97,6 +97,7 @@ static struct account *search_account(struct account **accts, const char *acctna } static void fillin_apy_acct_details(const struct bkpr *bkpr, + struct command *cmd, const struct account *acct, u32 current_blockheight, struct channel_apy *apy) @@ -107,7 +108,7 @@ static void fillin_apy_acct_details(const struct bkpr *bkpr, apy->acct_name = tal_strdup(apy, acct->name); assert(acct->open_event_db_id); - ev = find_chain_event_by_id(tmpctx, bkpr, *acct->open_event_db_id); + ev = find_chain_event_by_id(tmpctx, bkpr, cmd, *acct->open_event_db_id); assert(ev); apy->start_blockheight = ev->blockheight; @@ -116,7 +117,7 @@ static void fillin_apy_acct_details(const struct bkpr *bkpr, /* if this account is closed, add closing blockheight */ if (acct->closed_event_db_id) { - ev = find_chain_event_by_id(acct, bkpr, + ev = find_chain_event_by_id(acct, bkpr, cmd, *acct->closed_event_db_id); assert(ev); apy->end_blockheight = ev->blockheight; @@ -140,7 +141,8 @@ static void fillin_apy_acct_details(const struct bkpr *bkpr, } struct channel_apy **compute_channel_apys(const tal_t *ctx, - struct bkpr *bkpr, + const struct bkpr *bkpr, + struct command *cmd, u64 start_time, u64 end_time, u32 current_blockheight) @@ -149,7 +151,7 @@ struct channel_apy **compute_channel_apys(const tal_t *ctx, struct channel_apy *apy, **apys; struct account *acct, **accts; - evs = list_channel_events_timebox(ctx, bkpr->db, start_time, end_time); + evs = list_channel_events_timebox(ctx, bkpr, cmd, start_time, end_time); accts = list_accounts(ctx, bkpr); apys = tal_arr(ctx, struct channel_apy *, 0); @@ -167,7 +169,7 @@ struct channel_apy **compute_channel_apys(const tal_t *ctx, if (!acct || !streq(acct->name, ev->acct_name)) { if (acct && is_channel_account(acct->name)) { - fillin_apy_acct_details(bkpr, acct, + fillin_apy_acct_details(bkpr, cmd, acct, current_blockheight, apy); /* Save current apy, make new */ @@ -225,7 +227,7 @@ struct channel_apy **compute_channel_apys(const tal_t *ctx, } if (acct && is_channel_account(acct->name)) { - fillin_apy_acct_details(bkpr, acct, + fillin_apy_acct_details(bkpr, cmd, acct, current_blockheight, apy); /* Save current apy, make new */ diff --git a/plugins/bkpr/channelsapy.h b/plugins/bkpr/channelsapy.h index 73cacaeeb..6a63d4e07 100644 --- a/plugins/bkpr/channelsapy.h +++ b/plugins/bkpr/channelsapy.h @@ -34,7 +34,8 @@ WARN_UNUSED_RESULT bool channel_apy_sum(struct channel_apy *sum_apy, const struct channel_apy *entry); struct channel_apy **compute_channel_apys(const tal_t *ctx, - struct bkpr *bkpr, + const struct bkpr *bkpr, + struct command *cmd, u64 start_time, u64 end_time, u32 current_blockheight); diff --git a/plugins/bkpr/incomestmt.c b/plugins/bkpr/incomestmt.c index eac90f969..fd3a7e452 100644 --- a/plugins/bkpr/incomestmt.c +++ b/plugins/bkpr/incomestmt.c @@ -1,14 +1,12 @@ #include "config.h" +#include #include #include +#include #include #include #include #include -#include -#include -#include -#include #include #include #include @@ -20,6 +18,7 @@ #include #include #include +#include #include #define ONCHAIN_FEE "onchain_fee" @@ -111,6 +110,7 @@ static char *csv_safe_str(const tal_t *ctx, const char *input TAKES) static struct income_event *maybe_chain_income(const tal_t *ctx, const struct bkpr *bkpr, + struct command *cmd, struct account *acct, struct chain_event *ev) { @@ -141,7 +141,8 @@ static struct income_event *maybe_chain_income(const tal_t *ctx, /* income */ if (streq(ev->tag, "deposit")) { - struct db_stmt *stmt; + const jsmntok_t *toks; + const char *buf; /* deposit to external is cost to us */ if (is_external_account(ev->acct_name)) { @@ -168,16 +169,16 @@ static struct income_event *maybe_chain_income(const tal_t *ctx, * into a tx that included funds from a 3rd party * coming to us... eg. a splice out from the peer * to our onchain wallet */ - stmt = db_prepare_v2(bkpr->db, SQL("SELECT" - " 1" - " FROM chain_events e" - " WHERE " - " e.spending_txid = ?")); - - db_bind_txid(stmt, &ev->outpoint.txid); - db_query_prepared(stmt); - if (!db_step(stmt)) { - tal_free(stmt); + toks = sql_req(tmpctx, cmd, &buf, + "SELECT" + " 1" + " FROM chainmoves" + " WHERE " + " spending_txid = X'%s'" + " AND created_index <= %"PRIu64, + fmt_bitcoin_txid(tmpctx, &ev->outpoint.txid), + bkpr->chainmoves_index); + if (json_get_member(buf, toks, "rows")->size == 0) { /* no matching withdrawal from internal, * so must be new deposit (external) */ return chain_to_income(ctx, bkpr, ev, @@ -185,9 +186,6 @@ static struct income_event *maybe_chain_income(const tal_t *ctx, ev->credit, ev->debit); } - - db_col_ignore(stmt, "1"); - tal_free(stmt); return NULL; } @@ -306,6 +304,7 @@ static struct onchain_fee **find_consolidated_fees(const tal_t *ctx, struct income_event **list_income_events(const tal_t *ctx, const struct bkpr *bkpr, + struct command *cmd, u64 start_time, u64 end_time, bool consolidate_fees) @@ -315,9 +314,9 @@ struct income_event **list_income_events(const tal_t *ctx, struct onchain_fee **onchain_fees; struct income_event **evs; - channel_events = list_channel_events_timebox(ctx, bkpr->db, + channel_events = list_channel_events_timebox(ctx, bkpr, cmd, start_time, end_time); - chain_events = list_chain_events_timebox(ctx, bkpr, start_time, end_time); + chain_events = list_chain_events_timebox(ctx, bkpr, cmd, start_time, end_time); if (consolidate_fees) { onchain_fees = find_consolidated_fees(ctx, bkpr, @@ -369,7 +368,7 @@ struct income_event **list_income_events(const tal_t *ctx, struct account *acct = find_account(bkpr, chain->acct_name); - ev = maybe_chain_income(evs, bkpr, acct, chain); + ev = maybe_chain_income(evs, bkpr, cmd, acct, chain); if (ev) tal_arr_expand(&evs, ev); i++; @@ -407,9 +406,10 @@ struct income_event **list_income_events(const tal_t *ctx, struct income_event **list_income_events_all(const tal_t *ctx, const struct bkpr *bkpr, + struct command *cmd, bool consolidate_fees) { - return list_income_events(ctx, bkpr, 0, SQLITE_MAX_UINT, + return list_income_events(ctx, bkpr, cmd, 0, SQLITE_MAX_UINT, consolidate_fees); } diff --git a/plugins/bkpr/incomestmt.h b/plugins/bkpr/incomestmt.h index a6c813aa0..0de3c00dc 100644 --- a/plugins/bkpr/incomestmt.h +++ b/plugins/bkpr/incomestmt.h @@ -31,12 +31,14 @@ struct csv_fmt { /* List all the events that are income related (gain/loss) */ struct income_event **list_income_events_all(const tal_t *ctx, const struct bkpr *bkpr, + struct command *cmd, bool consolidate_fees); /* List all the events that are income related (gain/loss), * by a start and end date */ struct income_event **list_income_events(const tal_t *ctx, const struct bkpr *bkpr, + struct command *cmd, u64 start_time, u64 end_time, bool consolidate_fees); diff --git a/plugins/bkpr/onchain_fee.c b/plugins/bkpr/onchain_fee.c index 3f4e9dc04..4af85e259 100644 --- a/plugins/bkpr/onchain_fee.c +++ b/plugins/bkpr/onchain_fee.c @@ -397,9 +397,9 @@ char *update_channel_onchain_fees(const tal_t *ctx, struct amount_msat onchain_amt; assert(acct->onchain_resolved_block); - close_ev = find_chain_event_by_id(ctx, bkpr, + close_ev = find_chain_event_by_id(ctx, bkpr, cmd, *acct->closed_event_db_id); - events = find_chain_events_bytxid(ctx, bkpr, + events = find_chain_events_bytxid(ctx, bkpr, cmd, close_ev->spending_txid); /* Starting balance is close-ev's debit amount */ @@ -453,6 +453,7 @@ char *update_channel_onchain_fees(const tal_t *ctx, static char *is_closed_channel_txid(const tal_t *ctx, struct bkpr *bkpr, + struct command *cmd, struct chain_event *ev, struct bitcoin_txid *txid, bool *is_channel_close_tx) @@ -475,7 +476,7 @@ static char *is_closed_channel_txid(const tal_t *ctx, /* is the closed utxo the same as the one * we're trying to find fees for now */ - closed = find_chain_event_by_id(inner_ctx, bkpr, + closed = find_chain_event_by_id(inner_ctx, bkpr, cmd, *acct->closed_event_db_id); if (!closed) { *is_channel_close_tx = false; @@ -516,7 +517,7 @@ char *maybe_update_onchain_fees(const tal_t *ctx, u8 *inner_ctx = tal(NULL, u8); /* Find all the deposits/withdrawals for this txid */ - events = find_chain_events_bytxid(inner_ctx, bkpr, txid); + events = find_chain_events_bytxid(inner_ctx, bkpr, cmd, txid); /* If we don't even have two events, skip */ if (tal_count(events) < 2) @@ -524,7 +525,7 @@ char *maybe_update_onchain_fees(const tal_t *ctx, for (size_t i = 0; i < tal_count(events); i++) { bool is_channel_close_tx; - err = is_closed_channel_txid(ctx, bkpr, + err = is_closed_channel_txid(ctx, bkpr, cmd, events[i], txid, &is_channel_close_tx); diff --git a/plugins/bkpr/recorder.c b/plugins/bkpr/recorder.c index 08fda0f19..2e84bedd2 100644 --- a/plugins/bkpr/recorder.c +++ b/plugins/bkpr/recorder.c @@ -18,220 +18,62 @@ #include #include #include +#include #include - -static struct chain_event *stmt2chain_event(const tal_t *ctx, - const struct bkpr *bkpr, - struct db_stmt *stmt) -{ - struct chain_event *e = tal(ctx, struct chain_event); - e->db_id = db_col_u64(stmt, "e.id"); - e->acct_name = db_col_strdup(e, stmt, "e.account_name"); - - if (!db_col_is_null(stmt, "e.origin")) - e->origin_acct = db_col_strdup(e, stmt, "e.origin"); - else - e->origin_acct = NULL; - - e->tag = db_col_strdup(e, stmt, "e.tag"); - - e->credit = db_col_amount_msat(stmt, "e.credit"); - e->debit = db_col_amount_msat(stmt, "e.debit"); - e->output_value = db_col_amount_msat(stmt, "e.output_value"); - - e->timestamp = db_col_u64(stmt, "e.timestamp"); - e->blockheight = db_col_int(stmt, "e.blockheight"); - - db_col_txid(stmt, "e.utxo_txid", &e->outpoint.txid); - e->outpoint.n = db_col_int(stmt, "e.outnum"); - - if (e->blockheight == 0) - e->blockheight = find_blockheight(bkpr, &e->outpoint.txid); - - if (!db_col_is_null(stmt, "e.payment_id")) { - e->payment_id = tal(e, struct sha256); - db_col_sha256(stmt, "e.payment_id", e->payment_id); - } else - e->payment_id = NULL; - - if (!db_col_is_null(stmt, "e.spending_txid")) { - e->spending_txid = tal(e, struct bitcoin_txid); - db_col_txid(stmt, "e.spending_txid", e->spending_txid); - } else - e->spending_txid = NULL; - - e->stealable = db_col_int(stmt, "e.stealable") == 1; - e->splice_close = db_col_int(stmt, "e.spliced") == 1; - - return e; -} - -static struct chain_event **find_chain_events(const tal_t *ctx, - const struct bkpr *bkpr, - struct db_stmt *stmt TAKES) -{ - struct chain_event **results; - - db_query_prepared(stmt); - if (stmt->error) - db_fatal(stmt->db, "find_chain_events err: %s", stmt->error); - results = tal_arr(ctx, struct chain_event *, 0); - while (db_step(stmt)) { - struct chain_event *e = stmt2chain_event(results, bkpr, stmt); - tal_arr_expand(&results, e); - } - - if (taken(stmt)) - tal_free(stmt); - - return results; -} - -static struct channel_event *stmt2channel_event(const tal_t *ctx, struct db_stmt *stmt) -{ - struct channel_event *e = tal(ctx, struct channel_event); - - e->db_id = db_col_u64(stmt, "e.id"); - e->acct_name = db_col_strdup(e, stmt, "e.account_name"); - - e->tag = db_col_strdup(e, stmt, "e.tag"); - - e->credit = db_col_amount_msat(stmt, "e.credit"); - e->debit = db_col_amount_msat(stmt, "e.debit"); - e->fees = db_col_amount_msat(stmt, "e.fees"); - - if (!db_col_is_null(stmt, "e.payment_id")) { - e->payment_id = tal(e, struct sha256); - db_col_sha256(stmt, "e.payment_id", e->payment_id); - } else - e->payment_id = NULL; - e->part_id = db_col_int(stmt, "e.part_id"); - e->timestamp = db_col_u64(stmt, "e.timestamp"); - - return e; -} - -static struct channel_event **find_channel_events(const tal_t *ctx, - struct db_stmt *stmt TAKES) -{ - struct channel_event **results; - - db_query_prepared(stmt); - if (stmt->error) - db_fatal(stmt->db, "find_channel_events err: %s", stmt->error); - results = tal_arr(ctx, struct channel_event *, 0); - while (db_step(stmt)) { - struct channel_event *e = stmt2channel_event(results, stmt); - tal_arr_expand(&results, e); - } - - if (taken(stmt)) - tal_free(stmt); - - return results; -} - struct chain_event **list_chain_events_timebox(const tal_t *ctx, const struct bkpr *bkpr, + struct command *cmd, u64 start_time, u64 end_time) { - struct db_stmt *stmt; - - stmt = db_prepare_v2(bkpr->db, SQL("SELECT" - " e.id" - ", e.account_name" - ", e.origin" - ", e.tag" - ", e.credit" - ", e.debit" - ", e.output_value" - ", e.timestamp" - ", e.blockheight" - ", e.utxo_txid" - ", e.outnum" - ", e.spending_txid" - ", e.payment_id" - ", e.stealable" - ", e.spliced" - " FROM chain_events e" - " WHERE e.timestamp > ?" - " AND e.timestamp <= ?" - " ORDER BY e.timestamp, e.id;")); - - db_bind_u64(stmt, start_time); - db_bind_u64(stmt, end_time); - return find_chain_events(ctx, bkpr, take(stmt)); + return chain_events_from_sql(ctx, bkpr, cmd, + SELECT_CHAIN_EVENTS + " WHERE timestamp > %"PRIu64 + " AND timestamp <= %"PRIu64 + " AND created_index <= %"PRIu64 + " ORDER BY timestamp, created_index;", + start_time, end_time, + bkpr->chainmoves_index); } -struct chain_event **list_chain_events(const tal_t *ctx, const struct bkpr *bkpr) +struct chain_event **list_chain_events(const tal_t *ctx, + const struct bkpr *bkpr, + struct command *cmd) { - return list_chain_events_timebox(ctx, bkpr, 0, SQLITE_MAX_UINT); + return list_chain_events_timebox(ctx, bkpr, cmd, 0, SQLITE_MAX_UINT); } struct chain_event **account_get_chain_events(const tal_t *ctx, const struct bkpr *bkpr, + struct command *cmd, struct account *acct) { - struct db_stmt *stmt; - - stmt = db_prepare_v2(bkpr->db, SQL("SELECT" - " e.id" - ", e.account_name" - ", e.origin" - ", e.tag" - ", e.credit" - ", e.debit" - ", e.output_value" - ", e.timestamp" - ", e.blockheight" - ", e.utxo_txid" - ", e.outnum" - ", e.spending_txid" - ", e.payment_id" - ", e.stealable" - ", e.spliced" - " FROM chain_events e" - " WHERE e.account_name = ?" - " ORDER BY e.timestamp, e.id")); - - db_bind_text(stmt, acct->name); - return find_chain_events(ctx, bkpr, take(stmt)); + return chain_events_from_sql(ctx, bkpr, cmd, + SELECT_CHAIN_EVENTS + " WHERE account_id = '%s'" + " AND created_index <= %"PRIu64 + " ORDER BY timestamp, created_index;", + sql_string(tmpctx, acct->name), + bkpr->chainmoves_index); } static struct chain_event **find_txos_for_tx(const tal_t *ctx, const struct bkpr *bkpr, - struct bitcoin_txid *txid) + struct command *cmd, + const struct bitcoin_txid *txid) { - struct db_stmt *stmt; - - stmt = db_prepare_v2(bkpr->db, SQL("SELECT" - " e.id" - ", e.account_name" - ", e.origin" - ", e.tag" - ", e.credit" - ", e.debit" - ", e.output_value" - ", e.timestamp" - ", e.blockheight" - ", e.utxo_txid" - ", e.outnum" - ", e.spending_txid" - ", e.payment_id" - ", e.stealable" - ", e.spliced" - " FROM chain_events e" - " WHERE e.utxo_txid = ?" + return chain_events_from_sql(ctx, bkpr, cmd, + SELECT_CHAIN_EVENTS + /* utxo is txid:outnum */ + " WHERE utxo LIKE '%s:%%'" + " AND created_index <= %"PRIu64 " ORDER BY " - " e.utxo_txid" - ", e.outnum" - ", e.spending_txid NULLS FIRST" - ", e.blockheight")); - - db_bind_txid(stmt, txid); - return find_chain_events(ctx, bkpr, take(stmt)); + " utxo" + ", spending_txid NULLS FIRST" + ", blockheight", + fmt_bitcoin_txid(tmpctx, txid), + bkpr->chainmoves_index); } static struct txo_pair *new_txo_pair(const tal_t *ctx) @@ -244,7 +86,8 @@ static struct txo_pair *new_txo_pair(const tal_t *ctx) static struct txo_set *find_txo_set(const tal_t *ctx, const struct bkpr *bkpr, - struct bitcoin_txid *txid, + struct command *cmd, + const struct bitcoin_txid *txid, const char *acct_name, bool *is_complete) { @@ -255,7 +98,7 @@ static struct txo_set *find_txo_set(const tal_t *ctx, /* In some special cases (the opening tx), we only * want the outputs that pertain to a given account, * most other times we want all utxos, regardless of account */ - evs = find_txos_for_tx(ctx, bkpr, txid); + evs = find_txos_for_tx(ctx, bkpr, cmd, txid); txos->pairs = tal_arr(txos, struct txo_pair *, 0); txos->txid = tal_dup(txos, struct bitcoin_txid, txid); @@ -323,6 +166,7 @@ static bool txid_in_list(struct bitcoin_txid **list, bool find_txo_chain(const tal_t *ctx, const struct bkpr *bkpr, + struct command *cmd, const struct account *acct, struct txo_set ***sets) { @@ -332,7 +176,7 @@ bool find_txo_chain(const tal_t *ctx, const char *start_acct_name; assert(acct->open_event_db_id); - open_ev = find_chain_event_by_id(ctx, bkpr, + open_ev = find_chain_event_by_id(ctx, bkpr, cmd, *acct->open_event_db_id); if (sets) @@ -349,7 +193,7 @@ bool find_txo_chain(const tal_t *ctx, struct txo_set *set; bool set_complete; - set = find_txo_set(ctx, bkpr, txids[i], + set = find_txo_set(ctx, bkpr, cmd, txids[i], start_acct_name, &set_complete); @@ -392,55 +236,69 @@ bool find_txo_chain(const tal_t *ctx, } const char *find_close_account_name(const tal_t *ctx, - struct db *db, + const struct bkpr *bkpr, + struct command *cmd, const struct bitcoin_txid *txid) { - struct db_stmt *stmt; - char *acct_name; + const char *buf; + const jsmntok_t *result, *rows, *row; + size_t i; + const char *acct_name = NULL; - stmt = db_prepare_v2(db, SQL("SELECT" - " e.account_name" - " FROM chain_events e" - " WHERE " - " e.tag = ?" - " AND e.spending_txid = ?" - /* ignore splicing 'close' events */ - " AND e.spliced = 0 ")); + /* We look for a CHANNEL_CLOSE spend, but ignore “spliced” close events. */ + result = sql_req(ctx, cmd, &buf, + "SELECT account_id" + " FROM chainmoves cm" + " WHERE cm.primary_tag = '%s'" + " AND cm.spending_txid = X'%s'" + " AND NOT EXISTS (" + " SELECT 1 FROM chainmoves_extra_tags et" + " WHERE et.row = cm.created_index" + " AND et.extra_tags = 'spliced'" + " )" + " AND" + " cm.created_index <= %"PRIu64 + " LIMIT 1", + sql_string(tmpctx, mvt_tag_str(MVT_CHANNEL_CLOSE)), + fmt_bitcoin_txid(tmpctx, txid), + bkpr->chainmoves_index); - db_bind_text(stmt, mvt_tag_str(MVT_CHANNEL_CLOSE)); - db_bind_txid(stmt, txid); - db_query_prepared(stmt); + rows = json_get_member(buf, result, "rows"); + json_for_each_arr(i, row, rows) { + /* Single column => row->size == 1; first value token is row+1 */ + const jsmntok_t *val = row + 1; + acct_name = json_strdup(ctx, buf, val); + break; /* only need the first row */ + } - if (db_step(stmt)) { - acct_name = db_col_strdup(ctx, stmt, "e.account_name"); - } else - acct_name = NULL; - - tal_free(stmt); - return acct_name; + return acct_name; /* NULL if none found */ } -u64 account_onchain_closeheight(const struct bkpr *bkpr, const struct account *acct) +u64 account_onchain_closeheight(const struct bkpr *bkpr, + struct command *cmd, + const struct account *acct) { const u8 *ctx = tal(NULL, u8); struct txo_set **sets; struct chain_event *close_ev; - struct db_stmt *stmt; u64 height; assert(acct->closed_count > 0); - close_ev = find_chain_event_by_id(ctx, bkpr, + close_ev = find_chain_event_by_id(ctx, bkpr, cmd, *acct->closed_event_db_id); - if (find_txo_chain(ctx, bkpr, acct, &sets)) { + if (find_txo_chain(ctx, bkpr, cmd, acct, &sets)) { /* Ok now we find the max block height of the * spending chain_events for this channel */ bool ok; + const char *buf; + const jsmntok_t *result, *rows, *row; + size_t i; /* Have we accounted for all the outputs */ ok = false; - for (size_t i = 0; i < tal_count(sets); i++) { + for (i = 0; i < tal_count(sets); i++) { if (bitcoin_txid_eq(sets[i]->txid, close_ev->spending_txid)) { @@ -455,21 +313,28 @@ u64 account_onchain_closeheight(const struct bkpr *bkpr, const struct account *a return 0; } - stmt = db_prepare_v2(bkpr->db, SQL("SELECT" - " blockheight" - " FROM chain_events" - " WHERE account_name = ?" - " AND spending_txid IS NOT NULL" - " ORDER BY blockheight DESC" - " LIMIT 1")); + result = sql_req(tmpctx, cmd, &buf, + "SELECT blockheight" + " FROM chainmoves" + " WHERE account_id = '%s'" + " AND spending_txid IS NOT NULL" + " AND created_index <= %"PRIu64 + " ORDER BY blockheight DESC" + " LIMIT 1", + sql_string(tmpctx, acct->name), + bkpr->chainmoves_index); - db_bind_text(stmt, acct->name); - db_query_prepared(stmt); - ok = db_step(stmt); - assert(ok); + rows = json_get_member(buf, result, "rows"); + assert(rows && rows->type == JSMN_ARRAY); - height = db_col_int(stmt, "blockheight"); - tal_free(stmt); + height = 0; + json_for_each_arr(i, row, rows) { + const jsmntok_t *val = row + 1; + assert(row->size == 1); + ok = json_to_u64(buf, val, &height); + assert(ok); + break; + } } else { height = 0; } @@ -480,356 +345,169 @@ u64 account_onchain_closeheight(const struct bkpr *bkpr, const struct account *a struct chain_event *find_chain_event_by_id(const tal_t *ctx, const struct bkpr *bkpr, - u64 event_db_id) + struct command *cmd, + u64 created_index) { - struct db_stmt *stmt; - struct chain_event *e; + struct chain_event **evs = + chain_events_from_sql(tmpctx, bkpr, cmd, + SELECT_CHAIN_EVENTS + " WHERE created_index = %"PRIu64 + " LIMIT 1;", + created_index); - stmt = db_prepare_v2(bkpr->db, SQL("SELECT" - " e.id" - ", e.account_name" - ", e.origin" - ", e.tag" - ", e.credit" - ", e.debit" - ", e.output_value" - ", e.timestamp" - ", e.blockheight" - ", e.utxo_txid" - ", e.outnum" - ", e.spending_txid" - ", e.payment_id" - ", e.stealable" - ", e.spliced" - " FROM chain_events e" - " WHERE " - " e.id = ?")); + if (tal_count(evs) == 0) + return NULL; - db_bind_u64(stmt, event_db_id); - db_query_prepared(stmt); - if (db_step(stmt)) - e = stmt2chain_event(ctx, bkpr, stmt); - else - e = NULL; - - tal_free(stmt); - return e; + return tal_steal(ctx, evs[0]); } struct chain_event **get_chain_events_by_outpoint(const tal_t *ctx, const struct bkpr *bkpr, - const struct bitcoin_outpoint *outpoint, - bool credits_only) + struct command *cmd, + const struct bitcoin_outpoint *outpoint) { - struct db_stmt *stmt; - if (credits_only) - stmt = db_prepare_v2(bkpr->db, SQL("SELECT" - " e.id" - ", e.account_name" - ", e.origin" - ", e.tag" - ", e.credit" - ", e.debit" - ", e.output_value" - ", e.timestamp" - ", e.blockheight" - ", e.utxo_txid" - ", e.outnum" - ", e.spending_txid" - ", e.payment_id" - ", e.stealable" - ", e.spliced" - " FROM chain_events e" - " WHERE " - " e.utxo_txid = ?" - " AND e.outnum = ?" - " AND credit > 0")); - else - stmt = db_prepare_v2(bkpr->db, SQL("SELECT" - " e.id" - ", e.account_name" - ", e.origin" - ", e.tag" - ", e.credit" - ", e.debit" - ", e.output_value" - ", e.timestamp" - ", e.blockheight" - ", e.utxo_txid" - ", e.outnum" - ", e.spending_txid" - ", e.payment_id" - ", e.stealable" - ", e.spliced" - " FROM chain_events e" - " WHERE " - " e.utxo_txid = ?" - " AND e.outnum = ?")); - - db_bind_txid(stmt, &outpoint->txid); - db_bind_int(stmt, outpoint->n); - return find_chain_events(ctx, bkpr, take(stmt)); + return chain_events_from_sql(ctx, bkpr, cmd, + SELECT_CHAIN_EVENTS + " WHERE utxo = '%s'" + " AND credit_msat > 0" + " AND created_index <= %"PRIu64 + " ORDER BY timestamp, created_index", + fmt_bitcoin_outpoint(tmpctx, outpoint), + bkpr->chainmoves_index); } struct chain_event **get_chain_events_by_id(const tal_t *ctx, const struct bkpr *bkpr, + struct command *cmd, const struct sha256 *id) { - struct db_stmt *stmt; - stmt = db_prepare_v2(bkpr->db, SQL("SELECT" - " e.id" - ", e.account_name" - ", e.origin" - ", e.tag" - ", e.credit" - ", e.debit" - ", e.output_value" - ", e.timestamp" - ", e.blockheight" - ", e.utxo_txid" - ", e.outnum" - ", e.spending_txid" - ", e.payment_id" - ", e.stealable" - ", e.spliced" - " FROM chain_events e" - " WHERE " - " e.payment_id = ?")); - - db_bind_sha256(stmt, id); - return find_chain_events(ctx, bkpr, take(stmt)); + return chain_events_from_sql(ctx, bkpr, cmd, + SELECT_CHAIN_EVENTS + " WHERE payment_hash = X'%s'" + " AND created_index <= %"PRIu64 + " ORDER BY timestamp, created_index", + fmt_sha256(tmpctx, id), + bkpr->chainmoves_index); } -static struct chain_event *find_chain_event(const tal_t *ctx, - struct bkpr *bkpr, - const struct account *acct, - const struct bitcoin_outpoint *outpoint, - const struct bitcoin_txid *spending_txid, - const char *tag) - -{ - struct db_stmt *stmt; - struct chain_event *e; - - if (spending_txid) { - stmt = db_prepare_v2(bkpr->db, SQL("SELECT" - " e.id" - ", e.account_name" - ", e.origin" - ", e.tag" - ", e.credit" - ", e.debit" - ", e.output_value" - ", e.timestamp" - ", e.blockheight" - ", e.utxo_txid" - ", e.outnum" - ", e.spending_txid" - ", e.payment_id" - ", e.stealable" - ", e.spliced" - " FROM chain_events e" - " WHERE " - " e.spending_txid = ?" - " AND e.account_name = ?" - " AND e.utxo_txid = ?" - " AND e.outnum = ?")); - db_bind_txid(stmt, spending_txid); - } else { - stmt = db_prepare_v2(bkpr->db, SQL("SELECT" - " e.id" - ", e.account_name" - ", e.origin" - ", e.tag" - ", e.credit" - ", e.debit" - ", e.output_value" - ", e.timestamp" - ", e.blockheight" - ", e.utxo_txid" - ", e.outnum" - ", e.spending_txid" - ", e.payment_id" - ", e.stealable" - ", e.spliced" - " FROM chain_events e" - " WHERE " - " e.tag = ?" - " AND e.account_name = ?" - " AND e.utxo_txid = ?" - " AND e.outnum = ?" - " AND e.spending_txid IS NULL")); - db_bind_text(stmt, tag); - } - - db_bind_text(stmt, acct->name); - db_bind_txid(stmt, &outpoint->txid); - db_bind_int(stmt, outpoint->n); - - db_query_prepared(stmt); - if (db_step(stmt)) - e = stmt2chain_event(ctx, bkpr, stmt); - else - e = NULL; - - tal_free(stmt); - return e; -} - -bool account_get_credit_debit(struct plugin *plugin, - struct db *db, +bool account_get_credit_debit(const struct bkpr *bkpr, + struct command *cmd, const char *acct_name, struct amount_msat *credit, struct amount_msat *debit) { - struct db_stmt *stmt; + const jsmntok_t *result, *rows, *row; + const char *buf; bool exists; /* Get sum from chain_events */ - stmt = db_prepare_v2(db, SQL("SELECT" - " CAST(SUM(ce.credit) AS BIGINT) as credit" - ", CAST(SUM(ce.debit) AS BIGINT) as debit" - " FROM chain_events ce" - " WHERE ce.account_name = ?")); - db_bind_text(stmt, acct_name); - db_query_prepared(stmt); - - db_step(stmt); - if (db_col_is_null(stmt, "credit")) { - db_col_ignore(stmt, "debit"); + result = sql_req(tmpctx, cmd, &buf, + "SELECT" + " CAST(SUM(credit_msat) AS BIGINT)" + ", CAST(SUM(debit_msat) AS BIGINT)" + " FROM chainmoves" + " WHERE account_id = '%s'" + " AND created_index <= %"PRIu64, + sql_string(tmpctx, acct_name), + bkpr->chainmoves_index); + rows = json_get_member(buf, result, "rows"); + assert(rows && rows->type == JSMN_ARRAY && rows->size == 1); + row = rows + 1; + assert(row->size == 2); + if (json_tok_is_null(buf, row + 1)) { *credit = *debit = AMOUNT_MSAT(0); exists = false; } else { - *credit = db_col_amount_msat(stmt, "credit"); - *debit = db_col_amount_msat(stmt, "debit"); + json_to_msat(buf, row + 1, credit); + json_to_msat(buf, row + 2, debit); exists = true; } - tal_free(stmt); /* Get sum from channel_events */ - stmt = db_prepare_v2(db, SQL("SELECT" - " CAST(SUM(ce.credit) AS BIGINT) as credit" - ", CAST(SUM(ce.debit) AS BIGINT) as debit" - " FROM channel_events ce" - " WHERE ce.account_name = ?")); - db_bind_text(stmt, acct_name); - db_query_prepared(stmt); - db_step(stmt); + result = sql_req(tmpctx, cmd, &buf, + "SELECT" + " CAST(SUM(credit_msat) AS BIGINT)" + ", CAST(SUM(debit_msat) AS BIGINT)" + " FROM channelmoves" + " WHERE account_id = '%s'" + " AND created_index <= %"PRIu64, + sql_string(tmpctx, acct_name), + bkpr->channelmoves_index); + rows = json_get_member(buf, result, "rows"); + assert(rows && rows->type == JSMN_ARRAY && rows->size == 1); + row = rows + 1; + assert(row->size == 2); + if (!json_tok_is_null(buf, row + 1)) { + struct amount_msat channel_credit, channel_debit; + json_to_msat(buf, row + 1, &channel_credit); + json_to_msat(buf, row + 2, &channel_debit); - if (db_col_is_null(stmt, "credit")) { - db_col_ignore(stmt, "debit"); - } else { - if (!amount_msat_accumulate(credit, - db_col_amount_msat(stmt, "credit"))) { - plugin_err(plugin, "db overflow: chain credit %s, adding channel credit %s", + if (!amount_msat_accumulate(credit, channel_credit)) { + plugin_err(cmd->plugin, "db overflow: chain credit %s, adding channel credit %s", fmt_amount_msat(tmpctx, *credit), - fmt_amount_msat(tmpctx, - db_col_amount_msat(stmt, "credit"))); + fmt_amount_msat(tmpctx, channel_credit)); } - if (!amount_msat_accumulate(debit, - db_col_amount_msat(stmt, "debit"))) { - plugin_err(plugin, "db overflow: chain debit %s, adding channel debit %s", + if (!amount_msat_accumulate(debit, channel_debit)) { + plugin_err(cmd->plugin, "db overflow: chain debit %s, adding channel debit %s", fmt_amount_msat(tmpctx, *debit), - fmt_amount_msat(tmpctx, - db_col_amount_msat(stmt, "debit"))); + fmt_amount_msat(tmpctx, channel_debit)); } exists = true; } - tal_free(stmt); return exists; } struct channel_event **list_channel_events_timebox(const tal_t *ctx, - struct db *db, + const struct bkpr *bkpr, + struct command *cmd, u64 start_time, u64 end_time) - { - struct db_stmt *stmt; - struct channel_event **results; - - stmt = db_prepare_v2(db, SQL("SELECT" - " e.id" - ", e.account_name" - ", e.tag" - ", e.credit" - ", e.debit" - ", e.fees" - ", e.payment_id" - ", e.part_id" - ", e.timestamp" - " FROM channel_events e" - " WHERE e.timestamp > ?" - " AND e.timestamp <= ?" - " ORDER BY e.timestamp, e.id;")); - - db_bind_u64(stmt, start_time); - db_bind_u64(stmt, end_time); - db_query_prepared(stmt); - - results = tal_arr(ctx, struct channel_event *, 0); - while (db_step(stmt)) { - struct channel_event *e = stmt2channel_event(results, stmt); - tal_arr_expand(&results, e); - } - tal_free(stmt); - - return results; + return channel_events_from_sql(ctx, cmd, + SELECT_CHANNEL_EVENTS + " WHERE timestamp > %"PRIu64 + " AND timestamp <= %"PRIu64 + " AND created_index <= %"PRIu64 + " ORDER BY timestamp, created_index;", + start_time, end_time, + bkpr->channelmoves_index); } -struct channel_event **list_channel_events(const tal_t *ctx, struct db *db) +struct channel_event **list_channel_events(const tal_t *ctx, + const struct bkpr *bkpr, + struct command *cmd) { - return list_channel_events_timebox(ctx, db, 0, SQLITE_MAX_UINT); + return list_channel_events_timebox(ctx, bkpr, cmd, 0, SQLITE_MAX_UINT); } struct channel_event **account_get_channel_events(const tal_t *ctx, - struct db *db, + const struct bkpr *bkpr, + struct command *cmd, struct account *acct) { - struct db_stmt *stmt; - - stmt = db_prepare_v2(db, SQL("SELECT" - " e.id" - ", e.account_name" - ", e.tag" - ", e.credit" - ", e.debit" - ", e.fees" - ", e.payment_id" - ", e.part_id" - ", e.timestamp" - " FROM channel_events e" - " WHERE e.account_name = ?" - " ORDER BY e.timestamp, e.id")); - - db_bind_text(stmt, acct->name); - return find_channel_events(ctx, take(stmt)); + return channel_events_from_sql(ctx, cmd, + SELECT_CHANNEL_EVENTS + " WHERE account_id = '%s'" + " AND created_index <= %"PRIu64 + " ORDER BY timestamp, created_index", + sql_string(tmpctx, acct->name), + bkpr->channelmoves_index); } struct channel_event **get_channel_events_by_id(const tal_t *ctx, - struct db *db, - struct sha256 *id) + const struct bkpr *bkpr, + struct command *cmd, + const struct sha256 *id) { - struct db_stmt *stmt; - - stmt = db_prepare_v2(db, SQL("SELECT" - " e.id" - ", e.account_name" - ", e.tag" - ", e.credit" - ", e.debit" - ", e.fees" - ", e.payment_id" - ", e.part_id" - ", e.timestamp" - " FROM channel_events e" - " WHERE e.payment_id = ?" - " ORDER BY e.timestamp, e.id")); - - db_bind_sha256(stmt, id); - return find_channel_events(ctx, take(stmt)); + return channel_events_from_sql(ctx, cmd, + SELECT_CHANNEL_EVENTS + " WHERE payment_hash = X'%s'" + " AND created_index <= %"PRIu64 + " ORDER BY timestamp, created_index", + fmt_sha256(tmpctx, id), + bkpr->channelmoves_index); } void log_channel_event(struct db *db, @@ -872,34 +550,18 @@ void log_channel_event(struct db *db, struct chain_event **find_chain_events_bytxid(const tal_t *ctx, const struct bkpr *bkpr, + struct command *cmd, const struct bitcoin_txid *txid) { - struct db_stmt *stmt; - - stmt = db_prepare_v2(bkpr->db, SQL("SELECT " - " e.id" - ", e.account_name" - ", e.origin" - ", e.tag" - ", e.credit" - ", e.debit" - ", e.output_value" - ", e.timestamp" - ", e.blockheight" - ", e.utxo_txid" - ", e.outnum" - ", e.spending_txid" - ", e.payment_id" - ", e.stealable" - ", e.spliced" - " FROM chain_events e" - " WHERE e.spending_txid = ?" - " OR (e.utxo_txid = ? AND e.spending_txid IS NULL)" - " ORDER BY e.account_name")); - - db_bind_txid(stmt, txid); - db_bind_txid(stmt, txid); - return find_chain_events(ctx, bkpr, take(stmt)); + return chain_events_from_sql(ctx, bkpr, cmd, + SELECT_CHAIN_EVENTS + " WHERE created_index <= %"PRIu64 + " AND (spending_txid = X'%s'" + " OR (utxo LIKE '%s%%' AND spending_txid IS NULL))" + " ORDER BY account_id, created_index", + bkpr->chainmoves_index, + fmt_bitcoin_txid(tmpctx, txid), /* spending_txid match */ + fmt_bitcoin_txid(tmpctx, txid)); /* utxo prefix (txid:*) */ } void maybe_record_rebalance(struct command *cmd, @@ -911,7 +573,9 @@ void maybe_record_rebalance(struct command *cmd, * and amt as such. If you repeat a payment_id * with the same amt, they'll be marked as rebalances * also */ - struct db_stmt *stmt; + const char *buf; + const jsmntok_t *res, *rows, *row, *val; + size_t i; struct amount_msat credit; bool ok; @@ -919,54 +583,65 @@ void maybe_record_rebalance(struct command *cmd, ok = amount_msat_sub(&credit, out->debit, out->fees); assert(ok); - stmt = db_prepare_v2(bkpr->db, SQL("SELECT " - " e.id" - " FROM channel_events e" - " WHERE e.payment_id = ?" - " AND e.credit = ?")); + /* Look for a matching credit-side event for the same payment */ + res = sql_req(tmpctx, cmd, &buf, + "SELECT created_index" + " FROM channelmoves" + " WHERE payment_hash = X'%s'" + " AND credit_msat = %"PRIu64 + " AND created_index <= %"PRIu64, + fmt_sha256(tmpctx, out->payment_id), + credit.millisatoshis /* Raw: sql query */, + bkpr->channelmoves_index); - db_bind_sha256(stmt, out->payment_id); - db_bind_amount_msat(stmt, credit); - db_query_prepared(stmt); + rows = json_get_member(buf, res, "rows"); + json_for_each_arr(i, row, rows) { + u64 id; + val = row + 1; /* single column */ + ok = json_to_u64(buf, val, &id); + assert(ok); - while (db_step(stmt)) { - u64 id = db_col_u64(stmt, "e.id"); /* Already has one? */ if (find_rebalance(bkpr, id)) continue; + add_rebalance_pair(cmd, bkpr, out->db_id, id); break; } - tal_free(stmt); } void maybe_closeout_external_deposits(struct command *cmd, struct bkpr *bkpr, - const struct bitcoin_txid *txid, + const struct bitcoin_txid *txid, u32 blockheight) { - struct db_stmt *stmt; + const char *buf; + const jsmntok_t *res, *rows, *row; + size_t i; - assert(txid); - stmt = db_prepare_v2(bkpr->db, SQL("SELECT " - " 1" - " FROM chain_events e" - " WHERE e.blockheight = ?" - " AND e.utxo_txid = ?" - " AND e.account_name = ?")); + /* Find any unconfirmed external deposits for this txid. */ + res = sql_req(tmpctx, cmd, &buf, + "SELECT utxo" + " FROM chainmoves" + " WHERE blockheight = 0" + " AND utxo LIKE '%s:%%'" + " AND account_id = '%s'" + " AND created_index <= %"PRIu64, + /* utxo is ':' so we prefix-match on txid: */ + fmt_bitcoin_txid(tmpctx, txid), + sql_string(tmpctx, ACCOUNT_NAME_EXTERNAL), + bkpr->chainmoves_index); - /* Blockheight for unconfirmeds is zero */ - db_bind_int(stmt, 0); - db_bind_txid(stmt, txid); - db_bind_text(stmt, ACCOUNT_NAME_EXTERNAL); - db_query_prepared(stmt); + rows = json_get_member(buf, res, "rows"); + json_for_each_arr(i, row, rows) { + const jsmntok_t *val = row + 1; /* single column */ + struct bitcoin_outpoint outp; + bool ok; - if (db_step(stmt)) { - db_col_ignore(stmt, "1"); - add_blockheight(cmd, bkpr, txid, blockheight); + ok = json_to_outpoint(buf, val, &outp); + assert(ok); + add_blockheight(cmd, bkpr, &outp.txid, blockheight); } - - tal_free(stmt); } bool log_chain_event(struct bkpr *bkpr, @@ -975,12 +650,6 @@ bool log_chain_event(struct bkpr *bkpr, { struct db_stmt *stmt; - /* We're responsible for de-duping chain events! */ - if (find_chain_event(tmpctx, bkpr, acct, - &e->outpoint, e->spending_txid, - e->tag)) - return false; - stmt = db_prepare_v2(bkpr->db, SQL("INSERT INTO chain_events" " (" " account_name" diff --git a/plugins/bkpr/recorder.h b/plugins/bkpr/recorder.h index 991a2a59c..9ffdd2721 100644 --- a/plugins/bkpr/recorder.h +++ b/plugins/bkpr/recorder.h @@ -33,16 +33,20 @@ struct txo_set { /* Get all channel events for this account */ struct channel_event **account_get_channel_events(const tal_t *ctx, - struct db *db, + const struct bkpr *bkpr, + struct command *cmd, struct account *acct); /* Get all channel events for a payment id, order by timestamp */ struct channel_event **get_channel_events_by_id(const tal_t *ctx, - struct db *db, - struct sha256 *id); + const struct bkpr *bkpr, + struct command *cmd, + const struct sha256 *id); /* Get all channel events, ordered by timestamp */ -struct channel_event **list_channel_events(const tal_t *ctx, struct db *db); +struct channel_event **list_channel_events(const tal_t *ctx, + const struct bkpr *bkpr, + struct command *cmd); /* Get all channel events, order by timestamp. * @@ -52,50 +56,56 @@ struct channel_event **list_channel_events(const tal_t *ctx, struct db *db); * @end_time - UNIX timestamp to query until (inclusive) */ struct channel_event **list_channel_events_timebox(const tal_t *ctx, - struct db *db, + const struct bkpr *bkpr, + struct command *cmd, u64 start_time, u64 end_time); /* Get all chain events for this account */ struct chain_event **account_get_chain_events(const tal_t *ctx, const struct bkpr *bkpr, + struct command *cmd, struct account *acct); /* Get all chain events for a transaction id, order by timestamp */ struct chain_event **find_chain_events_bytxid(const tal_t *ctx, const struct bkpr *bkpr, + struct command *cmd, const struct bitcoin_txid *txid); /* Get all chain events, order by timestamp. */ -struct chain_event **list_chain_events(const tal_t *ctx, const struct bkpr *bkpr); +struct chain_event **list_chain_events(const tal_t *ctx, + const struct bkpr *bkpr, + struct command *cmd); /* Get all chain events, order by timestamp. * * @ctx - context to allocate from - * @db - database to query * @start_time - UNIX timestamp to query after (exclusive) * @end_time - UNIX timestamp to query until (inclusive) */ struct chain_event **list_chain_events_timebox(const tal_t *ctx, const struct bkpr *bkpr, + struct command *cmd, u64 start_time, u64 end_time); /* Get all chain events for a payment hash */ struct chain_event **get_chain_events_by_id(const tal_t *ctx, - const struct bkpr *bkpr, - const struct sha256 *id); + const struct bkpr *bkpr, + struct command *cmd, + const struct sha256 *id); /* Get all chain events for a utxo */ struct chain_event **get_chain_events_by_outpoint(const tal_t *ctx, const struct bkpr *bkpr, - const struct bitcoin_outpoint *outpoint, - bool credits_only); + struct command *cmd, + const struct bitcoin_outpoint *outpoint); /* Get total credits and debits for this account: returns false if no entries at all * (in which case, credit and debit will both be AMOUNT_MSAT(0)). */ -bool account_get_credit_debit(struct plugin *plugin, - struct db *db, +bool account_get_credit_debit(const struct bkpr *bkpr, + struct command *cmd, const char *acct_name, struct amount_msat *credit, struct amount_msat *debit); @@ -104,6 +114,7 @@ bool account_get_credit_debit(struct plugin *plugin, /* Find a chain event by its database id */ struct chain_event *find_chain_event_by_id(const tal_t *ctx, const struct bkpr *bkpr, + struct command *cmd, u64 event_db_id); /* Find the utxos for this account. @@ -113,13 +124,15 @@ struct chain_event *find_chain_event_by_id(const tal_t *ctx, */ bool find_txo_chain(const tal_t *ctx, const struct bkpr *bkpr, + struct command *cmd, const struct account *acct, struct txo_set ***sets); /* Find the account that was closed by this txid. * Returns NULL if none */ const char *find_close_account_name(const tal_t *ctx, - struct db *db, + const struct bkpr *bkpr, + struct command *cmd, const struct bitcoin_txid *txid); /* Have all the outputs for this account's close tx @@ -127,7 +140,9 @@ const char *find_close_account_name(const tal_t *ctx, * highest blockheight that has a resolving tx in it. * * The point of this is to allow us to prune data, eventually */ -u64 account_onchain_closeheight(const struct bkpr *bkpr, const struct account *acct); +u64 account_onchain_closeheight(const struct bkpr *bkpr, + struct command *cmd, + const struct account *acct); /* When we make external deposits from the wallet, we don't * count them until any output that was spent *into* them is