mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 21:35:11 +01:00
json-rpc: Add listforwardings
command
This commit is contained in:
parent
6efdd5275c
commit
facd7d16aa
@ -428,6 +428,15 @@ class LightningRpc(UnixDomainSocketRpc):
|
||||
"""
|
||||
return self.call("listfunds")
|
||||
|
||||
def getroutestats(self, details=True):
|
||||
"""Get statistics about routed payments.
|
||||
|
||||
If @details is True, this'll include the individual forwarded
|
||||
payments.
|
||||
|
||||
"""
|
||||
return self.call("getroutestats", payload={'details': details})
|
||||
|
||||
def dev_rescan_outputs(self):
|
||||
"""
|
||||
Synchronize the state of our funds with bitcoind
|
||||
|
@ -1842,3 +1842,82 @@ static const struct json_command dev_ignore_htlcs = {
|
||||
};
|
||||
AUTODATA(json_command, &dev_ignore_htlcs);
|
||||
#endif /* DEVELOPER */
|
||||
|
||||
static void listforwardings_add_stats(struct json_result *response, struct wallet *wallet)
|
||||
{
|
||||
const struct forwarding_stats *stats;
|
||||
stats = wallet_forwarded_payments_stats(wallet, tmpctx);
|
||||
|
||||
json_object_start(response, "stats");
|
||||
json_object_start(response, "settled");
|
||||
json_add_num(response, "fee_msatoshis", stats->fee[FORWARD_SETTLED]);
|
||||
json_add_num(response, "count", stats->count[FORWARD_SETTLED]);
|
||||
json_add_num(response, "msatoshi", stats->msatoshi[FORWARD_SETTLED]);
|
||||
json_object_end(response);
|
||||
|
||||
json_object_start(response, "failed");
|
||||
json_add_num(response, "fee_msatoshis", stats->fee[FORWARD_FAILED]);
|
||||
json_add_num(response, "count", stats->count[FORWARD_FAILED]);
|
||||
json_add_num(response, "msatoshi", stats->msatoshi[FORWARD_FAILED]);
|
||||
json_object_end(response);
|
||||
|
||||
json_object_start(response, "pending");
|
||||
json_add_num(response, "fee_msatoshis", stats->fee[FORWARD_OFFERED]);
|
||||
json_add_num(response, "count", stats->count[FORWARD_FAILED]);
|
||||
json_add_num(response, "msatoshi", stats->msatoshi[FORWARD_FAILED]);
|
||||
json_object_end(response);
|
||||
json_object_end(response);
|
||||
|
||||
tal_free(stats);
|
||||
}
|
||||
|
||||
static void listforwardings_add_forwardings(struct json_result *response, struct wallet *wallet)
|
||||
{
|
||||
const struct forwarding *forwardings;
|
||||
forwardings = wallet_forwarded_payments_get(wallet, tmpctx);
|
||||
|
||||
json_array_start(response, "forwards");
|
||||
for (size_t i=0; i<tal_count(forwardings); i++) {
|
||||
const struct forwarding *cur = &forwardings[i];
|
||||
json_object_start(response, NULL);
|
||||
json_add_short_channel_id(response, "in_channel", &cur->channel_in);
|
||||
json_add_short_channel_id(response, "out_channel", &cur->channel_out);
|
||||
json_add_num(response, "in_msatoshi", cur->msatoshi_in);
|
||||
json_add_num(response, "out_msatoshi", cur->msatoshi_out);
|
||||
json_add_num(response, "fee", cur->fee);
|
||||
json_add_string(response, "status", forward_status_name(cur->status));
|
||||
json_object_end(response);
|
||||
}
|
||||
json_array_end(response);
|
||||
|
||||
tal_free(forwardings);
|
||||
}
|
||||
|
||||
static void json_getroutestats(struct command *cmd, const char *buffer,
|
||||
const jsmntok_t *params)
|
||||
{
|
||||
struct json_result *response = new_json_result(cmd);
|
||||
bool *details;
|
||||
|
||||
if (!param(cmd, buffer, params,
|
||||
p_opt_def("details", json_tok_bool, &details, true),
|
||||
NULL))
|
||||
return;
|
||||
|
||||
json_object_start(response, NULL);
|
||||
listforwardings_add_stats(response, cmd->ld->wallet);
|
||||
|
||||
if (*details)
|
||||
listforwardings_add_forwardings(response, cmd->ld->wallet);
|
||||
|
||||
json_object_end(response);
|
||||
|
||||
command_success(cmd, response);
|
||||
}
|
||||
|
||||
static const struct json_command getroutestats_command = {
|
||||
"getroutestats", json_getroutestats,
|
||||
"Get statistics about routed / forwarded payments", false,
|
||||
"Get statistics about routed payments, i.e., the ones we aren't the initiator or recipient, including a detailed list if {details} is true."
|
||||
};
|
||||
AUTODATA(json_command, &getroutestats_command);
|
||||
|
@ -985,7 +985,7 @@ def test_forward_stats(node_factory, bitcoind):
|
||||
hash) and l5 will keep the HTLC dangling by disconnecting.
|
||||
|
||||
"""
|
||||
amount = 10**4
|
||||
amount = 10**5
|
||||
l1, l2, l3 = node_factory.line_graph(3, announce=False)
|
||||
l4 = node_factory.get_node()
|
||||
l5 = node_factory.get_node(may_fail=True)
|
||||
@ -1046,3 +1046,7 @@ def test_forward_stats(node_factory, bitcoind):
|
||||
assert outchan['out_msatoshi_offered'] == outchan['out_msatoshi_fulfilled']
|
||||
|
||||
assert outchan['out_msatoshi_fulfilled'] < inchan['in_msatoshi_fulfilled']
|
||||
|
||||
stats = l2.rpc.getroutestats()
|
||||
|
||||
assert [f['status'] for f in stats['forwards']] == ['settled', 'failed', 'offered']
|
||||
|
@ -2430,3 +2430,63 @@ void wallet_forwarded_payment_add(struct wallet *w, const struct htlc_in *in,
|
||||
sqlite3_bind_int(stmt, 7, state);
|
||||
db_exec_prepared(w->db, stmt);
|
||||
}
|
||||
|
||||
const struct forwarding_stats *wallet_forwarded_payments_stats(struct wallet *w,
|
||||
const tal_t *ctx)
|
||||
{
|
||||
struct forwarding_stats *stats = talz(ctx, struct forwarding_stats);
|
||||
sqlite3_stmt *stmt;
|
||||
stmt = db_prepare(w->db,
|
||||
"SELECT"
|
||||
" state"
|
||||
", COUNT(*)"
|
||||
", SUM(out_msatoshi) as total"
|
||||
", SUM(in_msatoshi - out_msatoshi) as fee "
|
||||
"FROM forwarded_payments "
|
||||
"GROUP BY state;");
|
||||
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
enum forward_status state = sqlite3_column_int(stmt, 0);
|
||||
stats->count[state] = sqlite3_column_int64(stmt, 1);
|
||||
stats->msatoshi[state] = sqlite3_column_int64(stmt, 2);
|
||||
stats->fee[state] = sqlite3_column_int64(stmt, 3);
|
||||
}
|
||||
|
||||
db_stmt_done(stmt);
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
const struct forwarding *wallet_forwarded_payments_get(struct wallet *w,
|
||||
const tal_t *ctx)
|
||||
{
|
||||
struct forwarding *results = tal_arr(ctx, struct forwarding, 0);
|
||||
size_t count = 0;
|
||||
sqlite3_stmt *stmt;
|
||||
stmt = db_prepare(w->db,
|
||||
"SELECT"
|
||||
" f.state"
|
||||
", in_msatoshi"
|
||||
", out_msatoshi"
|
||||
", hin.payment_hash as payment_hash"
|
||||
", in_channel_scid"
|
||||
", out_channel_scid "
|
||||
"FROM forwarded_payments f "
|
||||
"LEFT JOIN channel_htlcs hin ON (f.in_htlc_id == hin.id)");
|
||||
|
||||
for (count=0; sqlite3_step(stmt) == SQLITE_ROW; count++) {
|
||||
tal_resize(&results, count+1);
|
||||
struct forwarding *cur = &results[count];
|
||||
cur->status = sqlite3_column_int(stmt, 0);
|
||||
cur->msatoshi_in = sqlite3_column_int64(stmt, 1);
|
||||
cur->msatoshi_out = sqlite3_column_int64(stmt, 2);
|
||||
cur->fee = cur->msatoshi_in - cur->msatoshi_out;
|
||||
sqlite3_column_sha256_double(stmt, 3, &cur->payment_hash);
|
||||
sqlite3_column_short_channel_id(stmt, 4, &cur->channel_in);
|
||||
sqlite3_column_short_channel_id(stmt, 5, &cur->channel_out);
|
||||
}
|
||||
|
||||
db_stmt_done(stmt);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
@ -146,6 +146,31 @@ static inline enum forward_status wallet_forward_status_in_db(enum forward_statu
|
||||
fatal("%s: %u is invalid", __func__, s);
|
||||
}
|
||||
|
||||
static inline const char* forward_status_name(enum forward_status status)
|
||||
{
|
||||
switch(status) {
|
||||
case FORWARD_OFFERED:
|
||||
return "offered";
|
||||
case FORWARD_SETTLED:
|
||||
return "settled";
|
||||
case FORWARD_FAILED:
|
||||
return "failed";
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
struct forwarding {
|
||||
struct short_channel_id channel_in, channel_out;
|
||||
u64 msatoshi_in, msatoshi_out, fee;
|
||||
struct sha256_double payment_hash;
|
||||
enum forward_status status;
|
||||
};
|
||||
|
||||
struct forwarding_stats {
|
||||
/* One entry for each of the forward_statuses */
|
||||
u64 count[3], msatoshi[3], fee[3];
|
||||
};
|
||||
|
||||
/* A database backed shachain struct. The datastructure is
|
||||
* writethrough, reads are performed from an in-memory version, all
|
||||
* writes are passed through to the DB. */
|
||||
@ -995,8 +1020,22 @@ u32 *wallet_onchaind_channels(struct wallet *w,
|
||||
struct channeltx *wallet_channeltxs_get(struct wallet *w, const tal_t *ctx,
|
||||
u32 channel_id);
|
||||
|
||||
/**
|
||||
* Add of update a forwarded_payment
|
||||
*/
|
||||
void wallet_forwarded_payment_add(struct wallet *w, const struct htlc_in *in,
|
||||
const struct htlc_out *out,
|
||||
enum forward_status state);
|
||||
|
||||
/**
|
||||
* Retrieve global stats about all forwarded_payments
|
||||
*/
|
||||
const struct forwarding_stats *wallet_forwarded_payments_stats(struct wallet *w,
|
||||
const tal_t *ctx);
|
||||
|
||||
/**
|
||||
* Retrieve a list of all forwarded_payments
|
||||
*/
|
||||
const struct forwarding *wallet_forwarded_payments_get(struct wallet *w,
|
||||
const tal_t *ctx);
|
||||
#endif /* LIGHTNING_WALLET_WALLET_H */
|
||||
|
Loading…
Reference in New Issue
Block a user