Basically, `devtools/reduce-includes.sh */*.c`. Build time from make clean (RUST=0) (includes building external libs): Before: real 0m38.944000-40.416000(40.1131+/-0.4)s user 3m6.790000-17.159000(15.0571+/-2.8)s sys 0m35.304000-37.336000(36.8942+/-0.57)s After: real 0m37.872000-39.974000(39.5466+/-0.59)s user 3m1.211000-14.968000(12.4556+/-3.9)s sys 0m35.008000-36.830000(36.4143+/-0.5)s Build time after touch config.vars (RUST=0): Before: real 0m19.831000-21.862000(21.5528+/-0.58)s user 2m15.361000-30.731000(28.4798+/-4.4)s sys 0m21.056000-22.339000(22.0346+/-0.35)s After: real 0m18.384000-21.307000(20.8605+/-0.92)s user 2m5.585000-26.843000(23.6017+/-6.7)s sys 0m19.650000-22.003000(21.4943+/-0.69)s Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
496 lines
15 KiB
C
496 lines
15 KiB
C
#include "config.h"
|
|
#include <ccan/tal/str/str.h>
|
|
#include <common/json_command.h>
|
|
#include <lightningd/channel.h>
|
|
#include <lightningd/coin_mvts.h>
|
|
#include <lightningd/notification.h>
|
|
|
|
|
|
struct channel_coin_mvt *new_channel_mvt_invoice_hin(const tal_t *ctx,
|
|
const struct htlc_in *hin,
|
|
const struct channel *channel)
|
|
{
|
|
return new_channel_coin_mvt(ctx, channel, time_now().ts.tv_sec,
|
|
&hin->payment_hash, NULL, NULL,
|
|
COIN_CREDIT, hin->msat,
|
|
mk_mvt_tags(MVT_INVOICE),
|
|
AMOUNT_MSAT(0));
|
|
}
|
|
|
|
struct channel_coin_mvt *new_channel_mvt_routed_hin(const tal_t *ctx,
|
|
const struct htlc_in *hin,
|
|
const struct channel *channel)
|
|
{
|
|
struct amount_msat fees_collected;
|
|
|
|
if (!hin->payload)
|
|
return NULL;
|
|
|
|
if (!amount_msat_sub(&fees_collected, hin->msat,
|
|
hin->payload->amt_to_forward))
|
|
return NULL;
|
|
|
|
return new_channel_coin_mvt(ctx, channel, time_now().ts.tv_sec,
|
|
&hin->payment_hash, NULL, NULL,
|
|
COIN_CREDIT, hin->msat,
|
|
mk_mvt_tags(MVT_ROUTED),
|
|
fees_collected);
|
|
}
|
|
|
|
struct channel_coin_mvt *new_channel_mvt_invoice_hout(const tal_t *ctx,
|
|
const struct htlc_out *hout,
|
|
const struct channel *channel)
|
|
{
|
|
return new_channel_coin_mvt(ctx, channel, time_now().ts.tv_sec,
|
|
&hout->payment_hash,
|
|
&hout->partid,
|
|
&hout->groupid,
|
|
COIN_DEBIT, hout->msat,
|
|
mk_mvt_tags(MVT_INVOICE),
|
|
hout->fees);
|
|
}
|
|
|
|
struct channel_coin_mvt *new_channel_mvt_routed_hout(const tal_t *ctx,
|
|
const struct htlc_out *hout,
|
|
const struct channel *channel)
|
|
{
|
|
return new_channel_coin_mvt(ctx, channel, time_now().ts.tv_sec,
|
|
&hout->payment_hash, NULL, NULL,
|
|
COIN_DEBIT, hout->msat,
|
|
mk_mvt_tags(MVT_ROUTED),
|
|
hout->fees);
|
|
}
|
|
|
|
struct channel_coin_mvt *new_channel_mvt_penalty_adj(const tal_t *ctx,
|
|
const struct channel *channel,
|
|
struct amount_msat amount,
|
|
enum coin_mvt_dir direction)
|
|
{
|
|
return new_channel_coin_mvt(ctx, channel, time_now().ts.tv_sec,
|
|
NULL, NULL, NULL,
|
|
direction, amount,
|
|
mk_mvt_tags(MVT_PENALTY_ADJ),
|
|
AMOUNT_MSAT(0));
|
|
}
|
|
|
|
static bool report_chan_balance(const struct channel *chan)
|
|
{
|
|
switch (chan->state) {
|
|
case CHANNELD_AWAITING_LOCKIN:
|
|
case DUALOPEND_OPEN_INIT:
|
|
case DUALOPEND_OPEN_COMMIT_READY:
|
|
case DUALOPEND_OPEN_COMMITTED:
|
|
case DUALOPEND_AWAITING_LOCKIN:
|
|
case CLOSINGD_COMPLETE:
|
|
case AWAITING_UNILATERAL:
|
|
case ONCHAIN:
|
|
case CLOSED:
|
|
return false;
|
|
|
|
case CHANNELD_NORMAL:
|
|
case CHANNELD_AWAITING_SPLICE:
|
|
case CHANNELD_SHUTTING_DOWN:
|
|
case CLOSINGD_SIGEXCHANGE:
|
|
case FUNDING_SPEND_SEEN:
|
|
return true;
|
|
}
|
|
abort();
|
|
}
|
|
|
|
void send_account_balance_snapshot(struct lightningd *ld)
|
|
{
|
|
struct balance_snapshot *snap = tal(NULL, struct balance_snapshot);
|
|
struct account_balance *bal;
|
|
struct utxo **utxos;
|
|
struct channel *chan;
|
|
struct peer *p;
|
|
struct peer_node_id_map_iter it;
|
|
|
|
snap->blockheight = get_block_height(ld->topology);
|
|
snap->timestamp = time_now().ts.tv_sec;
|
|
snap->node_id = &ld->our_nodeid;
|
|
|
|
/* Add the 'wallet' account balance */
|
|
snap->accts = tal_arr(snap, struct account_balance *, 1);
|
|
bal = tal(snap, struct account_balance);
|
|
bal->balance = AMOUNT_MSAT(0);
|
|
bal->acct_id = ACCOUNT_NAME_WALLET;
|
|
bal->bip173_name = chainparams->lightning_hrp;
|
|
|
|
utxos = wallet_get_unspent_utxos(NULL, ld->wallet);
|
|
for (size_t j = 0; j < tal_count(utxos); j++) {
|
|
/* Don't count unconfirmed utxos! */
|
|
if (!utxos[j]->spendheight && !utxos[j]->blockheight)
|
|
continue;
|
|
if (!amount_msat_add_sat(&bal->balance,
|
|
bal->balance, utxos[j]->amount))
|
|
fatal("Overflow adding node balance");
|
|
}
|
|
tal_free(utxos);
|
|
|
|
snap->accts[0] = bal;
|
|
|
|
/* Add channel balances */
|
|
for (p = peer_node_id_map_first(ld->peers, &it);
|
|
p;
|
|
p = peer_node_id_map_next(ld->peers, &it)) {
|
|
list_for_each(&p->channels, chan, list) {
|
|
if (report_chan_balance(chan)) {
|
|
bal = tal(snap, struct account_balance);
|
|
bal->bip173_name = chainparams->lightning_hrp;
|
|
bal->acct_id = fmt_channel_id(bal, &chan->cid);
|
|
bal->balance = chan->our_msat;
|
|
tal_arr_expand(&snap->accts, bal);
|
|
}
|
|
}
|
|
}
|
|
|
|
notify_balance_snapshot(ld, snap);
|
|
tal_free(snap);
|
|
}
|
|
|
|
static void add_movement_tags(struct json_stream *stream,
|
|
bool include_tags_arr,
|
|
const struct mvt_tags tags,
|
|
bool extra_tags_field)
|
|
{
|
|
const char **tagstrs = mvt_tag_strs(tmpctx, tags);
|
|
|
|
if (include_tags_arr) {
|
|
json_array_start(stream, "tags");
|
|
for (size_t i = 0; i < tal_count(tagstrs); i++)
|
|
json_add_string(stream, NULL, tagstrs[i]);
|
|
json_array_end(stream);
|
|
}
|
|
|
|
json_add_string(stream, "primary_tag", tagstrs[0]);
|
|
if (extra_tags_field) {
|
|
json_array_start(stream, "extra_tags");
|
|
for (size_t i = 1; i < tal_count(tagstrs); i++)
|
|
json_add_string(stream, NULL, tagstrs[i]);
|
|
json_array_end(stream);
|
|
} else {
|
|
assert(tal_count(tagstrs) == 1);
|
|
}
|
|
}
|
|
|
|
static void json_add_mvt_account_id(struct json_stream *stream,
|
|
const char *fieldname,
|
|
const struct mvt_account_id *account_id)
|
|
{
|
|
if (account_id->channel)
|
|
json_add_channel_id(stream, fieldname, &account_id->channel->cid);
|
|
else
|
|
json_add_string(stream, fieldname, account_id->alt_account);
|
|
}
|
|
|
|
void json_add_chain_mvt_fields(struct json_stream *stream,
|
|
bool include_tags_arr,
|
|
bool include_old_utxo_fields,
|
|
bool include_old_txid_field,
|
|
const struct chain_coin_mvt *chain_mvt,
|
|
u64 id)
|
|
{
|
|
/* Fields in common with channel moves go first */
|
|
json_add_u64(stream, "created_index", id);
|
|
json_add_mvt_account_id(stream, "account_id", &chain_mvt->account);
|
|
json_add_amount_msat(stream, "credit_msat", chain_mvt->credit);
|
|
json_add_amount_msat(stream, "debit_msat", chain_mvt->debit);
|
|
json_add_u64(stream, "timestamp", chain_mvt->timestamp);
|
|
add_movement_tags(stream, include_tags_arr, chain_mvt->tags, true);
|
|
|
|
json_add_outpoint(stream, "utxo", &chain_mvt->outpoint);
|
|
if (chain_mvt->peer_id)
|
|
json_add_node_id(stream, "peer_id", chain_mvt->peer_id);
|
|
|
|
if (chain_mvt->originating_acct)
|
|
json_add_mvt_account_id(stream, "originating_account", chain_mvt->originating_acct);
|
|
|
|
if (chain_mvt->spending_txid) {
|
|
if (include_old_txid_field)
|
|
json_add_txid(stream, "txid",
|
|
chain_mvt->spending_txid);
|
|
json_add_txid(stream, "spending_txid", chain_mvt->spending_txid);
|
|
}
|
|
|
|
if (include_old_utxo_fields) {
|
|
json_add_string(stream, "utxo_txid",
|
|
fmt_bitcoin_txid(tmpctx,
|
|
&chain_mvt->outpoint.txid));
|
|
json_add_u32(stream, "vout", chain_mvt->outpoint.n);
|
|
}
|
|
|
|
/* on-chain htlcs include a payment hash */
|
|
if (chain_mvt->payment_hash)
|
|
json_add_sha256(stream, "payment_hash", chain_mvt->payment_hash);
|
|
json_add_amount_sat_msat(stream,
|
|
"output_msat", chain_mvt->output_val);
|
|
if (chain_mvt->output_count > 0)
|
|
json_add_num(stream, "output_count", chain_mvt->output_count);
|
|
|
|
json_add_u32(stream, "blockheight", chain_mvt->blockheight);
|
|
}
|
|
|
|
void json_add_channel_mvt_fields(struct json_stream *stream,
|
|
bool include_tags_arr,
|
|
const struct channel_coin_mvt *chan_mvt,
|
|
u64 id,
|
|
bool extra_tags_field)
|
|
{
|
|
/* Fields in common with chain moves go first */
|
|
json_add_u64(stream, "created_index", id);
|
|
json_add_mvt_account_id(stream, "account_id", &chan_mvt->account);
|
|
json_add_amount_msat(stream, "credit_msat", chan_mvt->credit);
|
|
json_add_amount_msat(stream, "debit_msat", chan_mvt->debit);
|
|
json_add_u64(stream, "timestamp", chan_mvt->timestamp);
|
|
add_movement_tags(stream, include_tags_arr, chan_mvt->tags, extra_tags_field);
|
|
|
|
/* push funding / leases don't have a payment_hash */
|
|
if (chan_mvt->payment_hash)
|
|
json_add_sha256(stream, "payment_hash", chan_mvt->payment_hash);
|
|
if (chan_mvt->part_and_group) {
|
|
json_add_u64(stream, "part_id", chan_mvt->part_and_group->part_id);
|
|
json_add_u64(stream, "group_id", chan_mvt->part_and_group->group_id);
|
|
}
|
|
json_add_amount_msat(stream, "fees_msat", chan_mvt->fees);
|
|
}
|
|
|
|
static u64 coinmvt_index_inc(struct lightningd *ld,
|
|
struct db *db,
|
|
enum wait_subsystem subsys,
|
|
const struct mvt_account_id *account,
|
|
struct amount_msat credit,
|
|
struct amount_msat debit,
|
|
enum wait_index idx)
|
|
{
|
|
return wait_index_increment(ld, db, subsys, idx,
|
|
"account", account->channel ? fmt_channel_id(tmpctx, &account->channel->cid) : account->alt_account,
|
|
"=credit_msat", tal_fmt(tmpctx, "%"PRIu64, credit.millisatoshis), /* Raw: JSON output */
|
|
"=debit_msat", tal_fmt(tmpctx, "%"PRIu64, debit.millisatoshis), /* Raw: JSON output */
|
|
NULL);
|
|
}
|
|
|
|
u64 chain_mvt_index_created(struct lightningd *ld,
|
|
struct db *db,
|
|
const struct mvt_account_id *account,
|
|
struct amount_msat credit,
|
|
struct amount_msat debit)
|
|
{
|
|
return coinmvt_index_inc(ld, db, WAIT_SUBSYSTEM_CHAINMOVES,
|
|
account, credit, debit,
|
|
WAIT_INDEX_CREATED);
|
|
}
|
|
|
|
u64 channel_mvt_index_created(struct lightningd *ld,
|
|
struct db *db,
|
|
const struct mvt_account_id *account,
|
|
struct amount_msat credit,
|
|
struct amount_msat debit)
|
|
{
|
|
return coinmvt_index_inc(ld, db, WAIT_SUBSYSTEM_CHANNELMOVES,
|
|
account, credit, debit,
|
|
WAIT_INDEX_CREATED);
|
|
}
|
|
|
|
static struct command_result *json_listchainmoves(struct command *cmd,
|
|
const char *buffer,
|
|
const jsmntok_t *obj UNNEEDED,
|
|
const jsmntok_t *params)
|
|
{
|
|
struct json_stream *response;
|
|
struct db_stmt *stmt;
|
|
enum wait_index *listindex;
|
|
u64 *liststart;
|
|
u32 *listlimit;
|
|
|
|
if (!param(cmd, buffer, params,
|
|
p_opt("index", param_index, &listindex),
|
|
p_opt_def("start", param_u64, &liststart, 0),
|
|
p_opt("limit", param_u32, &listlimit),
|
|
NULL))
|
|
return command_param_failed();
|
|
|
|
if (*liststart != 0 && !listindex) {
|
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
|
"Can only specify {start} with {index}");
|
|
}
|
|
if (listlimit && !listindex) {
|
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
|
"Can only specify {limit} with {index}");
|
|
}
|
|
if (listindex && *listindex != WAIT_INDEX_CREATED) {
|
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
|
"index must be 'created', since chainmoves are never updated");
|
|
}
|
|
response = json_stream_success(cmd);
|
|
json_array_start(response, "chainmoves");
|
|
for (stmt = wallet_chain_moves_first(cmd->ld->wallet, *liststart, listlimit);
|
|
stmt;
|
|
stmt = wallet_chain_moves_next(cmd->ld->wallet, stmt)) {
|
|
struct chain_coin_mvt *chain_mvt;
|
|
u64 id;
|
|
chain_mvt = wallet_chain_move_extract(cmd, stmt, cmd->ld, &id);
|
|
json_object_start(response, NULL);
|
|
json_add_chain_mvt_fields(response, false, false, false, chain_mvt, id);
|
|
json_object_end(response);
|
|
}
|
|
json_array_end(response);
|
|
|
|
return command_success(cmd, response);
|
|
}
|
|
static const struct json_command listchainmoves_command = {
|
|
"listchainmoves",
|
|
json_listchainmoves,
|
|
};
|
|
AUTODATA(json_command, &listchainmoves_command);
|
|
|
|
static struct command_result *json_listchannelmoves(struct command *cmd,
|
|
const char *buffer,
|
|
const jsmntok_t *obj UNNEEDED,
|
|
const jsmntok_t *params)
|
|
{
|
|
struct json_stream *response;
|
|
struct db_stmt *stmt;
|
|
enum wait_index *listindex;
|
|
u64 *liststart;
|
|
u32 *listlimit;
|
|
|
|
if (!param(cmd, buffer, params,
|
|
p_opt("index", param_index, &listindex),
|
|
p_opt_def("start", param_u64, &liststart, 0),
|
|
p_opt("limit", param_u32, &listlimit),
|
|
NULL))
|
|
return command_param_failed();
|
|
|
|
if (*liststart != 0 && !listindex) {
|
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
|
"Can only specify {start} with {index}");
|
|
}
|
|
if (listlimit && !listindex) {
|
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
|
"Can only specify {limit} with {index}");
|
|
}
|
|
if (listindex && *listindex != WAIT_INDEX_CREATED) {
|
|
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
|
"index must be 'created', since channelmoves are never updated");
|
|
}
|
|
|
|
response = json_stream_success(cmd);
|
|
json_array_start(response, "channelmoves");
|
|
for (stmt = wallet_channel_moves_first(cmd->ld->wallet, *liststart, listlimit);
|
|
stmt;
|
|
stmt = wallet_channel_moves_next(cmd->ld->wallet, stmt)) {
|
|
struct channel_coin_mvt *chan_mvt;
|
|
u64 id;
|
|
chan_mvt = wallet_channel_move_extract(cmd, stmt, cmd->ld, &id);
|
|
json_object_start(response, NULL);
|
|
/* No deprecated tags[], no extra_tags field */
|
|
json_add_channel_mvt_fields(response, false, chan_mvt, id, false);
|
|
json_object_end(response);
|
|
}
|
|
json_array_end(response);
|
|
|
|
return command_success(cmd, response);
|
|
}
|
|
static const struct json_command listchannelmoves_command = {
|
|
"listchannelmoves",
|
|
json_listchannelmoves,
|
|
};
|
|
AUTODATA(json_command, &listchannelmoves_command);
|
|
|
|
static struct command_result *param_msat_as_sat(struct command *cmd,
|
|
const char *name,
|
|
const char *buffer,
|
|
const jsmntok_t *tok,
|
|
struct amount_sat **sat)
|
|
{
|
|
struct amount_msat msat;
|
|
|
|
*sat = tal(cmd, struct amount_sat);
|
|
if (parse_amount_msat(&msat, buffer + tok->start, tok->end - tok->start)
|
|
&& amount_msat_to_sat(*sat, msat))
|
|
return NULL;
|
|
|
|
return command_fail_badparam(cmd, name, buffer, tok,
|
|
"should be a millisatoshi amount");
|
|
}
|
|
|
|
/* Internal interfaces for bookkeeper.c.
|
|
* FIXME: handle utxo_deposit / utxo_spend notifications directly! */
|
|
static struct command_result *json_injectutxodeposit(struct command *cmd,
|
|
const char *buffer,
|
|
const jsmntok_t *obj UNNEEDED,
|
|
const jsmntok_t *params)
|
|
{
|
|
struct chain_coin_mvt *ev;
|
|
const char *account, *origin_acct;
|
|
struct bitcoin_outpoint *outpoint;
|
|
struct amount_sat *amount;
|
|
u64 *timestamp;
|
|
u32 *blockheight;
|
|
|
|
if (!param(cmd, buffer, params,
|
|
p_req("account", param_string, &account),
|
|
p_req("outpoint", param_outpoint, &outpoint),
|
|
p_req("amount_msat", param_msat_as_sat, &amount),
|
|
p_req("timestamp", param_u64, ×tamp),
|
|
p_req("blockheight", param_u32, &blockheight),
|
|
p_opt("transfer_from", param_string, &origin_acct),
|
|
NULL))
|
|
return command_param_failed();
|
|
|
|
ev = new_foreign_deposit(cmd, outpoint, *blockheight, *amount,
|
|
account, *timestamp);
|
|
if (origin_acct) {
|
|
/* Need temporary because originating_acct is const */
|
|
struct mvt_account_id *acct;
|
|
ev->originating_acct = acct = tal(ev, struct mvt_account_id);
|
|
acct->channel = NULL;
|
|
acct->alt_account = tal_strdup(acct, origin_acct);
|
|
}
|
|
wallet_save_chain_mvt(cmd->ld, ev);
|
|
|
|
return command_success(cmd, json_stream_success(cmd));
|
|
}
|
|
static const struct json_command injectutxodeposit_command = {
|
|
"injectutxodeposit",
|
|
json_injectutxodeposit,
|
|
};
|
|
AUTODATA(json_command, &injectutxodeposit_command);
|
|
|
|
static struct command_result *json_injectutxospend(struct command *cmd,
|
|
const char *buffer,
|
|
const jsmntok_t *obj UNNEEDED,
|
|
const jsmntok_t *params)
|
|
{
|
|
struct chain_coin_mvt *ev;
|
|
const char *account;
|
|
struct bitcoin_txid *spending_txid;
|
|
struct bitcoin_outpoint *outpoint;
|
|
struct amount_sat *amount;
|
|
u64 *timestamp;
|
|
u32 *blockheight;
|
|
|
|
if (!param(cmd, buffer, params,
|
|
p_req("account", param_string, &account),
|
|
p_req("outpoint", param_outpoint, &outpoint),
|
|
p_req("spending_txid", param_txid, &spending_txid),
|
|
p_req("amount_msat", param_msat_as_sat, &amount),
|
|
p_req("timestamp", param_u64, ×tamp),
|
|
p_req("blockheight", param_u32, &blockheight),
|
|
NULL))
|
|
return command_param_failed();
|
|
|
|
ev = new_foreign_withdrawal(cmd, outpoint, spending_txid,
|
|
*amount, *blockheight, account, *timestamp);
|
|
wallet_save_chain_mvt(cmd->ld, ev);
|
|
|
|
return command_success(cmd, json_stream_success(cmd));
|
|
}
|
|
static const struct json_command injectutxospend_command = {
|
|
"injectutxospend",
|
|
json_injectutxospend,
|
|
};
|
|
AUTODATA(json_command, &injectutxospend_command);
|
|
|