mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-23 09:04:22 +01:00
bkpr: add a new command listaccountevents
Prints all the events for the requested account. If no account requested, prints out all the events. Ordered by timestamp. Changelog-Added: bookkeeper: new command `listaccountevents`
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <ccan/array_size/array_size.h>
|
#include <ccan/array_size/array_size.h>
|
||||||
|
#include <ccan/cast/cast.h>
|
||||||
#include <ccan/tal/str/str.h>
|
#include <ccan/tal/str/str.h>
|
||||||
#include <ccan/time/time.h>
|
#include <ccan/time/time.h>
|
||||||
#include <common/coin_mvt.h>
|
#include <common/coin_mvt.h>
|
||||||
@@ -12,6 +13,7 @@
|
|||||||
#include <plugins/bkpr/account.h>
|
#include <plugins/bkpr/account.h>
|
||||||
#include <plugins/bkpr/chain_event.h>
|
#include <plugins/bkpr/chain_event.h>
|
||||||
#include <plugins/bkpr/channel_event.h>
|
#include <plugins/bkpr/channel_event.h>
|
||||||
|
#include <plugins/bkpr/onchain_fee.h>
|
||||||
#include <plugins/bkpr/recorder.h>
|
#include <plugins/bkpr/recorder.h>
|
||||||
#include <plugins/libplugin.h>
|
#include <plugins/libplugin.h>
|
||||||
|
|
||||||
@@ -24,6 +26,158 @@ static struct db *db ;
|
|||||||
// FIXME: make relative to directory we're loaded into
|
// FIXME: make relative to directory we're loaded into
|
||||||
static char *db_dsn = "sqlite3://accounts.sqlite3";
|
static char *db_dsn = "sqlite3://accounts.sqlite3";
|
||||||
|
|
||||||
|
static void json_add_channel_event(struct json_stream *out,
|
||||||
|
struct channel_event *ev)
|
||||||
|
{
|
||||||
|
json_object_start(out, NULL);
|
||||||
|
json_add_string(out, "account", ev->acct_name);
|
||||||
|
json_add_string(out, "type", "channel");
|
||||||
|
json_add_string(out, "tag", ev->tag);
|
||||||
|
json_add_amount_msat_only(out, "credit", ev->credit);
|
||||||
|
json_add_amount_msat_only(out, "debit", ev->debit);
|
||||||
|
json_add_string(out, "currency", ev->currency);
|
||||||
|
if (ev->payment_id)
|
||||||
|
json_add_sha256(out, "payment_id", ev->payment_id);
|
||||||
|
json_add_u64(out, "timestamp", ev->timestamp);
|
||||||
|
json_object_end(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void json_add_chain_event(struct json_stream *out,
|
||||||
|
struct chain_event *ev)
|
||||||
|
{
|
||||||
|
json_object_start(out, NULL);
|
||||||
|
json_add_string(out, "account", ev->acct_name);
|
||||||
|
json_add_string(out, "type", "chain");
|
||||||
|
json_add_string(out, "tag", ev->tag);
|
||||||
|
json_add_amount_msat_only(out, "credit", ev->credit);
|
||||||
|
json_add_amount_msat_only(out, "debit", ev->debit);
|
||||||
|
json_add_string(out, "currency", ev->currency);
|
||||||
|
json_add_outpoint(out, "outpoint", &ev->outpoint);
|
||||||
|
if (ev->spending_txid)
|
||||||
|
json_add_txid(out, "txid", ev->spending_txid);
|
||||||
|
if (ev->payment_id)
|
||||||
|
json_add_sha256(out, "payment_id", ev->payment_id);
|
||||||
|
json_add_u64(out, "timestamp", ev->timestamp);
|
||||||
|
json_add_u32(out, "blockheight", ev->blockheight);
|
||||||
|
json_object_end(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void json_add_onchain_fee(struct json_stream *out,
|
||||||
|
struct onchain_fee *fee)
|
||||||
|
{
|
||||||
|
json_object_start(out, NULL);
|
||||||
|
json_add_string(out, "account", fee->acct_name);
|
||||||
|
json_add_string(out, "type", "onchain_fee");
|
||||||
|
json_add_string(out, "tag", "onchain_fee");
|
||||||
|
json_add_amount_msat_only(out, "credit", fee->credit);
|
||||||
|
json_add_amount_msat_only(out, "debit", fee->debit);
|
||||||
|
json_add_string(out, "currency", fee->currency);
|
||||||
|
json_add_u64(out, "timestamp", fee->timestamp);
|
||||||
|
json_add_txid(out, "txid", &fee->txid);
|
||||||
|
json_object_end(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find all the events for this account, ordered by timestamp */
|
||||||
|
static struct command_result *json_list_account_events(struct command *cmd,
|
||||||
|
const char *buf,
|
||||||
|
const jsmntok_t *params)
|
||||||
|
{
|
||||||
|
struct json_stream *res;
|
||||||
|
struct account *acct;
|
||||||
|
const char *acct_name;
|
||||||
|
struct channel_event **channel_events;
|
||||||
|
struct chain_event **chain_events;
|
||||||
|
struct onchain_fee **onchain_fees;
|
||||||
|
|
||||||
|
if (!param(cmd, buf, params,
|
||||||
|
p_opt("account", param_string, &acct_name),
|
||||||
|
NULL))
|
||||||
|
return command_param_failed();
|
||||||
|
|
||||||
|
if (acct_name) {
|
||||||
|
db_begin_transaction(db);
|
||||||
|
acct = find_account(cmd, db, acct_name);
|
||||||
|
db_commit_transaction(db);
|
||||||
|
|
||||||
|
if (!acct)
|
||||||
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||||
|
"Account '%s' not found",
|
||||||
|
acct_name);
|
||||||
|
} else
|
||||||
|
acct = NULL;
|
||||||
|
|
||||||
|
db_begin_transaction(db);
|
||||||
|
if (acct) {
|
||||||
|
channel_events = account_get_channel_events(cmd, db, acct);
|
||||||
|
chain_events = account_get_chain_events(cmd, db, acct);
|
||||||
|
onchain_fees = account_get_chain_fees(cmd, db, acct);
|
||||||
|
} else {
|
||||||
|
channel_events = list_channel_events(cmd, db);
|
||||||
|
chain_events = list_chain_events(cmd, db);
|
||||||
|
onchain_fees = list_chain_fees(cmd, db);
|
||||||
|
}
|
||||||
|
db_commit_transaction(db);
|
||||||
|
|
||||||
|
res = jsonrpc_stream_success(cmd);
|
||||||
|
json_array_start(res, "events");
|
||||||
|
for (size_t i = 0, j = 0, k = 0;
|
||||||
|
i < tal_count(channel_events)
|
||||||
|
|| j < tal_count(chain_events)
|
||||||
|
|| k < tal_count(onchain_fees);
|
||||||
|
/* Incrementing happens inside loop */) {
|
||||||
|
struct channel_event *chan;
|
||||||
|
struct chain_event *chain;
|
||||||
|
struct onchain_fee *fee;
|
||||||
|
u64 lowest = 0;
|
||||||
|
|
||||||
|
if (i < tal_count(channel_events))
|
||||||
|
chan = channel_events[i];
|
||||||
|
else
|
||||||
|
chan = NULL;
|
||||||
|
if (j < tal_count(chain_events))
|
||||||
|
chain = chain_events[j];
|
||||||
|
else
|
||||||
|
chain = NULL;
|
||||||
|
if (k < tal_count(onchain_fees))
|
||||||
|
fee = onchain_fees[k];
|
||||||
|
else
|
||||||
|
fee = NULL;
|
||||||
|
|
||||||
|
if (chan)
|
||||||
|
lowest = chan->timestamp;
|
||||||
|
|
||||||
|
if (chain
|
||||||
|
&& (lowest == 0 || lowest > chain->timestamp))
|
||||||
|
lowest = chain->timestamp;
|
||||||
|
|
||||||
|
if (fee
|
||||||
|
&& (lowest == 0 || lowest > fee->timestamp))
|
||||||
|
lowest = fee->timestamp;
|
||||||
|
|
||||||
|
/* channel events first, then chain events, then fees.
|
||||||
|
* (channel events contain journal entries, which
|
||||||
|
* are the starting balance for accounts created
|
||||||
|
* before the accountant plugin was installed) */
|
||||||
|
if (chan && chan->timestamp == lowest) {
|
||||||
|
json_add_channel_event(res, chan);
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chain && chain->timestamp == lowest) {
|
||||||
|
json_add_chain_event(res, chain);
|
||||||
|
j++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Last thing left is the fee */
|
||||||
|
json_add_onchain_fee(res, fee);
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
json_array_end(res);
|
||||||
|
return command_finished(cmd, res);
|
||||||
|
}
|
||||||
|
|
||||||
static struct command_result *json_list_balances(struct command *cmd,
|
static struct command_result *json_list_balances(struct command *cmd,
|
||||||
const char *buf,
|
const char *buf,
|
||||||
const jsmntok_t *params)
|
const jsmntok_t *params)
|
||||||
@@ -870,6 +1024,14 @@ static const struct plugin_command commands[] = {
|
|||||||
"List of current accounts and their balances",
|
"List of current accounts and their balances",
|
||||||
json_list_balances
|
json_list_balances
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"listaccountevents",
|
||||||
|
"bookkeeping",
|
||||||
|
"List all events for an {account}",
|
||||||
|
"List all events for an {account} (or all accounts, if"
|
||||||
|
" no account specified) in {format}. Sorted by timestamp",
|
||||||
|
json_list_account_events
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *init(struct plugin *p, const char *b, const jsmntok_t *t)
|
static const char *init(struct plugin *p, const char *b, const jsmntok_t *t)
|
||||||
|
|||||||
@@ -97,6 +97,33 @@ static struct channel_event *stmt2channel_event(const tal_t *ctx, struct db_stmt
|
|||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct chain_event **list_chain_events(const tal_t *ctx, struct db *db)
|
||||||
|
{
|
||||||
|
struct db_stmt *stmt;
|
||||||
|
|
||||||
|
stmt = db_prepare_v2(db, SQL("SELECT"
|
||||||
|
" e.id"
|
||||||
|
", e.account_id"
|
||||||
|
", a.name"
|
||||||
|
", e.tag"
|
||||||
|
", e.credit"
|
||||||
|
", e.debit"
|
||||||
|
", e.output_value"
|
||||||
|
", e.currency"
|
||||||
|
", e.timestamp"
|
||||||
|
", e.blockheight"
|
||||||
|
", e.utxo_txid"
|
||||||
|
", e.outnum"
|
||||||
|
", e.spending_txid"
|
||||||
|
", e.payment_id"
|
||||||
|
" FROM chain_events e"
|
||||||
|
" LEFT OUTER JOIN accounts a"
|
||||||
|
" ON e.account_id = a.id"
|
||||||
|
" ORDER BY e.timestamp, e.id;"));
|
||||||
|
|
||||||
|
return find_chain_events(ctx, take(stmt));
|
||||||
|
}
|
||||||
|
|
||||||
struct chain_event **account_get_chain_events(const tal_t *ctx,
|
struct chain_event **account_get_chain_events(const tal_t *ctx,
|
||||||
struct db *db,
|
struct db *db,
|
||||||
struct account *acct)
|
struct account *acct)
|
||||||
@@ -304,6 +331,40 @@ char *account_get_balance(const tal_t *ctx,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct channel_event **list_channel_events(const tal_t *ctx, struct db *db)
|
||||||
|
{
|
||||||
|
struct db_stmt *stmt;
|
||||||
|
struct channel_event **results;
|
||||||
|
|
||||||
|
stmt = db_prepare_v2(db, SQL("SELECT"
|
||||||
|
" e.id"
|
||||||
|
", e.account_id"
|
||||||
|
", a.name"
|
||||||
|
", e.tag"
|
||||||
|
", e.credit"
|
||||||
|
", e.debit"
|
||||||
|
", e.fees"
|
||||||
|
", e.currency"
|
||||||
|
", e.payment_id"
|
||||||
|
", e.part_id"
|
||||||
|
", e.timestamp"
|
||||||
|
" FROM channel_events e"
|
||||||
|
" LEFT OUTER JOIN accounts a"
|
||||||
|
" ON a.id = e.account_id"
|
||||||
|
" ORDER BY e.timestamp, e.id;"));
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
struct channel_event **account_get_channel_events(const tal_t *ctx,
|
struct channel_event **account_get_channel_events(const tal_t *ctx,
|
||||||
struct db *db,
|
struct db *db,
|
||||||
struct account *acct)
|
struct account *acct)
|
||||||
@@ -359,6 +420,43 @@ static struct onchain_fee *stmt2onchain_fee(const tal_t *ctx,
|
|||||||
return of;
|
return of;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct onchain_fee **account_get_chain_fees(const tal_t *ctx, struct db *db,
|
||||||
|
struct account *acct)
|
||||||
|
{
|
||||||
|
struct db_stmt *stmt;
|
||||||
|
struct onchain_fee **results;
|
||||||
|
|
||||||
|
stmt = db_prepare_v2(db, SQL("SELECT"
|
||||||
|
" of.account_id"
|
||||||
|
", a.name"
|
||||||
|
", of.txid"
|
||||||
|
", of.credit"
|
||||||
|
", of.debit"
|
||||||
|
", of.currency"
|
||||||
|
", of.timestamp"
|
||||||
|
", of.update_count"
|
||||||
|
" FROM onchain_fees of"
|
||||||
|
" LEFT OUTER JOIN accounts a"
|
||||||
|
" ON a.id = of.account_id"
|
||||||
|
" WHERE of.account_id = ?"
|
||||||
|
" ORDER BY "
|
||||||
|
" of.timestamp"
|
||||||
|
", of.txid"
|
||||||
|
", of.update_count"));
|
||||||
|
|
||||||
|
db_bind_u64(stmt, 0, acct->db_id);
|
||||||
|
db_query_prepared(stmt);
|
||||||
|
|
||||||
|
results = tal_arr(ctx, struct onchain_fee *, 0);
|
||||||
|
while (db_step(stmt)) {
|
||||||
|
struct onchain_fee *of = stmt2onchain_fee(results, stmt);
|
||||||
|
tal_arr_expand(&results, of);
|
||||||
|
}
|
||||||
|
tal_free(stmt);
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
struct onchain_fee **list_chain_fees(const tal_t *ctx, struct db *db)
|
struct onchain_fee **list_chain_fees(const tal_t *ctx, struct db *db)
|
||||||
{
|
{
|
||||||
struct db_stmt *stmt;
|
struct db_stmt *stmt;
|
||||||
|
|||||||
@@ -32,10 +32,17 @@ struct channel_event **account_get_channel_events(const tal_t *ctx,
|
|||||||
struct db *db,
|
struct db *db,
|
||||||
struct account *acct);
|
struct account *acct);
|
||||||
|
|
||||||
|
/* Get all channel events, ordered by timestamp */
|
||||||
|
struct channel_event **list_channel_events(const tal_t *ctx, struct db *db);
|
||||||
|
|
||||||
/* Get all chain events for this account */
|
/* Get all chain events for this account */
|
||||||
struct chain_event **account_get_chain_events(const tal_t *ctx,
|
struct chain_event **account_get_chain_events(const tal_t *ctx,
|
||||||
struct db *db,
|
struct db *db,
|
||||||
struct account *acct);
|
struct account *acct);
|
||||||
|
|
||||||
|
/* Get all chain events, ordered by timestamp */
|
||||||
|
struct chain_event **list_chain_events(const tal_t *ctx, struct db *db);
|
||||||
|
|
||||||
/* Calculate the balances for an account
|
/* Calculate the balances for an account
|
||||||
*
|
*
|
||||||
* @calc_sum - compute the total balance. error if negative
|
* @calc_sum - compute the total balance. error if negative
|
||||||
@@ -46,6 +53,10 @@ char *account_get_balance(const tal_t *ctx,
|
|||||||
bool calc_sum,
|
bool calc_sum,
|
||||||
struct acct_balance ***balances);
|
struct acct_balance ***balances);
|
||||||
|
|
||||||
|
/* Get chain fees for account */
|
||||||
|
struct onchain_fee **account_get_chain_fees(const tal_t *ctx, struct db *db,
|
||||||
|
struct account *acct);
|
||||||
|
|
||||||
/* List all chain fees, for all accounts */
|
/* List all chain fees, for all accounts */
|
||||||
struct onchain_fee **list_chain_fees(const tal_t *ctx, struct db *db);
|
struct onchain_fee **list_chain_fees(const tal_t *ctx, struct db *db);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user