diff --git a/onchaind/onchaind.c b/onchaind/onchaind.c index 4426e3fbe..24f54abf9 100644 --- a/onchaind/onchaind.c +++ b/onchaind/onchaind.c @@ -157,6 +157,18 @@ static void record_htlc_fulfilled(const struct bitcoin_txid *txid, send_coin_mvt(take(mvt)); } +static void update_ledger_chain_fees_msat(const struct bitcoin_txid *txid, + struct amount_msat fees) +{ + struct chain_coin_mvt *mvt; + mvt = new_chain_coin_mvt(NULL, NULL, + txid, NULL, 0, NULL, + CHAIN_FEES, fees, + false, BTC); + + send_coin_mvt(take(mvt)); +} + static void update_ledger_chain_fees(const struct bitcoin_txid *txid, struct amount_sat fees) { @@ -188,6 +200,49 @@ static struct amount_sat record_chain_fees_tx(const struct bitcoin_txid *txid, return fees; } +static void record_mutual_closure(const struct bitcoin_txid *txid, + struct amount_sat our_out, + int output_num) +{ + struct amount_msat chain_fees, output_msat; + struct chain_coin_mvt *mvt; + + /* First figure out 'fees' we paid on this will include + * - 'residue' that can't fit onchain (< 1 sat) + * - trimmed output, if our balance is < dust_limit + * - fees paid for getting this tx mined + */ + if (!amount_sat_to_msat(&output_msat, our_out)) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "unable to convert %s to msat", + type_to_string(tmpctx, struct amount_sat, + &our_out)); + + if (!amount_msat_sub(&chain_fees, our_msat, output_msat)) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "unable to subtract %s from %s", + type_to_string(tmpctx, struct amount_msat, + &output_msat), + type_to_string(tmpctx, struct amount_msat, + &our_msat)); + + if (!amount_msat_eq(AMOUNT_MSAT(0), chain_fees)) + update_ledger_chain_fees_msat(txid, chain_fees); + + /* If we have no output, we exit early */ + if (amount_msat_eq(AMOUNT_MSAT(0), output_msat)) + return; + + assert(output_num > -1); + /* Otherwise, we record the channel withdrawal */ + mvt = new_chain_coin_mvt(NULL, NULL, txid, + txid, output_num, NULL, + WITHDRAWAL, output_msat, + false, BTC); + + send_coin_mvt(take(mvt)); +} + static void record_channel_withdrawal_minus_fees(const struct bitcoin_txid *tx_txid, struct tracked_output *out, struct amount_sat fees) @@ -870,10 +925,12 @@ static u64 unmask_commit_number(const struct bitcoin_tx *tx, static bool is_mutual_close(const struct bitcoin_tx *tx, const u8 *local_scriptpubkey, - const u8 *remote_scriptpubkey) + const u8 *remote_scriptpubkey, + int *local_outnum) { size_t i; bool local_matched = false, remote_matched = false; + *local_outnum = -1; for (i = 0; i < tx->wtx->num_outputs; i++) { const u8 *script = bitcoin_tx_output_get_script(tmpctx, tx, i); @@ -883,9 +940,10 @@ static bool is_mutual_close(const struct bitcoin_tx *tx, /* This is a fee output, ignore please */ continue; } else if (scripteq(script, local_scriptpubkey) - && !local_matched) + && !local_matched) { + *local_outnum = i; local_matched = true; - else if (scripteq(script, remote_scriptpubkey) + } else if (scripteq(script, remote_scriptpubkey) && !remote_matched) remote_matched = true; else @@ -1586,8 +1644,11 @@ static void init_reply(const char *what) static void handle_mutual_close(const struct chainparams *chainparams, const struct bitcoin_txid *txid, - struct tracked_output **outs) + struct tracked_output **outs, + const struct bitcoin_tx *tx, + int our_outnum) { + struct amount_sat our_out; init_reply("Tracking mutual close transaction"); /* Annotate the first input as close. We can currently only have a @@ -1603,6 +1664,17 @@ static void handle_mutual_close(const struct chainparams *chainparams, */ resolved_by_other(outs[0], txid, MUTUAL_CLOSE); + /* It's possible there's no to_us output */ + if (our_outnum > -1) { + struct amount_asset asset; + asset = bitcoin_tx_output_get_amount(tx, our_outnum); + assert(amount_asset_is_main(&asset)); + our_out = amount_asset_to_sat(&asset); + } else + our_out = AMOUNT_SAT(0); + + record_mutual_closure(txid, our_out, our_outnum); + wait_for_resolved(chainparams, outs); } @@ -2808,6 +2880,7 @@ int main(int argc, char *argv[]) bool *tell_if_missing, *tell_immediately; u32 tx_blockheight; struct pubkey *possible_remote_per_commitment_point; + int mutual_outnum; subdaemon_setup(argc, argv); @@ -2899,8 +2972,8 @@ int main(int argc, char *argv[]) * without any pending payments) and publish it on the blockchain (see * [BOLT #2: Channel Close](02-peer-protocol.md#channel-close)). */ - if (is_mutual_close(tx, scriptpubkey[LOCAL], scriptpubkey[REMOTE])) - handle_mutual_close(tx->chainparams, &txid, outs); + if (is_mutual_close(tx, scriptpubkey[LOCAL], scriptpubkey[REMOTE], &mutual_outnum)) + handle_mutual_close(tx->chainparams, &txid, outs, tx, mutual_outnum); else { /* BOLT #5: * diff --git a/onchaind/test/run-grind_feerate-bug.c b/onchaind/test/run-grind_feerate-bug.c index 5989bf71c..28ad51247 100644 --- a/onchaind/test/run-grind_feerate-bug.c +++ b/onchaind/test/run-grind_feerate-bug.c @@ -97,6 +97,18 @@ void memleak_remove_referenced(struct htable *memtable UNNEEDED, const void *roo void memleak_scan_region(struct htable *memtable UNNEEDED, const void *p UNNEEDED, size_t bytelen UNNEEDED) { fprintf(stderr, "memleak_scan_region called!\n"); abort(); } +/* Generated stub for new_chain_coin_mvt */ +struct chain_coin_mvt *new_chain_coin_mvt(const tal_t *ctx UNNEEDED, + const char *account_name UNNEEDED, + const struct bitcoin_txid *tx_txid UNNEEDED, + const struct bitcoin_txid *output_txid UNNEEDED, + u32 vout UNNEEDED, + struct sha256 *payment_hash UNNEEDED, + enum mvt_tag tag UNNEEDED, + struct amount_msat amount UNNEEDED, + bool is_credit UNNEEDED, + enum mvt_unit_type unit UNNEEDED) +{ fprintf(stderr, "new_chain_coin_mvt called!\n"); abort(); } /* Generated stub for new_chain_coin_mvt_sat */ struct chain_coin_mvt *new_chain_coin_mvt_sat(const tal_t *ctx UNNEEDED, const char *account_name UNNEEDED, diff --git a/onchaind/test/run-grind_feerate.c b/onchaind/test/run-grind_feerate.c index 7a23962b1..f6685ccdc 100644 --- a/onchaind/test/run-grind_feerate.c +++ b/onchaind/test/run-grind_feerate.c @@ -109,6 +109,18 @@ void memleak_remove_referenced(struct htable *memtable UNNEEDED, const void *roo void memleak_scan_region(struct htable *memtable UNNEEDED, const void *p UNNEEDED, size_t bytelen UNNEEDED) { fprintf(stderr, "memleak_scan_region called!\n"); abort(); } +/* Generated stub for new_chain_coin_mvt */ +struct chain_coin_mvt *new_chain_coin_mvt(const tal_t *ctx UNNEEDED, + const char *account_name UNNEEDED, + const struct bitcoin_txid *tx_txid UNNEEDED, + const struct bitcoin_txid *output_txid UNNEEDED, + u32 vout UNNEEDED, + struct sha256 *payment_hash UNNEEDED, + enum mvt_tag tag UNNEEDED, + struct amount_msat amount UNNEEDED, + bool is_credit UNNEEDED, + enum mvt_unit_type unit UNNEEDED) +{ fprintf(stderr, "new_chain_coin_mvt called!\n"); abort(); } /* Generated stub for new_chain_coin_mvt_sat */ struct chain_coin_mvt *new_chain_coin_mvt_sat(const tal_t *ctx UNNEEDED, const char *account_name UNNEEDED,