#include "config.h" #include #include #include #include #include #include #include #include #define EXTERNAL "external" static const char *mvt_types[] = { "chain_mvt", "channel_mvt" }; const char *mvt_type_str(enum mvt_type type) { return mvt_types[type]; } static const char *mvt_tags[] = { "deposit", "withdrawal", "penalty", "invoice", "routed", "pushed", "channel_open", "channel_close", "delayed_to_us", "htlc_timeout", "htlc_fulfill", "htlc_tx", "to_wallet", "ignored", "anchor", "to_them", "penalized", "stolen", "to_miner", "opener", "lease_fee", "leased", }; const char *mvt_tag_str(enum mvt_tag tag) { return mvt_tags[tag]; } enum mvt_tag *new_tag_arr(const tal_t *ctx, enum mvt_tag tag) { enum mvt_tag *tags = tal_arr(ctx, enum mvt_tag, 1); tags[0] = tag; return tags; } struct channel_coin_mvt *new_channel_coin_mvt(const tal_t *ctx, const struct channel_id *cid, const struct sha256 *payment_hash TAKES, u64 *part_id TAKES, struct amount_msat amount, const enum mvt_tag *tags TAKES, bool is_credit, struct amount_msat fees) { struct channel_coin_mvt *mvt = tal(ctx, struct channel_coin_mvt); mvt->chan_id = *cid; mvt->payment_hash = tal_dup_or_null(mvt, struct sha256, payment_hash); mvt->part_id = tal_dup_or_null(mvt, u64, part_id); mvt->tags = tal_dup_talarr(mvt, enum mvt_tag, tags); if (is_credit) { mvt->credit = amount; mvt->debit = AMOUNT_MSAT(0); } else { mvt->debit = amount; mvt->credit = AMOUNT_MSAT(0); } mvt->fees = fees; return mvt; } static struct chain_coin_mvt *new_chain_coin_mvt(const tal_t *ctx, const char *account_name TAKES, const struct bitcoin_txid *tx_txid, const struct bitcoin_outpoint *outpoint, const struct sha256 *payment_hash TAKES, u32 blockheight, enum mvt_tag *tags TAKES, struct amount_msat amount, bool is_credit, struct amount_sat output_val, u32 out_count) { struct chain_coin_mvt *mvt = tal(ctx, struct chain_coin_mvt); if (account_name) mvt->account_name = tal_strdup(mvt, account_name); else mvt->account_name = NULL; mvt->tx_txid = tx_txid; mvt->outpoint = outpoint; mvt->originating_acct = NULL; /* for htlc's that are filled onchain, we also have a * preimage, NULL otherwise */ mvt->payment_hash = tal_dup_or_null(mvt, struct sha256, payment_hash); mvt->blockheight = blockheight; mvt->tags = tal_dup_talarr(mvt, enum mvt_tag, tags); if (is_credit) { mvt->credit = amount; mvt->debit = AMOUNT_MSAT(0); } else { mvt->debit = amount; mvt->credit = AMOUNT_MSAT(0); } mvt->output_val = output_val; mvt->output_count = out_count; return mvt; } static struct chain_coin_mvt *new_chain_coin_mvt_sat(const tal_t *ctx, const char *account_name, const struct bitcoin_txid *tx_txid, const struct bitcoin_outpoint *outpoint, const struct sha256 *payment_hash TAKES, u32 blockheight, enum mvt_tag *tags TAKES, struct amount_sat amt_sat, bool is_credit) { struct amount_msat amt_msat; bool ok; ok = amount_sat_to_msat(&amt_msat, amt_sat); assert(ok); return new_chain_coin_mvt(ctx, account_name, tx_txid, outpoint, payment_hash, blockheight, tags, amt_msat, is_credit, /* All amounts that are sat are * on-chain output values */ amt_sat, 0); } struct chain_coin_mvt *new_onchaind_withdraw(const tal_t *ctx, const struct bitcoin_outpoint *outpoint, const struct bitcoin_txid *spend_txid, u32 blockheight, struct amount_sat amount, enum mvt_tag tag) { return new_chain_coin_mvt_sat(ctx, NULL, spend_txid, outpoint, NULL, blockheight, take(new_tag_arr(NULL, tag)), amount, false); } struct chain_coin_mvt *new_onchaind_deposit(const tal_t *ctx, const struct bitcoin_outpoint *outpoint, u32 blockheight, struct amount_sat amount, enum mvt_tag tag) { return new_chain_coin_mvt_sat(ctx, NULL, NULL, outpoint, NULL, blockheight, take(new_tag_arr(NULL, tag)), amount, true); } struct chain_coin_mvt *new_coin_channel_close(const tal_t *ctx, const struct bitcoin_txid *txid, const struct bitcoin_outpoint *out, u32 blockheight, const struct amount_msat amount, const struct amount_sat output_val, u32 output_count) { return new_chain_coin_mvt(ctx, NULL, txid, out, NULL, blockheight, take(new_tag_arr(NULL, CHANNEL_CLOSE)), amount, false, output_val, output_count); } struct chain_coin_mvt *new_coin_channel_open(const tal_t *ctx, const struct channel_id *chan_id, const struct bitcoin_outpoint *out, u32 blockheight, const struct amount_msat amount, const struct amount_sat output_val, bool is_opener, bool is_leased) { struct chain_coin_mvt *mvt; mvt = new_chain_coin_mvt(ctx, NULL, NULL, out, NULL, blockheight, take(new_tag_arr(NULL, CHANNEL_OPEN)), amount, true, output_val, 0); mvt->account_name = type_to_string(mvt, struct channel_id, chan_id); /* If we're the opener, add to the tag list */ if (is_opener) tal_arr_expand(&mvt->tags, OPENER); if (is_leased) tal_arr_expand(&mvt->tags, LEASED); return mvt; } struct chain_coin_mvt *new_onchain_htlc_deposit(const tal_t *ctx, const struct bitcoin_outpoint *outpoint, u32 blockheight, struct amount_sat amount, const struct sha256 *payment_hash) { return new_chain_coin_mvt_sat(ctx, NULL, NULL, outpoint, payment_hash, blockheight, take(new_tag_arr(NULL, HTLC_FULFILL)), amount, true); } struct chain_coin_mvt *new_onchain_htlc_withdraw(const tal_t *ctx, const struct bitcoin_outpoint *outpoint, u32 blockheight, struct amount_sat amount, const struct sha256 *payment_hash) { /* An onchain htlc fulfillment to peer is a *deposit* of * that output into their (external) account */ return new_chain_coin_mvt_sat(ctx, EXTERNAL, NULL, outpoint, payment_hash, blockheight, take(new_tag_arr(NULL, HTLC_FULFILL)), amount, true); } struct chain_coin_mvt *new_coin_external_spend(const tal_t *ctx, const struct bitcoin_outpoint *outpoint, const struct bitcoin_txid *txid, u32 blockheight, struct amount_sat amount, enum mvt_tag tag) { return new_chain_coin_mvt(ctx, EXTERNAL, txid, outpoint, NULL, blockheight, take(new_tag_arr(NULL, tag)), AMOUNT_MSAT(0), true, amount, 0); } struct chain_coin_mvt *new_coin_external_deposit(const tal_t *ctx, const struct bitcoin_outpoint *outpoint, u32 blockheight, struct amount_sat amount, enum mvt_tag tag) { return new_chain_coin_mvt_sat(ctx, EXTERNAL, NULL, outpoint, NULL, blockheight, take(new_tag_arr(NULL, tag)), amount, true); } bool chain_mvt_is_external(const struct chain_coin_mvt *mvt) { return streq(mvt->account_name, EXTERNAL); } struct chain_coin_mvt *new_coin_wallet_deposit(const tal_t *ctx, const struct bitcoin_outpoint *outpoint, u32 blockheight, struct amount_sat amount, enum mvt_tag tag) { return new_chain_coin_mvt_sat(ctx, WALLET, NULL, outpoint, NULL, blockheight, take(new_tag_arr(NULL, tag)), amount, true); } struct chain_coin_mvt *new_coin_wallet_withdraw(const tal_t *ctx, const struct bitcoin_txid *spend_txid, const struct bitcoin_outpoint *outpoint, u32 blockheight, struct amount_sat amount, enum mvt_tag tag) { return new_chain_coin_mvt_sat(ctx, WALLET, spend_txid, outpoint, NULL, blockheight, take(new_tag_arr(NULL, tag)), amount, false); } struct channel_coin_mvt *new_coin_channel_push(const tal_t *ctx, const struct channel_id *cid, struct amount_msat amount, enum mvt_tag tag, bool is_credit) { return new_channel_coin_mvt(ctx, cid, NULL, NULL, amount, take(new_tag_arr(NULL, tag)), is_credit, AMOUNT_MSAT(0)); } struct coin_mvt *finalize_chain_mvt(const tal_t *ctx, const struct chain_coin_mvt *chain_mvt, const char *hrp_name TAKES, u32 timestamp, struct node_id *node_id) { struct coin_mvt *mvt = tal(ctx, struct coin_mvt); mvt->account_id = tal_strdup(mvt, chain_mvt->account_name); if (chain_mvt->originating_acct) mvt->originating_acct = tal_strdup(mvt, chain_mvt->originating_acct); else mvt->originating_acct = NULL; mvt->hrp_name = tal_strdup(mvt, hrp_name); mvt->type = CHAIN_MVT; mvt->id.tx_txid = chain_mvt->tx_txid; mvt->id.outpoint = chain_mvt->outpoint; mvt->id.payment_hash = chain_mvt->payment_hash; mvt->tags = tal_steal(mvt, chain_mvt->tags); mvt->credit = chain_mvt->credit; mvt->debit = chain_mvt->debit; mvt->output_val = tal(mvt, struct amount_sat); *mvt->output_val = chain_mvt->output_val; mvt->output_count = chain_mvt->output_count; mvt->fees = NULL; mvt->timestamp = timestamp; mvt->blockheight = chain_mvt->blockheight; mvt->version = COIN_MVT_VERSION; mvt->node_id = node_id; return mvt; } struct coin_mvt *finalize_channel_mvt(const tal_t *ctx, const struct channel_coin_mvt *chan_mvt, const char *hrp_name TAKES, u32 timestamp, const struct node_id *node_id TAKES) { struct coin_mvt *mvt = tal(ctx, struct coin_mvt); mvt->account_id = type_to_string(mvt, struct channel_id, &chan_mvt->chan_id); /* channel moves don't have external events! */ mvt->originating_acct = NULL; mvt->hrp_name = tal_strdup(mvt, hrp_name); mvt->type = CHANNEL_MVT; mvt->id.payment_hash = chan_mvt->payment_hash; mvt->id.part_id = chan_mvt->part_id; mvt->id.tx_txid = NULL; mvt->id.outpoint = NULL; mvt->tags = tal_steal(mvt, chan_mvt->tags); mvt->credit = chan_mvt->credit; mvt->debit = chan_mvt->debit; mvt->output_val = NULL; mvt->output_count = 0; mvt->fees = tal(mvt, struct amount_msat); *mvt->fees = chan_mvt->fees; mvt->timestamp = timestamp; mvt->version = COIN_MVT_VERSION; mvt->node_id = tal_dup(mvt, struct node_id, node_id); return mvt; } void towire_chain_coin_mvt(u8 **pptr, const struct chain_coin_mvt *mvt) { if (mvt->account_name) { towire_bool(pptr, true); towire_wirestring(pptr, mvt->account_name); } else towire_bool(pptr, false); if (mvt->originating_acct) { towire_bool(pptr, true); towire_wirestring(pptr, mvt->originating_acct); } else towire_bool(pptr, false); towire_bitcoin_outpoint(pptr, mvt->outpoint); if (mvt->tx_txid) { towire_bool(pptr, true); towire_bitcoin_txid(pptr, cast_const(struct bitcoin_txid *, mvt->tx_txid)); } else towire_bool(pptr, false); if (mvt->payment_hash) { towire_bool(pptr, true); towire_sha256(pptr, mvt->payment_hash); } else towire_bool(pptr, false); towire_u32(pptr, mvt->blockheight); towire_u32(pptr, tal_count(mvt->tags)); for (size_t i = 0; i < tal_count(mvt->tags); i++) towire_u8(pptr, mvt->tags[i]); towire_amount_msat(pptr, mvt->credit); towire_amount_msat(pptr, mvt->debit); towire_amount_sat(pptr, mvt->output_val); towire_u32(pptr, mvt->output_count); } void fromwire_chain_coin_mvt(const u8 **cursor, size_t *max, struct chain_coin_mvt *mvt) { if (fromwire_bool(cursor, max)) { mvt->account_name = fromwire_wirestring(mvt, cursor, max); } else mvt->account_name = NULL; if (fromwire_bool(cursor, max)) { mvt->originating_acct = fromwire_wirestring(mvt, cursor, max); } else mvt->originating_acct = NULL; /* Read into non-const version */ struct bitcoin_outpoint *outpoint = tal(mvt, struct bitcoin_outpoint); fromwire_bitcoin_outpoint(cursor, max, outpoint); mvt->outpoint = outpoint; if (fromwire_bool(cursor, max)) { mvt->tx_txid = tal(mvt, struct bitcoin_txid); fromwire_bitcoin_txid(cursor, max, cast_const(struct bitcoin_txid *, mvt->tx_txid)); } else mvt->tx_txid = NULL; if (fromwire_bool(cursor, max)) { mvt->payment_hash = tal(mvt, struct sha256); fromwire_sha256(cursor, max, mvt->payment_hash); } else mvt->payment_hash = NULL; mvt->blockheight = fromwire_u32(cursor, max); u32 tags_len = fromwire_u32(cursor, max); mvt->tags = tal_arr(mvt, enum mvt_tag, tags_len); for (size_t i = 0; i < tags_len; i++) mvt->tags[i] = fromwire_u8(cursor, max); mvt->credit = fromwire_amount_msat(cursor, max); mvt->debit = fromwire_amount_msat(cursor, max); mvt->output_val = fromwire_amount_sat(cursor, max); mvt->output_count = fromwire_u32(cursor, max); }