Browse Source

coin_moves: update withdrawal logic to account for 'variable owner' txs

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
paymod-02
niftynei 5 years ago
committed by Christian Decker
parent
commit
2e9c387f45
  1. 3
      bitcoin/test/run-bitcoin_block_from_hex.c
  2. 3
      bitcoin/test/run-tx-encode.c
  3. 3
      cli/test/run-large-input.c
  4. 3
      cli/test/run-remove-hint.c
  5. 3
      common/test/run-bigsize.c
  6. 3
      common/test/run-cryptomsg.c
  7. 3
      common/test/run-derive_basepoints.c
  8. 3
      common/test/run-features.c
  9. 3
      common/test/run-gossip_rcvd_filter.c
  10. 3
      common/test/run-ip_port_parsing.c
  11. 3
      common/test/run-json_remove.c
  12. 3
      common/test/run-key_derive.c
  13. 3
      common/test/run-lock.c
  14. 3
      common/test/run-softref.c
  15. 3
      common/test/run-sphinx.c
  16. 3
      connectd/test/run-initiator-success.c
  17. 3
      connectd/test/run-responder-success.c
  18. 106
      lightningd/chaintopology.c
  19. 41
      tests/test_wallet.py

3
bitcoin/test/run-bitcoin_block_from_hex.c

@ -22,6 +22,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */ /* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); } { 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 */ /* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED, bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED, struct amount_sat a UNNEEDED,

3
bitcoin/test/run-tx-encode.c

@ -23,6 +23,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */ /* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); } { 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 */ /* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED, bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED, struct amount_sat a UNNEEDED,

3
cli/test/run-large-input.c

@ -47,6 +47,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */ /* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); } { 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 */ /* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED, bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED, struct amount_sat a UNNEEDED,

3
cli/test/run-remove-hint.c

@ -50,6 +50,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */ /* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); } { 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 */ /* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED, bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED, struct amount_sat a UNNEEDED,

3
common/test/run-bigsize.c

@ -27,6 +27,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */ /* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); } { 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 */ /* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED, bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED, struct amount_sat a UNNEEDED,

3
common/test/run-cryptomsg.c

@ -22,6 +22,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */ /* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); } { 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 */ /* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED, bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED, struct amount_sat a UNNEEDED,

3
common/test/run-derive_basepoints.c

@ -23,6 +23,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */ /* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); } { 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 */ /* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED, bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED, struct amount_sat a UNNEEDED,

3
common/test/run-features.c

@ -22,6 +22,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */ /* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); } { 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 */ /* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED, bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED, struct amount_sat a UNNEEDED,

3
common/test/run-gossip_rcvd_filter.c

@ -19,6 +19,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */ /* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); } { 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 */ /* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED, bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED, struct amount_sat a UNNEEDED,

3
common/test/run-ip_port_parsing.c

@ -21,6 +21,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */ /* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); } { 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 */ /* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED, bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED, struct amount_sat a UNNEEDED,

3
common/test/run-json_remove.c

@ -19,6 +19,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */ /* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); } { 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 */ /* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED, bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED, struct amount_sat a UNNEEDED,

3
common/test/run-key_derive.c

@ -24,6 +24,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */ /* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); } { 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 */ /* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED, bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED, struct amount_sat a UNNEEDED,

3
common/test/run-lock.c

@ -23,6 +23,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */ /* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); } { 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 */ /* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED, bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED, struct amount_sat a UNNEEDED,

3
common/test/run-softref.c

@ -20,6 +20,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */ /* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); } { 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 */ /* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED, bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED, struct amount_sat a UNNEEDED,

3
common/test/run-sphinx.c

@ -36,6 +36,9 @@ void amount_msat_from_u64(struct amount_msat *msat UNNEEDED, u64 millisatoshis U
/* Generated stub for amount_sat_eq */ /* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); } { 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 */ /* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED, bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED, struct amount_sat a UNNEEDED,

3
connectd/test/run-initiator-success.c

@ -26,6 +26,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */ /* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); } { 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 */ /* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED, bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED, struct amount_sat a UNNEEDED,

3
connectd/test/run-responder-success.c

@ -26,6 +26,9 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
/* Generated stub for amount_sat_eq */ /* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); } { 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 */ /* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED, bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED, struct amount_sat a UNNEEDED,

106
lightningd/chaintopology.c

@ -662,22 +662,24 @@ static void updates_complete(struct chain_topology *topo)
next_topology_timer(topo); next_topology_timer(topo);
} }
static void record_output_spend(struct lightningd *ld, static void record_utxo_spent(struct lightningd *ld,
const struct bitcoin_txid *txid, const struct bitcoin_txid *txid,
const struct bitcoin_txid *utxo_txid, const struct bitcoin_txid *utxo_txid,
u32 vout, u32 blockheight, u32 vout, u32 blockheight,
struct amount_sat *input_amt) struct amount_sat *input_amt)
{ {
struct utxo *utxo; struct utxo *utxo;
struct chain_coin_mvt *mvt; struct chain_coin_mvt *mvt;
u8 *ctx = tal(NULL, u8); u8 *ctx = tal(NULL, u8);
utxo = wallet_utxo_get(ctx, ld->wallet, utxo_txid, vout); utxo = wallet_utxo_get(ctx, ld->wallet, utxo_txid, vout);
if (!utxo) if (!utxo) {
log_broken(ld->log, "No record of utxo %s:%d", log_broken(ld->log, "No record of utxo %s:%d",
type_to_string(tmpctx, struct bitcoin_txid, type_to_string(tmpctx, struct bitcoin_txid,
utxo_txid), utxo_txid),
vout); vout);
return;
}
*input_amt = utxo->amount; *input_amt = utxo->amount;
mvt = new_coin_spend_track(ctx, txid, utxo_txid, vout, blockheight); mvt = new_coin_spend_track(ctx, txid, utxo_txid, vout, blockheight);
@ -685,23 +687,14 @@ static void record_output_spend(struct lightningd *ld,
tal_free(ctx); tal_free(ctx);
} }
static void record_tx_outs_and_fees(struct lightningd *ld, const struct bitcoin_tx *tx, static void record_outputs_as_withdraws(const tal_t *ctx,
struct bitcoin_txid *txid, u32 blockheight, struct lightningd *ld,
struct amount_sat inputs_total) const struct bitcoin_tx *tx,
struct bitcoin_txid *txid,
u32 blockheight)
{ {
struct amount_sat fee;
struct chain_coin_mvt *mvt; struct chain_coin_mvt *mvt;
size_t i; for (size_t i = 0; i < tx->wtx->num_outputs; 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++) {
struct amount_asset asset; struct amount_asset asset;
struct amount_sat outval; struct amount_sat outval;
if (elements_tx_output_is_fee(tx, i)) if (elements_tx_output_is_fee(tx, i))
@ -709,18 +702,55 @@ static void record_tx_outs_and_fees(struct lightningd *ld, const struct bitcoin_
asset = bitcoin_tx_output_get_amount(tx, i); asset = bitcoin_tx_output_get_amount(tx, i);
assert(amount_asset_is_main(&asset)); assert(amount_asset_is_main(&asset));
outval = amount_asset_to_sat(&asset); outval = amount_asset_to_sat(&asset);
mvt = new_coin_withdrawal_sat(ctx, "wallet", txid, txid, mvt = new_coin_withdrawal_sat(ctx, "wallet", txid,
i, blockheight, outval); txid, i, blockheight,
outval);
notify_chain_mvt(ld, mvt); 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' /* Note that to figure out the *total* 'onchain'
* cost of a channel, you'll want to also include * cost of a channel, you'll want to also include
* fees logged here, to the 'wallet' account (for funding tx). * fees logged here, to the 'wallet' account (for funding tx).
* You can do this in post by accounting for any 'chain_fees' logged for * You can do this in post by accounting for any 'chain_fees' logged for
* the funding txid when looking at a channel. */ * the funding txid when looking at a channel. */
log_fee:
notify_chain_mvt(ld, notify_chain_mvt(ld,
new_coin_chain_fees_sat(ctx, "wallet", txid, new_coin_chain_fees_sat(ctx, "wallet", txid,
blockheight, fee)); blockheight, fee));
@ -736,7 +766,7 @@ static void topo_update_spends(struct chain_topology *topo, struct block *b)
const struct short_channel_id *scid; const struct short_channel_id *scid;
for (size_t i = 0; i < tal_count(b->full_txs); i++) { for (size_t i = 0; i < tal_count(b->full_txs); i++) {
const struct bitcoin_tx *tx = 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 bitcoin_txid txid;
struct amount_sat inputs_total = AMOUNT_SAT(0); struct amount_sat inputs_total = AMOUNT_SAT(0);
@ -758,34 +788,22 @@ static void topo_update_spends(struct chain_topology *topo, struct block *b)
tal_free(scid); tal_free(scid);
} }
our_tx |= our_spend; our_tx &= our_spend;
includes_our_spend |= our_spend;
if (our_spend) { if (our_spend) {
struct amount_sat input_amt; struct amount_sat input_amt;
bool ok; bool ok;
record_output_spend(topo->ld, &txid, &outpoint_txid, record_utxo_spent(topo->ld, &txid, &outpoint_txid,
input->index, b->height, &input_amt); input->index, b->height, &input_amt);
ok = amount_sat_add(&inputs_total, inputs_total, input_amt); ok = amount_sat_add(&inputs_total, inputs_total, input_amt);
assert(ok); 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 if (includes_our_spend)
* 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)
record_tx_outs_and_fees(topo->ld, tx, &txid, record_tx_outs_and_fees(topo->ld, tx, &txid,
b->height, inputs_total); b->height, inputs_total, our_tx);
} }
} }

41
tests/test_wallet.py

@ -6,7 +6,7 @@ from flaky import flaky # noqa: F401
from pyln.client import RpcError, Millisatoshi from pyln.client import RpcError, Millisatoshi
from utils import ( from utils import (
only_one, wait_for, sync_blockheight, EXPERIMENTAL_FEATURES, COMPAT, only_one, wait_for, sync_blockheight, EXPERIMENTAL_FEATURES, COMPAT,
VALGRIND VALGRIND, check_coin_moves
) )
import os import os
@ -568,7 +568,9 @@ def test_sign_and_send_psbt(node_factory, bitcoind, chainparams):
""" """
amount = 1000000 amount = 1000000
total_outs = 12 total_outs = 12
l1 = node_factory.get_node(feerates=(7500, 7500, 7500, 7500)) coin_mvt_plugin = os.path.join(os.getcwd(), 'tests/plugins/coin_movements.py')
l1 = node_factory.get_node(options={'plugin': coin_mvt_plugin},
feerates=(7500, 7500, 7500, 7500))
l2 = node_factory.get_node() l2 = node_factory.get_node()
addr = chainparams['example_addr'] addr = chainparams['example_addr']
@ -677,6 +679,41 @@ def test_sign_and_send_psbt(node_factory, bitcoind, chainparams):
with pytest.raises(RpcError, match=r"should be a PSBT, not"): with pytest.raises(RpcError, match=r"should be a PSBT, not"):
l1.rpc.signpsbt(modded_psbt) l1.rpc.signpsbt(modded_psbt)
wallet_coin_mvts = [
{'type': 'chain_mvt', 'credit': 1000000000, 'debit': 0, 'tag': 'deposit'},
{'type': 'chain_mvt', 'credit': 1000000000, 'debit': 0, 'tag': 'deposit'},
{'type': 'chain_mvt', 'credit': 1000000000, 'debit': 0, 'tag': 'deposit'},
{'type': 'chain_mvt', 'credit': 1000000000, 'debit': 0, 'tag': 'deposit'},
{'type': 'chain_mvt', 'credit': 1000000000, 'debit': 0, 'tag': 'deposit'},
{'type': 'chain_mvt', 'credit': 1000000000, 'debit': 0, 'tag': 'deposit'},
{'type': 'chain_mvt', 'credit': 1000000000, 'debit': 0, 'tag': 'deposit'},
{'type': 'chain_mvt', 'credit': 1000000000, 'debit': 0, 'tag': 'deposit'},
{'type': 'chain_mvt', 'credit': 1000000000, 'debit': 0, 'tag': 'deposit'},
{'type': 'chain_mvt', 'credit': 1000000000, 'debit': 0, 'tag': 'deposit'},
{'type': 'chain_mvt', 'credit': 1000000000, 'debit': 0, 'tag': 'deposit'},
{'type': 'chain_mvt', 'credit': 1000000000, 'debit': 0, 'tag': 'deposit'},
{'type': 'chain_mvt', 'credit': 0, 'debit': 0, 'tag': 'spend_track'},
{'type': 'chain_mvt', 'credit': 0, 'debit': 0, 'tag': 'spend_track'},
{'type': 'chain_mvt', 'credit': 0, 'debit': 0, 'tag': 'spend_track'},
{'type': 'chain_mvt', 'credit': 0, 'debit': 0, 'tag': 'spend_track'},
# Nicely splits out withdrawals and chain fees, because it's all our tx
{'type': 'chain_mvt', 'credit': 0, 'debit': 988255000, 'tag': 'withdrawal'},
{'type': 'chain_mvt', 'credit': 0, 'debit': 3000000000, 'tag': 'withdrawal'},
{'type': 'chain_mvt', 'credit': 0, 'debit': 11745000, 'tag': 'chain_fees'},
{'type': 'chain_mvt', 'credit': 988255000, 'debit': 0, 'tag': 'deposit'},
{'type': 'chain_mvt', 'credit': 0, 'debit': 0, 'tag': 'spend_track'},
{'type': 'chain_mvt', 'credit': 0, 'debit': 0, 'tag': 'spend_track'},
{'type': 'chain_mvt', 'credit': 0, 'debit': 0, 'tag': 'spend_track'},
{'type': 'chain_mvt', 'credit': 0, 'debit': 0, 'tag': 'spend_track'},
# Note that this is technically wrong since we paid 11745sat in fees
# but since it includes inputs / outputs from a second node, we can't
# do proper acccounting for it.
{'type': 'chain_mvt', 'credit': 0, 'debit': 4000000000, 'tag': 'withdrawal'},
{'type': 'chain_mvt', 'credit': 0, 'debit': 0, 'tag': 'chain_fees'},
{'type': 'chain_mvt', 'credit': 988255000, 'debit': 0, 'tag': 'deposit'},
]
check_coin_moves(l1, 'wallet', wallet_coin_mvts)
def test_txsend(node_factory, bitcoind, chainparams): def test_txsend(node_factory, bitcoind, chainparams):
amount = 1000000 amount = 1000000

Loading…
Cancel
Save