Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

coin_movement updates #5019

Merged
merged 4 commits into from
Jan 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 27 additions & 5 deletions common/coin_mvt.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ static struct chain_coin_mvt *new_chain_coin_mvt(const tal_t *ctx,

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 */
Expand Down Expand Up @@ -260,11 +261,14 @@ struct chain_coin_mvt *new_coin_external_deposit(const tal_t *ctx,
struct amount_sat amount,
enum mvt_tag tag)
{
return new_chain_coin_mvt(ctx, EXTERNAL, NULL,
outpoint, NULL,
blockheight,
take(new_tag_arr(NULL, tag)),
AMOUNT_MSAT(0), true, amount);
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,
Expand Down Expand Up @@ -327,6 +331,11 @@ struct coin_mvt *finalize_chain_mvt(const tal_t *ctx,
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;

Expand Down Expand Up @@ -359,6 +368,8 @@ struct coin_mvt *finalize_channel_mvt(const tal_t *ctx,

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;
Expand Down Expand Up @@ -388,6 +399,12 @@ void towire_chain_coin_mvt(u8 **pptr, const struct chain_coin_mvt *mvt)
} 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) {
Expand Down Expand Up @@ -419,6 +436,11 @@ void fromwire_chain_coin_mvt(const u8 **cursor, size_t *max, struct chain_coin_m
} 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);
Expand Down
10 changes: 10 additions & 0 deletions common/coin_mvt.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ struct chain_coin_mvt {

/* total value of output (useful for tracking external outs) */
struct amount_sat output_val;

/* When we pay to external accounts, it's useful
* to track which internal account it originated from */
const char *originating_acct;
};

/* differs depending on type!? */
Expand All @@ -97,6 +101,9 @@ struct coin_mvt {
/* name of 'account': wallet, external, <channel_id> */
const char *account_id;

/* if account_id is external, the account this 'impacted' */
const char *originating_acct;

/* Chain name: BIP 173, except signet lightning-style: tbs not tb */
const char *hrp_name;

Expand Down Expand Up @@ -249,6 +256,9 @@ struct coin_mvt *finalize_channel_mvt(const tal_t *ctx,
const struct node_id *node_id)
NON_NULL_ARGS(2, 3, 5);

/* Is this an xternal account? */
bool chain_mvt_is_external(const struct chain_coin_mvt *mvt);

const char *mvt_type_str(enum mvt_type type);
const char *mvt_tag_str(enum mvt_tag tag);

Expand Down
17 changes: 17 additions & 0 deletions common/psbt_open.c
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,23 @@ bool psbt_has_our_input(const struct wally_psbt *psbt)
return false;
}

void psbt_output_mark_as_external(const tal_t *ctx,
struct wally_psbt_output *output)
{
u8 *key = psbt_make_key(tmpctx, PSBT_TYPE_OUTPUT_EXTERNAL, NULL);
beint16_t bev = cpu_to_be16(1);

psbt_output_set_unknown(ctx, output, key, &bev, sizeof(bev));
}

bool psbt_output_to_external(const struct wally_psbt_output *output)
{
size_t unused;
void *result = psbt_get_lightning(&output->unknowns,
PSBT_TYPE_OUTPUT_EXTERNAL, &unused);
return !(!result);
}

bool psbt_contribs_changed(struct wally_psbt *orig,
struct wally_psbt *new)
{
Expand Down
12 changes: 12 additions & 0 deletions common/psbt_open.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ struct psbt_changeset {

#define PSBT_TYPE_SERIAL_ID 0x01
#define PSBT_TYPE_INPUT_MARKER 0x02
#define PSBT_TYPE_OUTPUT_EXTERNAL 0x04

/* psbt_get_serial_id - Returns the serial_id from an unknowns map
*
Expand Down Expand Up @@ -177,6 +178,17 @@ bool psbt_input_is_ours(const struct wally_psbt_input *input);
*/
bool psbt_has_our_input(const struct wally_psbt *psbt);

/* psbt_output_mark_external - Marks an output as a deposit to
* an external address.
* Used when withdrawing from internal
* wallet */
void psbt_output_mark_as_external(const tal_t *ctx,
struct wally_psbt_output *output);

/* psbt_output_to_external - Is this an output we're paying to an external
* party? */
bool psbt_output_to_external(const struct wally_psbt_output *output);

/* psbt_contribs_changed - Returns true if the psbt's inputs/outputs
* have changed.
*
Expand Down
42 changes: 24 additions & 18 deletions doc/PLUGINS.md
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,7 @@ i.e. only definitively resolved HTLCs or confirmed bitcoin transactions.
"node_id":"03a7103a2322b811f7369cbb27fb213d30bbc0b012082fed3cad7e4498da2dc56b",
"type":"chain_mvt",
"account_id":"wallet",
"originating_account": "wallet", // (`chain_mvt` only, optional)
"txid":"0159693d8f3876b4def468b208712c630309381e9d106a9836fa0a9571a28722", // (`chain_mvt` only, optional)
"utxo_txid":"0159693d8f3876b4def468b208712c630309381e9d106a9836fa0a9571a28722", // (`chain_mvt` only)
"vout":1, // (`chain_mvt` only)
Expand Down Expand Up @@ -731,6 +732,9 @@ notification adheres to.
`account_id` is the name of this account. The node's wallet is named 'wallet',
all channel funds' account are the channel id.

`originating_account` is the account that this movement originated from.
*Only* tagged on external events (deposits/withdrawals to an external party).

`txid` is the transaction id of the bitcoin transaction that triggered this
ledger event. `utxo_txid` and `vout` identify the bitcoin output which triggered
this notification. (`chain_mvt` only). Notifications tagged
Expand Down Expand Up @@ -767,24 +771,26 @@ both the debit/credit contain fees. Technically routed debits are the
- `invoice`: funds paid to or recieved from an invoice.
- `routed`: funds routed through this node.
- `pushed`: funds pushed to peer.
- channel_open : channel is opened, initial channel balance
- channel_close: channel is closed, final channel balance
- delayed_to_us : on-chain output to us, spent back into our wallet
- htlc_timeout : on-chain htlc timeout output
- htlc_fulfill : on-chian htlc fulfill output
- htlc_tx : on-chain htlc tx has happened
- to_wallet : output being spent into our wallet
- ignored : output is being ignored
- anchor : an anchor output
- to_them : output intended to peer's wallet
- penalized : output we've 'lost' due to a penalty (failed cheat attempt)
- stolen : output we've 'lost' due to peer's cheat
- to_miner : output we've burned to miner (OP_RETURN)
- opener : tags channel_open, we are the channel opener
- lease_fee: amount paid as lease fee
- leased: tags channel_open, channel contains leased funds

`blockheight` is the block the txid is included in.
- `channel_open` : channel is opened, initial channel balance
- `channel_close`: channel is closed, final channel balance
- `delayed_to_us`: on-chain output to us, spent back into our wallet
- `htlc_timeout`: on-chain htlc timeout output
- `htlc_fulfill`: on-chian htlc fulfill output
- `htlc_tx`: on-chain htlc tx has happened
- `to_wallet`: output being spent into our wallet
- `ignored`: output is being ignored
- `anchor`: an anchor output
- `to_them`: output intended to peer's wallet
- `penalized`: output we've 'lost' due to a penalty (failed cheat attempt)
- `stolen`: output we've 'lost' due to peer's cheat
- `to_miner`: output we've burned to miner (OP_RETURN)
- `opener`: tags channel_open, we are the channel opener
- `lease_fee`: amount paid as lease fee
- `leased`: tags channel_open, channel contains leased funds

`blockheight` is the block the txid is included in. `channel_mvt`s will be null,
so will the blockheight for withdrawals to external parties (we issue these events
when we send the tx containing them, before they're included in the chain).

The `timestamp` is seconds since Unix epoch of the node's machine time
at the time lightningd broadcasts the notification.
Expand Down
3 changes: 3 additions & 0 deletions lightningd/notification.c
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,9 @@ static void coin_movement_notification_serialize(struct json_stream *stream,
json_add_node_id(stream, "node_id", mvt->node_id);
json_add_string(stream, "type", mvt_type_str(mvt->type));
json_add_string(stream, "account_id", mvt->account_id);
if (mvt->originating_acct)
json_add_string(stream, "originating_account",
mvt->originating_acct);
json_mvt_id(stream, mvt->type, &mvt->id);
json_add_amount_msat_only(stream, "credit", mvt->credit);
json_add_amount_msat_only(stream, "debit", mvt->debit);
Expand Down
3 changes: 3 additions & 0 deletions lightningd/onchain_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,9 @@ static void handle_onchain_log_coin_move(struct channel *channel, const u8 *msg)
if (!mvt->account_name)
mvt->account_name = type_to_string(mvt, struct channel_id,
&channel->cid);
else if (chain_mvt_is_external(mvt))
mvt->originating_acct = type_to_string(mvt, struct channel_id,
&channel->cid);
notify_chain_mvt(channel->peer->ld, mvt);
tal_free(mvt);
}
Expand Down
16 changes: 12 additions & 4 deletions plugins/spender/multiwithdraw.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <ccan/tal/str/str.h>
#include <common/json_stream.h>
#include <common/json_tok.h>
#include <common/psbt_open.h>
#include <common/pseudorand.h>
#include <common/type_to_string.h>
#include <plugins/spender/multiwithdraw.h>
Expand Down Expand Up @@ -44,6 +45,8 @@ struct multiwithdraw_destination {
struct amount_sat amount;
/* Whether the amount was "all". */
bool all;
/* Whether this is to an external addr (all passed in are assumed) */
bool is_to_external;
};

struct multiwithdraw_command {
Expand Down Expand Up @@ -93,6 +96,7 @@ param_outputs_array(struct command *cmd,
enum address_parse_result res;

dest = &(*outputs)[i];
dest->is_to_external = true;

if (e->type != JSMN_OBJECT)
goto err;
Expand Down Expand Up @@ -537,6 +541,7 @@ mw_after_newaddr(struct command *cmd,
change.script = script;
change.amount = mw->change_amount;
change.all = false;
change.is_to_external = false;

tal_arr_expand(&mw->outputs, change);

Expand All @@ -560,15 +565,18 @@ mw_load_outputs(struct multiwithdraw_command *mw)
{
/* Insert outputs at random locations. */
for (size_t i = 0; i < tal_count(mw->outputs); ++i) {
struct wally_psbt_output *out;
/* There are already `i` outputs at this point,
* select from 0 to `i` inclusive, with 0 meaning
* "before first output" and `i` meaning "after
* last output". */
size_t point = pseudorand(i + 1);
psbt_insert_output(mw->psbt,
mw->outputs[i].script,
mw->outputs[i].amount,
point);
out = psbt_insert_output(mw->psbt,
mw->outputs[i].script,
mw->outputs[i].amount,
point);
if (mw->outputs[i].is_to_external)
psbt_output_mark_as_external(mw->psbt, out);
}

if (chainparams->is_elements) {
Expand Down
12 changes: 12 additions & 0 deletions plugins/txprepare.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <common/json_stream.h>
#include <common/json_tok.h>
#include <common/memleak.h>
#include <common/psbt_open.h>
#include <common/pseudorand.h>
#include <common/type_to_string.h>
#include <plugins/libplugin.h>
Expand All @@ -13,6 +14,7 @@
struct tx_output {
struct amount_sat amount;
const u8 *script;
bool is_to_external;
};

struct txprepare {
Expand Down Expand Up @@ -79,6 +81,9 @@ static struct command_result *param_outputs(struct command *cmd,
enum address_parse_result res;
struct tx_output *out = &txp->outputs[i];

/* We assume these are accounted for elsewhere */
out->is_to_external = false;

/* output format: {destination: amount} */
if (t->type != JSMN_OBJECT)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
Expand Down Expand Up @@ -190,6 +195,11 @@ static struct command_result *finish_txprepare(struct command *cmd,
struct amount_sat,
&txp->outputs[i].amount));
psbt_add_output(txp->psbt, out, i);

if (txp->outputs[i].is_to_external)
psbt_output_mark_as_external(txp->psbt,
&txp->psbt->outputs[i]);

wally_tx_output_free(out);
}

Expand Down Expand Up @@ -239,6 +249,7 @@ static struct command_result *newaddr_done(struct command *cmd,
sizeof(txp->outputs[0]) * (num - pos));

txp->outputs[pos].amount = txp->change_amount;
txp->outputs[pos].is_to_external = false;
if (json_to_address_scriptpubkey(txp, chainparams, buf, addr,
&txp->outputs[pos].script)
!= ADDRESS_PARSE_SUCCESS) {
Expand Down Expand Up @@ -516,6 +527,7 @@ static struct command_result *json_withdraw(struct command *cmd,
}
txp->outputs[0].amount = *amount;
txp->outputs[0].script = scriptpubkey;
txp->outputs[0].is_to_external = true;
txp->weight = bitcoin_tx_core_weight(1, tal_count(txp->outputs))
+ bitcoin_tx_output_weight(tal_bytelen(scriptpubkey));

Expand Down
12 changes: 11 additions & 1 deletion tests/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
wait_for, TailableProc, env
)
from utils import (
account_balance, scriptpubkey_addr
account_balance, scriptpubkey_addr, check_coin_moves
)
from ephemeral_port_reserve import reserve
from utils import EXPERIMENTAL_FEATURES
Expand Down Expand Up @@ -623,6 +623,16 @@ def dont_spend_outputs(n, txid):
sync_blockheight(bitcoind, [l1])
assert account_balance(l1, 'wallet') == 0

external_moves = [
{'type': 'chain_mvt', 'credit': 2000000000, 'debit': 0, 'tags': ['deposit']},
{'type': 'chain_mvt', 'credit': 2000000000, 'debit': 0, 'tags': ['deposit']},
{'type': 'chain_mvt', 'credit': 2000000000, 'debit': 0, 'tags': ['deposit']},
{'type': 'chain_mvt', 'credit': 2000000000, 'debit': 0, 'tags': ['deposit']},
{'type': 'chain_mvt', 'credit': 11957603000, 'debit': 0, 'tags': ['deposit']},
]

check_coin_moves(l1, 'external', external_moves, chainparams)


def test_io_logging(node_factory, executor):
l1 = node_factory.get_node(options={'log-level': 'io'})
Expand Down
Loading