Skip to content

Commit 47c2735

Browse files
committed
bkpr: remove currency support from balances.
We're going to get rid of this concept, but the main change is that the account_get_balance API can be drastically simplified: account_get_credit_debit() accesses the raw fields, never fails, but returns the a flag which tells us if the account doesn't actually have any events. The one place we care about the balance, calculate by hand. Then account_get_balance() (and struct account_balance) can simply be moved to th test. Subtly, without the "GROUP BY" clause, you always get one row, even if there are no rows (but the SUM are null). Signed-off-by: Rusty Russell <[email protected]>
1 parent 0c9dc4c commit 47c2735

File tree

4 files changed

+108
-198
lines changed

4 files changed

+108
-198
lines changed

plugins/bkpr/bookkeeper.c

Lines changed: 33 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "config.h"
2+
#include <bitcoin/chainparams.h>
23
#include <ccan/array_size/array_size.h>
34
#include <ccan/cast/cast.h>
45
#include <ccan/json_escape/json_escape.h>
@@ -556,7 +557,6 @@ static struct command_result *json_list_balances(struct command *cmd,
556557
{
557558
struct json_stream *res;
558559
struct account **accts;
559-
char *err;
560560

561561
if (!param(cmd, buf, params, NULL))
562562
return command_param_failed();
@@ -568,18 +568,19 @@ static struct command_result *json_list_balances(struct command *cmd,
568568

569569
json_array_start(res, "accounts");
570570
for (size_t i = 0; i < tal_count(accts); i++) {
571-
struct acct_balance **balances;
572-
573-
err = account_get_balance(cmd, db,
574-
accts[i]->name,
575-
true,
576-
&balances);
571+
struct amount_msat credit, debit, balance;
572+
bool has_events;
577573

578-
if (err)
574+
has_events = account_get_credit_debit(cmd->plugin, db,
575+
accts[i]->name,
576+
&credit, &debit);
577+
if (!amount_msat_sub(&balance, credit, debit)) {
579578
plugin_err(cmd->plugin,
580-
"Get account balance returned err"
581-
" for account %s: %s",
582-
accts[i]->name, err);
579+
"Account balance underflow for account %s (credit %s, debit %s)",
580+
accts[i]->name,
581+
fmt_amount_msat(tmpctx, credit),
582+
fmt_amount_msat(tmpctx, debit));
583+
}
583584

584585
/* Skip the external acct balance, it's effectively
585586
* meaningless */
@@ -602,13 +603,15 @@ static struct command_result *json_list_balances(struct command *cmd,
602603
accts[i]->onchain_resolved_block);
603604
}
604605

606+
/* FIXME: This API is now overkill! */
605607
json_array_start(res, "balances");
606-
for (size_t j = 0; j < tal_count(balances); j++) {
608+
/* We expect no entry if account is not used. */
609+
for (size_t j = 0; j < has_events; j++) {
607610
json_object_start(res, NULL);
608611
json_add_amount_msat(res, "balance_msat",
609-
balances[j]->balance);
612+
balance);
610613
json_add_string(res, "coin_type",
611-
balances[j]->currency);
614+
chainparams->lightning_hrp);
612615
json_object_end(res);
613616
}
614617
json_array_end(res);
@@ -951,8 +954,7 @@ static struct command_result *listpeerchannels_multi_done(struct command *cmd,
951954
/* Let's register all these accounts! */
952955
for (size_t i = 0; i < tal_count(new_accts); i++) {
953956
struct new_account_info *info = new_accts[i];
954-
struct acct_balance **balances, *bal;
955-
struct amount_msat credit_diff, debit_diff;
957+
struct amount_msat credit, debit, credit_diff, debit_diff;
956958
char *err;
957959

958960
if (!new_missed_channel_account(cmd, buf, result,
@@ -966,25 +968,14 @@ static struct command_result *listpeerchannels_multi_done(struct command *cmd,
966968
}
967969

968970
db_begin_transaction(db);
969-
err = account_get_balance(tmpctx, db, info->acct->name,
970-
false, &balances);
971+
account_get_credit_debit(cmd->plugin, db,
972+
info->acct->name,
973+
&credit, &debit);
971974
db_commit_transaction(db);
972975

973-
if (err)
974-
plugin_err(cmd->plugin, "%s", err);
975-
976-
/* FIXME: multiple currencies */
977-
if (tal_count(balances) > 0)
978-
bal = balances[0];
979-
else {
980-
bal = tal(tmpctx, struct acct_balance);
981-
bal->credit = AMOUNT_MSAT(0);
982-
bal->debit= AMOUNT_MSAT(0);
983-
}
984-
985976
err = msat_find_diff(info->curr_bal,
986-
bal->credit,
987-
bal->debit,
977+
credit,
978+
debit,
988979
&credit_diff, &debit_diff);
989980
if (err)
990981
plugin_err(cmd->plugin, "%s", err);
@@ -1075,9 +1066,8 @@ static struct command_result *json_balance_snapshot(struct command *cmd,
10751066

10761067
db_begin_transaction(db);
10771068
json_for_each_arr(i, acct_tok, accounts_tok) {
1078-
struct acct_balance **balances, *bal;
10791069
struct account *acct;
1080-
struct amount_msat snap_balance, credit_diff, debit_diff;
1070+
struct amount_msat snap_balance, credit, debit, credit_diff, debit_diff;
10811071
char *acct_name, *currency;
10821072
bool existed;
10831073

@@ -1101,34 +1091,13 @@ static struct command_result *json_balance_snapshot(struct command *cmd,
11011091
fmt_amount_msat(tmpctx, snap_balance));
11021092

11031093
/* Find the account balances */
1104-
err = account_get_balance(cmd, db, acct_name,
1105-
/* Don't error if negative */
1106-
false,
1107-
&balances);
1108-
1109-
if (err)
1110-
plugin_err(cmd->plugin,
1111-
"Get account balance returned err"
1112-
" for account %s: %s",
1113-
acct_name, err);
1114-
1115-
/* multiple currency balances! */
1116-
bal = NULL;
1117-
for (size_t j = 0; j < tal_count(balances); j++) {
1118-
if (streq(balances[j]->currency, currency))
1119-
bal = balances[j];
1120-
}
1121-
1122-
if (!bal) {
1123-
bal = tal(balances, struct acct_balance);
1124-
bal->credit = AMOUNT_MSAT(0);
1125-
bal->debit = AMOUNT_MSAT(0);
1126-
}
1094+
account_get_credit_debit(cmd->plugin, db, acct_name,
1095+
&credit, &debit);
11271096

11281097
/* Figure out what the net diff is btw reported & actual */
11291098
err = msat_find_diff(snap_balance,
1130-
bal->credit,
1131-
bal->debit,
1099+
credit,
1100+
debit,
11321101
&credit_diff, &debit_diff);
11331102
if (err)
11341103
plugin_err(cmd->plugin,
@@ -1398,37 +1367,23 @@ listpeerchannels_done(struct command *cmd,
13981367
const jsmntok_t *result,
13991368
struct event_info *info)
14001369
{
1401-
struct acct_balance **balances, *bal;
1402-
struct amount_msat credit_diff, debit_diff;
1370+
struct amount_msat credit, debit, credit_diff, debit_diff;
14031371
const char *err;
14041372

14051373
if (new_missed_channel_account(cmd, buf, result,
14061374
info->acct,
14071375
info->ev->currency,
14081376
info->ev->timestamp)) {
14091377
db_begin_transaction(db);
1410-
err = account_get_balance(tmpctx, db, info->acct->name,
1411-
false, &balances);
1378+
account_get_credit_debit(cmd->plugin, db, info->acct->name,
1379+
&credit, &debit);
14121380
db_commit_transaction(db);
14131381

1414-
if (err)
1415-
plugin_err(cmd->plugin, "%s", err);
1416-
1417-
/* FIXME: multiple currencies per account? */
1418-
if (tal_count(balances) > 0)
1419-
bal = balances[0];
1420-
else {
1421-
bal = tal(balances, struct acct_balance);
1422-
bal->credit = AMOUNT_MSAT(0);
1423-
bal->debit = AMOUNT_MSAT(0);
1424-
}
1425-
assert(tal_count(balances) == 1);
1426-
14271382
/* The expected current balance is zero, since
14281383
* we just got the channel close event */
14291384
err = msat_find_diff(AMOUNT_MSAT(0),
1430-
bal->credit,
1431-
bal->debit,
1385+
credit,
1386+
debit,
14321387
&credit_diff, &debit_diff);
14331388
if (err)
14341389
plugin_err(cmd->plugin, "%s", err);

plugins/bkpr/recorder.c

Lines changed: 38 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <plugins/bkpr/channel_event.h>
1616
#include <plugins/bkpr/onchain_fee.h>
1717
#include <plugins/bkpr/recorder.h>
18+
#include <plugins/libplugin.h>
1819

1920

2021
static struct chain_event *stmt2chain_event(const tal_t *ctx, struct db_stmt *stmt)
@@ -917,103 +918,72 @@ static struct chain_event *find_chain_event(const tal_t *ctx,
917918
return e;
918919
}
919920

920-
char *account_get_balance(const tal_t *ctx,
921-
struct db *db,
922-
const char *acct_name,
923-
bool calc_sum,
924-
struct acct_balance ***balances)
921+
bool account_get_credit_debit(struct plugin *plugin,
922+
struct db *db,
923+
const char *acct_name,
924+
struct amount_msat *credit,
925+
struct amount_msat *debit)
925926
{
926927
struct db_stmt *stmt;
928+
bool exists;
927929

930+
/* Get sum from chain_events */
928931
stmt = db_prepare_v2(db, SQL("SELECT"
929932
" CAST(SUM(ce.credit) AS BIGINT) as credit"
930933
", CAST(SUM(ce.debit) AS BIGINT) as debit"
931-
", ce.currency"
932934
" FROM chain_events ce"
933935
" LEFT OUTER JOIN accounts a"
934936
" ON a.id = ce.account_id"
935-
" WHERE a.name = ?"
936-
" GROUP BY ce.currency"));
937-
937+
" WHERE a.name = ?"));
938938
db_bind_text(stmt, acct_name);
939939
db_query_prepared(stmt);
940-
*balances = tal_arr(ctx, struct acct_balance *, 0);
941-
942-
while (db_step(stmt)) {
943-
struct acct_balance *bal;
944940

945-
bal = tal(*balances, struct acct_balance);
946-
947-
bal->currency = db_col_strdup(bal, stmt, "ce.currency");
948-
bal->credit = db_col_amount_msat(stmt, "credit");
949-
bal->debit = db_col_amount_msat(stmt, "debit");
950-
tal_arr_expand(balances, bal);
941+
db_step(stmt);
942+
if (db_col_is_null(stmt, "credit")) {
943+
db_col_ignore(stmt, "debit");
944+
*credit = *debit = AMOUNT_MSAT(0);
945+
exists = false;
946+
} else {
947+
*credit = db_col_amount_msat(stmt, "credit");
948+
*debit = db_col_amount_msat(stmt, "debit");
949+
exists = true;
951950
}
952951
tal_free(stmt);
953952

953+
/* Get sum from channel_events */
954954
stmt = db_prepare_v2(db, SQL("SELECT"
955955
" CAST(SUM(ce.credit) AS BIGINT) as credit"
956956
", CAST(SUM(ce.debit) AS BIGINT) as debit"
957-
", ce.currency"
958957
" FROM channel_events ce"
959958
" LEFT OUTER JOIN accounts a"
960959
" ON a.id = ce.account_id"
961-
" WHERE a.name = ?"
962-
" GROUP BY ce.currency"));
960+
" WHERE a.name = ?"));
963961
db_bind_text(stmt, acct_name);
964962
db_query_prepared(stmt);
963+
db_step(stmt);
965964

966-
while (db_step(stmt)) {
967-
struct amount_msat amt;
968-
struct acct_balance *bal = NULL;
969-
char *currency;
970-
971-
currency = db_col_strdup(ctx, stmt, "ce.currency");
972-
973-
/* Find the currency entry from above */
974-
for (size_t i = 0; i < tal_count(*balances); i++) {
975-
if (streq((*balances)[i]->currency, currency)) {
976-
bal = (*balances)[i];
977-
break;
978-
}
979-
}
980-
981-
if (!bal) {
982-
bal = tal(*balances, struct acct_balance);
983-
bal->credit = AMOUNT_MSAT(0);
984-
bal->debit = AMOUNT_MSAT(0);
985-
bal->currency = tal_steal(bal, currency);
986-
tal_arr_expand(balances, bal);
987-
}
988-
989-
amt = db_col_amount_msat(stmt, "credit");
990-
if (!amount_msat_accumulate(&bal->credit, amt)) {
991-
tal_free(stmt);
992-
return "overflow adding channel_event credits";
965+
if (db_col_is_null(stmt, "credit")) {
966+
db_col_ignore(stmt, "debit");
967+
} else {
968+
if (!amount_msat_accumulate(credit,
969+
db_col_amount_msat(stmt, "credit"))) {
970+
plugin_err(plugin, "db overflow: chain credit %s, adding channel credit %s",
971+
fmt_amount_msat(tmpctx, *credit),
972+
fmt_amount_msat(tmpctx,
973+
db_col_amount_msat(stmt, "credit")));
993974
}
994975

995-
amt = db_col_amount_msat(stmt, "debit");
996-
if (!amount_msat_accumulate(&bal->debit, amt)) {
997-
tal_free(stmt);
998-
return "overflow adding channel_event debits";
976+
if (!amount_msat_accumulate(debit,
977+
db_col_amount_msat(stmt, "debit"))) {
978+
plugin_err(plugin, "db overflow: chain debit %s, adding channel debit %s",
979+
fmt_amount_msat(tmpctx, *debit),
980+
fmt_amount_msat(tmpctx,
981+
db_col_amount_msat(stmt, "debit")));
999982
}
983+
exists = true;
1000984
}
1001985
tal_free(stmt);
1002-
1003-
if (!calc_sum)
1004-
return NULL;
1005-
1006-
for (size_t i = 0; i < tal_count(*balances); i++) {
1007-
struct acct_balance *bal = (*balances)[i];
1008-
if (!amount_msat_sub(&bal->balance, bal->credit, bal->debit))
1009-
return tal_fmt(ctx,
1010-
"%s channel balance is negative? %s - %s",
1011-
bal->currency,
1012-
fmt_amount_msat(ctx, bal->credit),
1013-
fmt_amount_msat(ctx, bal->debit));
1014-
}
1015-
1016-
return NULL;
986+
return exists;
1017987
}
1018988

1019989
struct channel_event **list_channel_events_timebox(const tal_t *ctx,

plugins/bkpr/recorder.h

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,12 @@ struct bitcoin_txid;
99
struct chain_event;
1010
struct channel_event;
1111
struct db;
12+
struct plugin;
1213
enum mvt_tag;
1314
struct onchain_fee;
1415

1516
#define SQLITE_MAX_UINT 0x7FFFFFFFFFFFFFFF
1617

17-
struct acct_balance {
18-
char *currency;
19-
struct amount_msat credit;
20-
struct amount_msat debit;
21-
struct amount_msat balance;
22-
};
23-
2418
struct fee_sum {
2519
u64 acct_db_id;
2620
char *acct_name;
@@ -116,15 +110,14 @@ struct chain_event **get_chain_events_by_outpoint(const tal_t *ctx,
116110
const struct bitcoin_outpoint *outpoint,
117111
bool credits_only);
118112

119-
/* Calculate the balances for an account
120-
*
121-
* @calc_sum - compute the total balance. error if negative
122-
* */
123-
char *account_get_balance(const tal_t *ctx,
124-
struct db *db,
125-
const char *acct_name,
126-
bool calc_sum,
127-
struct acct_balance ***balances);
113+
/* Get total credits and debits for this account: returns false if no entries at all
114+
* (in which case, credit and debit will both be AMOUNT_MSAT(0)). */
115+
bool account_get_credit_debit(struct plugin *plugin,
116+
struct db *db,
117+
const char *acct_name,
118+
struct amount_msat *credit,
119+
struct amount_msat *debit);
120+
128121

129122
/* Get chain fees for account */
130123
struct onchain_fee **account_get_chain_fees(const tal_t *ctx, struct db *db,

0 commit comments

Comments
 (0)