Skip to content

Commit

Permalink
coin_moves: update withdrawal logic to account for 'variable owner' txs
Browse files Browse the repository at this point in the history
Our existing coin_moves tracking logic assumed that any tx we had an
input in belonged to *all* of our wallet (not a bad assumption as long
as there was no way to update a tx that spends our wallets)

Now that we've got `signpsbt` implemented, however, we need to be
careful about how we account for withdrawals. For now we do a best guess
at what the feerate is, and lump all of our spent outputs as a
'withdrawal' when it's impossible to disambiguate
  • Loading branch information
niftynei authored and cdecker committed Jun 29, 2020
1 parent ee549a2 commit 2e9c387
Show file tree
Hide file tree
Showing 19 changed files with 152 additions and 46 deletions.
3 changes: 3 additions & 0 deletions bitcoin/test/run-bitcoin_block_from_hex.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
/* Generated stub for amount_sat_less */
bool amount_sat_less(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_less called!\n"); abort(); }
/* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,
Expand Down
3 changes: 3 additions & 0 deletions bitcoin/test/run-tx-encode.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
/* Generated stub for amount_sat_less */
bool amount_sat_less(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_less called!\n"); abort(); }
/* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,
Expand Down
3 changes: 3 additions & 0 deletions cli/test/run-large-input.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
/* Generated stub for amount_sat_less */
bool amount_sat_less(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_less called!\n"); abort(); }
/* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,
Expand Down
3 changes: 3 additions & 0 deletions cli/test/run-remove-hint.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
/* Generated stub for amount_sat_less */
bool amount_sat_less(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_less called!\n"); abort(); }
/* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,
Expand Down
3 changes: 3 additions & 0 deletions common/test/run-bigsize.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
/* Generated stub for amount_sat_less */
bool amount_sat_less(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_less called!\n"); abort(); }
/* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,
Expand Down
3 changes: 3 additions & 0 deletions common/test/run-cryptomsg.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
/* Generated stub for amount_sat_less */
bool amount_sat_less(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_less called!\n"); abort(); }
/* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,
Expand Down
3 changes: 3 additions & 0 deletions common/test/run-derive_basepoints.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
/* Generated stub for amount_sat_less */
bool amount_sat_less(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_less called!\n"); abort(); }
/* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,
Expand Down
3 changes: 3 additions & 0 deletions common/test/run-features.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
/* Generated stub for amount_sat_less */
bool amount_sat_less(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_less called!\n"); abort(); }
/* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,
Expand Down
3 changes: 3 additions & 0 deletions common/test/run-gossip_rcvd_filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
/* Generated stub for amount_sat_less */
bool amount_sat_less(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_less called!\n"); abort(); }
/* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,
Expand Down
3 changes: 3 additions & 0 deletions common/test/run-ip_port_parsing.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
/* Generated stub for amount_sat_less */
bool amount_sat_less(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_less called!\n"); abort(); }
/* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,
Expand Down
3 changes: 3 additions & 0 deletions common/test/run-json_remove.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
/* Generated stub for amount_sat_less */
bool amount_sat_less(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_less called!\n"); abort(); }
/* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,
Expand Down
3 changes: 3 additions & 0 deletions common/test/run-key_derive.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
/* Generated stub for amount_sat_less */
bool amount_sat_less(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_less called!\n"); abort(); }
/* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,
Expand Down
3 changes: 3 additions & 0 deletions common/test/run-lock.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
/* Generated stub for amount_sat_less */
bool amount_sat_less(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_less called!\n"); abort(); }
/* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,
Expand Down
3 changes: 3 additions & 0 deletions common/test/run-softref.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
/* Generated stub for amount_sat_less */
bool amount_sat_less(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_less called!\n"); abort(); }
/* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,
Expand Down
3 changes: 3 additions & 0 deletions common/test/run-sphinx.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ void amount_msat_from_u64(struct amount_msat *msat UNNEEDED, u64 millisatoshis U
/* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
/* Generated stub for amount_sat_less */
bool amount_sat_less(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_less called!\n"); abort(); }
/* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,
Expand Down
3 changes: 3 additions & 0 deletions connectd/test/run-initiator-success.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
/* Generated stub for amount_sat_less */
bool amount_sat_less(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_less called!\n"); abort(); }
/* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,
Expand Down
3 changes: 3 additions & 0 deletions connectd/test/run-responder-success.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
/* Generated stub for amount_sat_less */
bool amount_sat_less(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_less called!\n"); abort(); }
/* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,
Expand Down
106 changes: 62 additions & 44 deletions lightningd/chaintopology.c
Original file line number Diff line number Diff line change
Expand Up @@ -662,65 +662,95 @@ static void updates_complete(struct chain_topology *topo)
next_topology_timer(topo);
}

static void record_output_spend(struct lightningd *ld,
const struct bitcoin_txid *txid,
const struct bitcoin_txid *utxo_txid,
u32 vout, u32 blockheight,
struct amount_sat *input_amt)
static void record_utxo_spent(struct lightningd *ld,
const struct bitcoin_txid *txid,
const struct bitcoin_txid *utxo_txid,
u32 vout, u32 blockheight,
struct amount_sat *input_amt)
{
struct utxo *utxo;
struct chain_coin_mvt *mvt;
u8 *ctx = tal(NULL, u8);

utxo = wallet_utxo_get(ctx, ld->wallet, utxo_txid, vout);
if (!utxo)
if (!utxo) {
log_broken(ld->log, "No record of utxo %s:%d",
type_to_string(tmpctx, struct bitcoin_txid,
utxo_txid),
vout);
return;
}

*input_amt = utxo->amount;
mvt = new_coin_spend_track(ctx, txid, utxo_txid, vout, blockheight);
notify_chain_mvt(ld, mvt);
tal_free(ctx);
}

static void record_tx_outs_and_fees(struct lightningd *ld, const struct bitcoin_tx *tx,
struct bitcoin_txid *txid, u32 blockheight,
struct amount_sat inputs_total)
static void record_outputs_as_withdraws(const tal_t *ctx,
struct lightningd *ld,
const struct bitcoin_tx *tx,
struct bitcoin_txid *txid,
u32 blockheight)
{
struct amount_sat fee;
struct chain_coin_mvt *mvt;
size_t i;
u8 *ctx = tal(NULL, u8);

if (!tx)
log_broken(ld->log, "We have no record of transaction %s",
type_to_string(ctx, struct bitcoin_txid, txid));

/* We record every output on this transaction as a withdraw */
/* FIXME: collaborative tx will need to keep track of which
* outputs are ours */
for (i = 0; i < tx->wtx->num_outputs; i++) {
for (size_t i = 0; i < tx->wtx->num_outputs; i++) {
struct amount_asset asset;
struct amount_sat outval;
if (elements_tx_output_is_fee(tx, i))
continue;
asset = bitcoin_tx_output_get_amount(tx, i);
assert(amount_asset_is_main(&asset));
outval = amount_asset_to_sat(&asset);
mvt = new_coin_withdrawal_sat(ctx, "wallet", txid, txid,
i, blockheight, outval);
mvt = new_coin_withdrawal_sat(ctx, "wallet", txid,
txid, i, blockheight,
outval);
notify_chain_mvt(ld, mvt);
}
}

fee = bitcoin_tx_compute_fee_w_inputs(tx, inputs_total);
static void record_tx_outs_and_fees(struct lightningd *ld,
const struct bitcoin_tx *tx,
struct bitcoin_txid *txid,
u32 blockheight,
struct amount_sat inputs_total,
bool our_tx)
{
struct amount_sat fee, out_val;
struct chain_coin_mvt *mvt;
bool ok;
struct wally_psbt *psbt = NULL;
u8 *ctx = tal(NULL, u8);

/* We own every input on this tx, so track withdrawals precisely */
if (our_tx) {
record_outputs_as_withdraws(ctx, ld, tx, txid, blockheight);
fee = bitcoin_tx_compute_fee_w_inputs(tx, inputs_total);
goto log_fee;
}

/* FIXME: look up stashed psbt! */
if (!psbt) {
fee = bitcoin_tx_compute_fee_w_inputs(tx, inputs_total);
ok = amount_sat_sub(&out_val, inputs_total, fee);
assert(ok);

/* We don't have detailed withdrawal info for this tx,
* so we log the wallet withdrawal as a single entry */
mvt = new_coin_withdrawal_sat(ctx, "wallet", txid, NULL,
0, blockheight, out_val);
notify_chain_mvt(ld, mvt);
goto log_fee;
}

fee = AMOUNT_SAT(0);

/* Note that to figure out the *total* 'onchain'
* cost of a channel, you'll want to also include
* fees logged here, to the 'wallet' account (for funding tx).
* You can do this in post by accounting for any 'chain_fees' logged for
* the funding txid when looking at a channel. */
log_fee:
notify_chain_mvt(ld,
new_coin_chain_fees_sat(ctx, "wallet", txid,
blockheight, fee));
Expand All @@ -736,7 +766,7 @@ static void topo_update_spends(struct chain_topology *topo, struct block *b)
const struct short_channel_id *scid;
for (size_t i = 0; i < tal_count(b->full_txs); i++) {
const struct bitcoin_tx *tx = b->full_txs[i];
bool our_tx = false;
bool our_tx = true, includes_our_spend = false;
struct bitcoin_txid txid;
struct amount_sat inputs_total = AMOUNT_SAT(0);

Expand All @@ -758,34 +788,22 @@ static void topo_update_spends(struct chain_topology *topo, struct block *b)
tal_free(scid);
}

our_tx |= our_spend;
our_tx &= our_spend;
includes_our_spend |= our_spend;
if (our_spend) {
struct amount_sat input_amt;
bool ok;

record_output_spend(topo->ld, &txid, &outpoint_txid,
input->index, b->height, &input_amt);
record_utxo_spent(topo->ld, &txid, &outpoint_txid,
input->index, b->height, &input_amt);
ok = amount_sat_add(&inputs_total, inputs_total, input_amt);
assert(ok);
} else if (our_tx)
log_broken(topo->ld->log, "Recording fee spend for tx %s but "
"our wallet did not contribute input %s:%d",
type_to_string(tmpctx, struct bitcoin_txid,
&txid),
type_to_string(tmpctx, struct bitcoin_txid,
&outpoint_txid),
input->index);

}
}

/* For now we assume that if one of the spent utxos
* in this tx is 'ours', that we own all of the
* utxos and therefore paid all of the fees
* FIXME: update once interactive tx construction
* is a reality */
if (our_tx)
if (includes_our_spend)
record_tx_outs_and_fees(topo->ld, tx, &txid,
b->height, inputs_total);
b->height, inputs_total, our_tx);
}
}

Expand Down
Loading

0 comments on commit 2e9c387

Please sign in to comment.