From 1b443d810a9ba5b7de35d26457bd322660988f7e Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 23 Mar 2023 16:12:52 +1030 Subject: [PATCH 01/13] chaintopology: rename broadcast_tx callback name. It was once only called on failure, now it's always called (if set). It was called different things in different places, so unify it. Signed-off-by: Rusty Russell --- lightningd/chaintopology.c | 12 ++++++------ lightningd/chaintopology.h | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lightningd/chaintopology.c b/lightningd/chaintopology.c index e8364af4a27a..604d086ad114 100644 --- a/lightningd/chaintopology.c +++ b/lightningd/chaintopology.c @@ -202,8 +202,8 @@ static void broadcast_done(struct bitcoind *bitcoind, /* No longer needs to be disconnected if channel dies. */ tal_del_destructor2(otx->channel, clear_otx_channel, otx); - if (otx->failed_or_success) { - otx->failed_or_success(otx->channel, success, msg); + if (otx->finished) { + otx->finished(otx->channel, success, msg); tal_free(otx); } else if (we_broadcast(bitcoind->ld->topology, &otx->txid)) { log_debug( @@ -223,9 +223,9 @@ static void broadcast_done(struct bitcoind *bitcoind, void broadcast_tx(struct chain_topology *topo, struct channel *channel, const struct bitcoin_tx *tx, const char *cmd_id, bool allowhighfees, - void (*failed)(struct channel *channel, - bool success, - const char *err)) + void (*finished)(struct channel *channel, + bool success, + const char *err)) { /* Channel might vanish: topo owns it to start with. */ struct outgoing_tx *otx = tal(topo, struct outgoing_tx); @@ -234,7 +234,7 @@ void broadcast_tx(struct chain_topology *topo, otx->channel = channel; bitcoin_txid(tx, &otx->txid); otx->hextx = tal_hex(otx, rawtx); - otx->failed_or_success = failed; + otx->finished = finished; if (cmd_id) otx->cmd_id = tal_strdup(otx, cmd_id); else diff --git a/lightningd/chaintopology.h b/lightningd/chaintopology.h index 4ba6687ebb4f..7ebddc079b34 100644 --- a/lightningd/chaintopology.h +++ b/lightningd/chaintopology.h @@ -22,7 +22,7 @@ struct outgoing_tx { const char *hextx; struct bitcoin_txid txid; const char *cmd_id; - void (*failed_or_success)(struct channel *channel, bool success, const char *err); + void (*finished)(struct channel *channel, bool success, const char *err); }; struct block { @@ -178,14 +178,14 @@ u32 penalty_feerate(struct chain_topology *topo); * @tx: the transaction * @cmd_id: the JSON command id which triggered this (or NULL). * @allowhighfees: set to true to override the high-fee checks in the backend. - * @failed: if non-NULL, call that and don't rebroadcast. + * @finished: if non-NULL, call that and don't rebroadcast. */ void broadcast_tx(struct chain_topology *topo, struct channel *channel, const struct bitcoin_tx *tx, const char *cmd_id, bool allowhighfees, - void (*failed)(struct channel *, - bool success, - const char *err)); + void (*finished)(struct channel *, + bool success, + const char *err)); struct chain_topology *new_topology(struct lightningd *ld, struct log *log); void setup_topology(struct chain_topology *topology, From 2750d1d42ddf77d61b2a039eb067732061ecb712 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 23 Mar 2023 16:13:52 +1030 Subject: [PATCH 02/13] bitcoin: helpers to clone a bitcoin_tx, and format one. Signed-off-by: Rusty Russell --- ...-tx-bitcoin_tx_2of2_input_witness_weight.c | 3 +++ bitcoin/tx.c | 27 ++++++++++++++++++- bitcoin/tx.h | 5 ++++ lightningd/test/run-invoice-select-inchan.c | 6 ++--- wallet/test/run-wallet.c | 6 ++--- 5 files changed, 40 insertions(+), 7 deletions(-) diff --git a/bitcoin/test/run-tx-bitcoin_tx_2of2_input_witness_weight.c b/bitcoin/test/run-tx-bitcoin_tx_2of2_input_witness_weight.c index 05892c964618..305c400c2272 100644 --- a/bitcoin/test/run-tx-bitcoin_tx_2of2_input_witness_weight.c +++ b/bitcoin/test/run-tx-bitcoin_tx_2of2_input_witness_weight.c @@ -38,6 +38,9 @@ struct amount_asset amount_sat_to_asset(struct amount_sat *sat UNNEEDED, const u /* Generated stub for amount_tx_fee */ struct amount_sat amount_tx_fee(u32 fee_per_kw UNNEEDED, size_t weight UNNEEDED) { fprintf(stderr, "amount_tx_fee called!\n"); abort(); } +/* Generated stub for clone_psbt */ +struct wally_psbt *clone_psbt(const tal_t *ctx UNNEEDED, struct wally_psbt *psbt UNNEEDED) +{ fprintf(stderr, "clone_psbt called!\n"); abort(); } /* Generated stub for fromwire */ const u8 *fromwire(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *copy UNNEEDED, size_t n UNNEEDED) { fprintf(stderr, "fromwire called!\n"); abort(); } diff --git a/bitcoin/tx.c b/bitcoin/tx.c index 95179823449f..cd132acc4259 100644 --- a/bitcoin/tx.c +++ b/bitcoin/tx.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -590,6 +591,30 @@ struct bitcoin_tx *bitcoin_tx_with_psbt(const tal_t *ctx, struct wally_psbt *psb return tx; } +struct bitcoin_tx *clone_bitcoin_tx(const tal_t *ctx, + const struct bitcoin_tx *tx) +{ + struct bitcoin_tx *newtx; + + if (taken(tx)) + return cast_const(struct bitcoin_tx *, tx); + + newtx = tal(ctx, struct bitcoin_tx); + + newtx->chainparams = tx->chainparams; + + tal_wally_start(); + if (wally_tx_clone_alloc(tx->wtx, 0, &newtx->wtx) != WALLY_OK) + newtx->wtx = NULL; + tal_wally_end_onto(newtx, newtx->wtx, struct wally_tx); + if (!newtx->wtx) + return tal_free(newtx); + + newtx->psbt = clone_psbt(newtx, tx->psbt); + tal_add_destructor(newtx, bitcoin_tx_destroy); + return newtx; +} + static struct wally_tx *pull_wtx(const tal_t *ctx, const u8 **cursor, size_t *max) @@ -699,7 +724,7 @@ bool bitcoin_txid_to_hex(const struct bitcoin_txid *txid, return hex_encode(&rev, sizeof(rev), hexstr, hexstr_len); } -static char *fmt_bitcoin_tx(const tal_t *ctx, const struct bitcoin_tx *tx) +char *fmt_bitcoin_tx(const tal_t *ctx, const struct bitcoin_tx *tx) { u8 *lin = linearize_tx(ctx, tx); char *s = tal_hex(ctx, lin); diff --git a/bitcoin/tx.h b/bitcoin/tx.h index cb0903ccf40d..476764b57aba 100644 --- a/bitcoin/tx.h +++ b/bitcoin/tx.h @@ -69,6 +69,10 @@ struct bitcoin_tx *bitcoin_tx(const tal_t *ctx, varint_t input_count, varint_t output_count, u32 nlocktime); +/* Make a (deep) copy */ +struct bitcoin_tx *clone_bitcoin_tx(const tal_t *ctx, + const struct bitcoin_tx *tx TAKES); + /* This takes a raw bitcoin tx in hex. */ struct bitcoin_tx *bitcoin_tx_from_hex(const tal_t *ctx, const char *hex, size_t hexlen); @@ -285,6 +289,7 @@ void towire_bitcoin_tx(u8 **pptr, const struct bitcoin_tx *tx); void towire_bitcoin_outpoint(u8 **pptr, const struct bitcoin_outpoint *outp); void fromwire_bitcoin_outpoint(const u8 **cursor, size_t *max, struct bitcoin_outpoint *outp); +char *fmt_bitcoin_tx(const tal_t *ctx, const struct bitcoin_tx *tx); /* Various weights of transaction parts. */ size_t bitcoin_tx_core_weight(size_t num_inputs, size_t num_outputs); diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index e830e40f56b4..da1e2b28b3c6 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -55,9 +55,9 @@ char *bolt11_encode_(const tal_t *ctx UNNEEDED, void broadcast_tx(struct chain_topology *topo UNNEEDED, struct channel *channel UNNEEDED, const struct bitcoin_tx *tx UNNEEDED, const char *cmd_id UNNEEDED, bool allowhighfees UNNEEDED, - void (*failed)(struct channel * UNNEEDED, - bool success UNNEEDED, - const char *err)) + void (*finished)(struct channel * UNNEEDED, + bool success UNNEEDED, + const char *err)) { fprintf(stderr, "broadcast_tx called!\n"); abort(); } /* Generated stub for channel_change_state_reason_str */ const char *channel_change_state_reason_str(enum state_change reason UNNEEDED) diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 63eb6c608dac..f26528ee8de5 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -72,9 +72,9 @@ bool blinding_next_pubkey(const struct pubkey *pk UNNEEDED, void broadcast_tx(struct chain_topology *topo UNNEEDED, struct channel *channel UNNEEDED, const struct bitcoin_tx *tx UNNEEDED, const char *cmd_id UNNEEDED, bool allowhighfees UNNEEDED, - void (*failed)(struct channel * UNNEEDED, - bool success UNNEEDED, - const char *err)) + void (*finished)(struct channel * UNNEEDED, + bool success UNNEEDED, + const char *err)) { fprintf(stderr, "broadcast_tx called!\n"); abort(); } /* Generated stub for channel_tell_depth */ bool channel_tell_depth(struct lightningd *ld UNNEEDED, From 2ffaca157be2500c98009c72ba9bc8acebe5c22b Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 23 Mar 2023 16:14:52 +1030 Subject: [PATCH 03/13] lightningd: rebroadcast code save actual tx, not just hex encoding. Signed-off-by: Rusty Russell --- lightningd/chaintopology.c | 9 ++++----- lightningd/chaintopology.h | 5 +++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lightningd/chaintopology.c b/lightningd/chaintopology.c index 604d086ad114..9b7817b97dc0 100644 --- a/lightningd/chaintopology.c +++ b/lightningd/chaintopology.c @@ -167,7 +167,7 @@ static void rebroadcast_txs(struct chain_topology *topo) if (wallet_transaction_height(topo->ld->wallet, &otx->txid)) continue; - tal_arr_expand(&txs->txs, tal_strdup(txs, otx->hextx)); + tal_arr_expand(&txs->txs, fmt_bitcoin_tx(txs->txs, otx->tx)); tal_arr_expand(&txs->cmd_id, otx->cmd_id ? tal_strdup(txs, otx->cmd_id) : NULL); } @@ -229,17 +229,15 @@ void broadcast_tx(struct chain_topology *topo, { /* Channel might vanish: topo owns it to start with. */ struct outgoing_tx *otx = tal(topo, struct outgoing_tx); - const u8 *rawtx = linearize_tx(otx, tx); otx->channel = channel; bitcoin_txid(tx, &otx->txid); - otx->hextx = tal_hex(otx, rawtx); + otx->tx = clone_bitcoin_tx(otx, tx); otx->finished = finished; if (cmd_id) otx->cmd_id = tal_strdup(otx, cmd_id); else otx->cmd_id = NULL; - tal_free(rawtx); tal_add_destructor2(channel, clear_otx_channel, otx); log_debug(topo->log, "Broadcasting txid %s%s%s", @@ -247,7 +245,8 @@ void broadcast_tx(struct chain_topology *topo, cmd_id ? " for " : "", cmd_id ? cmd_id : ""); wallet_transaction_add(topo->ld->wallet, tx->wtx, 0, 0); - bitcoind_sendrawtx(topo->bitcoind, otx->cmd_id, otx->hextx, + bitcoind_sendrawtx(topo->bitcoind, otx->cmd_id, + fmt_bitcoin_tx(tmpctx, otx->tx), allowhighfees, broadcast_done, otx); } diff --git a/lightningd/chaintopology.h b/lightningd/chaintopology.h index 7ebddc079b34..87f0a285e44c 100644 --- a/lightningd/chaintopology.h +++ b/lightningd/chaintopology.h @@ -19,7 +19,7 @@ struct txwatch; /* Off topology->outgoing_txs */ struct outgoing_tx { struct channel *channel; - const char *hextx; + const struct bitcoin_tx *tx; struct bitcoin_txid txid; const char *cmd_id; void (*finished)(struct channel *channel, bool success, const char *err); @@ -181,7 +181,8 @@ u32 penalty_feerate(struct chain_topology *topo); * @finished: if non-NULL, call that and don't rebroadcast. */ void broadcast_tx(struct chain_topology *topo, - struct channel *channel, const struct bitcoin_tx *tx, + struct channel *channel, + const struct bitcoin_tx *tx TAKES, const char *cmd_id, bool allowhighfees, void (*finished)(struct channel *, bool success, From c79729372c32388796843b2322da722f47eba816 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 23 Mar 2023 16:15:52 +1030 Subject: [PATCH 04/13] lightningd: provide callback in broadcast_tx() for refreshing tx. We'll use this to do RBF. Signed-off-by: Rusty Russell --- lightningd/chaintopology.c | 29 +++++++++++++++---- lightningd/chaintopology.h | 31 ++++++++++++++++----- lightningd/onchain_control.c | 3 +- lightningd/peer_control.c | 3 +- lightningd/test/run-invoice-select-inchan.c | 19 +++++++------ wallet/test/run-wallet.c | 19 +++++++------ 6 files changed, 73 insertions(+), 31 deletions(-) diff --git a/lightningd/chaintopology.c b/lightningd/chaintopology.c index 9b7817b97dc0..d1035ee5c776 100644 --- a/lightningd/chaintopology.c +++ b/lightningd/chaintopology.c @@ -155,6 +155,7 @@ static void rebroadcast_txs(struct chain_topology *topo) struct txs_to_broadcast *txs; struct outgoing_tx *otx; struct outgoing_tx_map_iter it; + tal_t *cleanup_ctx = tal(NULL, char); txs = tal(topo, struct txs_to_broadcast); txs->cmd_id = tal_arr(txs, const char *, 0); @@ -167,10 +168,18 @@ static void rebroadcast_txs(struct chain_topology *topo) if (wallet_transaction_height(topo->ld->wallet, &otx->txid)) continue; + /* Don't free from txmap inside loop! */ + if (otx->refresh + && !otx->refresh(otx->channel, &otx->tx, otx->refresh_arg)) { + tal_steal(cleanup_ctx, otx); + continue; + } + tal_arr_expand(&txs->txs, fmt_bitcoin_tx(txs->txs, otx->tx)); tal_arr_expand(&txs->cmd_id, otx->cmd_id ? tal_strdup(txs, otx->cmd_id) : NULL); } + tal_free(cleanup_ctx); /* Let this do the dirty work. */ txs->cursor = (size_t)-1; @@ -220,12 +229,16 @@ static void broadcast_done(struct bitcoind *bitcoind, } } -void broadcast_tx(struct chain_topology *topo, - struct channel *channel, const struct bitcoin_tx *tx, - const char *cmd_id, bool allowhighfees, - void (*finished)(struct channel *channel, - bool success, - const char *err)) +void broadcast_tx_(struct chain_topology *topo, + struct channel *channel, const struct bitcoin_tx *tx, + const char *cmd_id, bool allowhighfees, + void (*finished)(struct channel *channel, + bool success, + const char *err), + bool (*refresh)(struct channel *channel, + const struct bitcoin_tx **tx, + void *arg), + void *refresh_arg) { /* Channel might vanish: topo owns it to start with. */ struct outgoing_tx *otx = tal(topo, struct outgoing_tx); @@ -234,6 +247,10 @@ void broadcast_tx(struct chain_topology *topo, bitcoin_txid(tx, &otx->txid); otx->tx = clone_bitcoin_tx(otx, tx); otx->finished = finished; + otx->refresh = refresh; + otx->refresh_arg = refresh_arg; + if (taken(otx->refresh_arg)) + tal_steal(otx, otx->refresh_arg); if (cmd_id) otx->cmd_id = tal_strdup(otx, cmd_id); else diff --git a/lightningd/chaintopology.h b/lightningd/chaintopology.h index 87f0a285e44c..fa3b1f56aab5 100644 --- a/lightningd/chaintopology.h +++ b/lightningd/chaintopology.h @@ -23,6 +23,8 @@ struct outgoing_tx { struct bitcoin_txid txid; const char *cmd_id; void (*finished)(struct channel *channel, bool success, const char *err); + bool (*refresh)(struct channel *, const struct bitcoin_tx **, void *arg); + void *refresh_arg; }; struct block { @@ -179,14 +181,29 @@ u32 penalty_feerate(struct chain_topology *topo); * @cmd_id: the JSON command id which triggered this (or NULL). * @allowhighfees: set to true to override the high-fee checks in the backend. * @finished: if non-NULL, call that and don't rebroadcast. + * @refresh: if non-NULL, callback before re-broadcasting (can replace tx): + * if returns false, delete. + * @refresh_arg: argument for @refresh */ -void broadcast_tx(struct chain_topology *topo, - struct channel *channel, - const struct bitcoin_tx *tx TAKES, - const char *cmd_id, bool allowhighfees, - void (*finished)(struct channel *, - bool success, - const char *err)); +#define broadcast_tx(topo, channel, tx, cmd_id, allowhighfees, \ + finished, refresh, refresh_arg) \ + broadcast_tx_((topo), (channel), (tx), (cmd_id), (allowhighfees), \ + (finished), \ + typesafe_cb_preargs(bool, void *, \ + (refresh), (refresh_arg), \ + struct channel *, \ + const struct bitcoin_tx **), \ + (refresh_arg)) + +void broadcast_tx_(struct chain_topology *topo, + struct channel *channel, + const struct bitcoin_tx *tx TAKES, + const char *cmd_id, bool allowhighfees, + void (*finished)(struct channel *, + bool success, + const char *err), + bool (*refresh)(struct channel *, const struct bitcoin_tx **, void *), + void *refresh_arg TAKES); struct chain_topology *new_topology(struct lightningd *ld, struct log *log); void setup_topology(struct chain_topology *topology, diff --git a/lightningd/onchain_control.c b/lightningd/onchain_control.c index c243b47358bc..a472e7355daa 100644 --- a/lightningd/onchain_control.c +++ b/lightningd/onchain_control.c @@ -346,7 +346,8 @@ static void handle_onchain_broadcast_tx(struct channel *channel, * high feerates as protection against the MAD-HTLC attack. */ broadcast_tx(channel->peer->ld->topology, channel, tx, NULL, is_rbf, - is_rbf ? &handle_onchain_broadcast_rbf_tx_cb : NULL); + is_rbf ? &handle_onchain_broadcast_rbf_tx_cb : NULL, + NULL, NULL); } static void handle_onchain_unwatch_tx(struct channel *channel, const u8 *msg) diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 71c15a8f2d53..624cd4efa86c 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -284,7 +284,8 @@ static void sign_and_send_last(struct lightningd *ld, /* Keep broadcasting until we say stop (can fail due to dup, * if they beat us to the broadcast). */ - broadcast_tx(ld->topology, channel, last_tx, cmd_id, false, NULL); + broadcast_tx(ld->topology, channel, last_tx, cmd_id, false, NULL, + NULL, NULL); remove_sig(last_tx); } diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index da1e2b28b3c6..0e999e83292f 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -51,14 +51,17 @@ char *bolt11_encode_(const tal_t *ctx UNNEEDED, void *arg) UNNEEDED, void *arg UNNEEDED) { fprintf(stderr, "bolt11_encode_ called!\n"); abort(); } -/* Generated stub for broadcast_tx */ -void broadcast_tx(struct chain_topology *topo UNNEEDED, - struct channel *channel UNNEEDED, const struct bitcoin_tx *tx UNNEEDED, - const char *cmd_id UNNEEDED, bool allowhighfees UNNEEDED, - void (*finished)(struct channel * UNNEEDED, - bool success UNNEEDED, - const char *err)) -{ fprintf(stderr, "broadcast_tx called!\n"); abort(); } +/* Generated stub for broadcast_tx_ */ +void broadcast_tx_(struct chain_topology *topo UNNEEDED, + struct channel *channel UNNEEDED, + const struct bitcoin_tx *tx TAKES UNNEEDED, + const char *cmd_id UNNEEDED, bool allowhighfees UNNEEDED, + void (*finished)(struct channel * UNNEEDED, + bool success UNNEEDED, + const char *err) UNNEEDED, + bool (*refresh)(struct channel * UNNEEDED, const struct bitcoin_tx ** UNNEEDED, void *) UNNEEDED, + void *refresh_arg TAKES UNNEEDED) +{ fprintf(stderr, "broadcast_tx_ called!\n"); abort(); } /* Generated stub for channel_change_state_reason_str */ const char *channel_change_state_reason_str(enum state_change reason UNNEEDED) { fprintf(stderr, "channel_change_state_reason_str called!\n"); abort(); } diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index f26528ee8de5..b91e285a8c16 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -68,14 +68,17 @@ bool blinding_next_pubkey(const struct pubkey *pk UNNEEDED, const struct sha256 *h UNNEEDED, struct pubkey *next UNNEEDED) { fprintf(stderr, "blinding_next_pubkey called!\n"); abort(); } -/* Generated stub for broadcast_tx */ -void broadcast_tx(struct chain_topology *topo UNNEEDED, - struct channel *channel UNNEEDED, const struct bitcoin_tx *tx UNNEEDED, - const char *cmd_id UNNEEDED, bool allowhighfees UNNEEDED, - void (*finished)(struct channel * UNNEEDED, - bool success UNNEEDED, - const char *err)) -{ fprintf(stderr, "broadcast_tx called!\n"); abort(); } +/* Generated stub for broadcast_tx_ */ +void broadcast_tx_(struct chain_topology *topo UNNEEDED, + struct channel *channel UNNEEDED, + const struct bitcoin_tx *tx TAKES UNNEEDED, + const char *cmd_id UNNEEDED, bool allowhighfees UNNEEDED, + void (*finished)(struct channel * UNNEEDED, + bool success UNNEEDED, + const char *err) UNNEEDED, + bool (*refresh)(struct channel * UNNEEDED, const struct bitcoin_tx ** UNNEEDED, void *) UNNEEDED, + void *refresh_arg TAKES UNNEEDED) +{ fprintf(stderr, "broadcast_tx_ called!\n"); abort(); } /* Generated stub for channel_tell_depth */ bool channel_tell_depth(struct lightningd *ld UNNEEDED, struct channel *channel UNNEEDED, From 784a1849007954b1aaf17ad839cde13df3ec3b3e Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 23 Mar 2023 16:16:52 +1030 Subject: [PATCH 05/13] lightningd: don't use notleak in chaintopology.c We can add the htable to the memleak detection, and we already do this for the watches. Signed-off-by: Rusty Russell --- lightningd/chaintopology.c | 9 ++++----- lightningd/memdump.c | 1 + 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lightningd/chaintopology.c b/lightningd/chaintopology.c index d1035ee5c776..12f44dd3cd6a 100644 --- a/lightningd/chaintopology.c +++ b/lightningd/chaintopology.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -224,7 +223,7 @@ static void broadcast_done(struct bitcoind *bitcoind, } else { /* For continual rebroadcasting, until channel freed. */ tal_steal(otx->channel, otx); - outgoing_tx_map_add(bitcoind->ld->topology->outgoing_txs, notleak(otx)); + outgoing_tx_map_add(bitcoind->ld->topology->outgoing_txs, otx); tal_add_destructor2(otx, destroy_outgoing_tx, bitcoind->ld->topology); } } @@ -324,9 +323,9 @@ static void watch_for_utxo_reconfirmation(struct chain_topology *topo, if (find_txwatch(topo, &unconfirmed[i]->outpoint.txid, NULL)) continue; - notleak(watch_txid(topo, topo, NULL, - &unconfirmed[i]->outpoint.txid, - closeinfo_txid_confirmed)); + watch_txid(topo, topo, NULL, + &unconfirmed[i]->outpoint.txid, + closeinfo_txid_confirmed); } } diff --git a/lightningd/memdump.c b/lightningd/memdump.c index 64cfa6bec39f..dcca47368a4b 100644 --- a/lightningd/memdump.c +++ b/lightningd/memdump.c @@ -152,6 +152,7 @@ static void finish_report(const struct leak_detect *leaks) /* First delete known false positives. */ memleak_scan_htable(memtable, &ld->topology->txwatches->raw); memleak_scan_htable(memtable, &ld->topology->txowatches->raw); + memleak_scan_htable(memtable, &ld->topology->outgoing_txs->raw); memleak_scan_htable(memtable, &ld->htlcs_in->raw); memleak_scan_htable(memtable, &ld->htlcs_out->raw); memleak_scan_htable(memtable, &ld->htlc_sets->raw); From 0f14b364109bfa5d0842239176eda7e942e354c3 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 23 Mar 2023 16:17:52 +1030 Subject: [PATCH 06/13] chaintopology: allow minblock for broadcast_tx. Fun story. We're changing onchaind to hand txs to us, and we will construct them and do the broadcast for it. lightningd tells onchaind the witness it used (with flags to indicate which fields were signatures so should be ignored) so onchaind can recognize the tx when/if it is mined. And when onchaind was waiting for a CLTV delay, it wouldn't tell lightningd yet, but wait until the parent was sufficiently deep But this caused bugs! In particular, on replay, onchaind would see transactions which it hasn't sent yet. This was not a problem before, as onchaind had created the tx, even if it hadn't told lightningd to broadcast it, so recognized the variant when it came in. When we're relying on lightningd to tell us what the tx will look like, this doesn't work any more. The cause of this is that we fire off txowatches ("this output was spent!") while we process blocks, and only fire off txwatches ("this tx increased depth") once all the current blocks are processed. Often this didn't matter, since we replay messages to onchaind from the database, *but* we trim the last few blocks on restart (or, if there's a small reorg while we're stopped), and we can hit this misordering. Changing our topology code to only ever process one block at a time would be a solution, but slows down catchup (and tests, where we often mine a run of blocks). So, this seems like a premature optimization, but it's really required! And in future, lightningd can use this knowledge of pending transactions to combine them in more clever ways. Note that if a tx is valid at block N, we broadcast it once we see block N-1, to get it in the mempool for block N. Signed-off-by: Rusty Russell --- lightningd/chaintopology.c | 26 ++++++++++++++++++--- lightningd/chaintopology.h | 8 ++++--- lightningd/onchain_control.c | 2 +- lightningd/peer_control.c | 2 +- lightningd/test/run-invoice-select-inchan.c | 2 +- wallet/test/run-wallet.c | 2 +- 6 files changed, 32 insertions(+), 10 deletions(-) diff --git a/lightningd/chaintopology.c b/lightningd/chaintopology.c index 12f44dd3cd6a..9cc00d9a79b4 100644 --- a/lightningd/chaintopology.c +++ b/lightningd/chaintopology.c @@ -167,6 +167,11 @@ static void rebroadcast_txs(struct chain_topology *topo) if (wallet_transaction_height(topo->ld->wallet, &otx->txid)) continue; + /* Don't send ones which aren't ready yet. Note that if the + * minimum block is N, we broadcast it when we have block N-1! */ + if (get_block_height(topo) + 1 < otx->minblock) + continue; + /* Don't free from txmap inside loop! */ if (otx->refresh && !otx->refresh(otx->channel, &otx->tx, otx->refresh_arg)) { @@ -230,7 +235,7 @@ static void broadcast_done(struct bitcoind *bitcoind, void broadcast_tx_(struct chain_topology *topo, struct channel *channel, const struct bitcoin_tx *tx, - const char *cmd_id, bool allowhighfees, + const char *cmd_id, bool allowhighfees, u32 minblock, void (*finished)(struct channel *channel, bool success, const char *err), @@ -245,6 +250,7 @@ void broadcast_tx_(struct chain_topology *topo, otx->channel = channel; bitcoin_txid(tx, &otx->txid); otx->tx = clone_bitcoin_tx(otx, tx); + otx->minblock = minblock; otx->finished = finished; otx->refresh = refresh; otx->refresh_arg = refresh_arg; @@ -254,8 +260,22 @@ void broadcast_tx_(struct chain_topology *topo, otx->cmd_id = tal_strdup(otx, cmd_id); else otx->cmd_id = NULL; - tal_add_destructor2(channel, clear_otx_channel, otx); + /* Note that if the minimum block is N, we broadcast it when + * we have block N-1! */ + if (get_block_height(topo) + 1 < otx->minblock) { + log_debug(topo->log, "Deferring broadcast of txid %s until block %u", + type_to_string(tmpctx, struct bitcoin_txid, &otx->txid), + otx->minblock - 1); + + /* For continual rebroadcasting, until channel freed. */ + tal_steal(otx->channel, otx); + outgoing_tx_map_add(topo->outgoing_txs, otx); + tal_add_destructor2(otx, destroy_outgoing_tx, topo); + return; + } + + tal_add_destructor2(channel, clear_otx_channel, otx); log_debug(topo->log, "Broadcasting txid %s%s%s", type_to_string(tmpctx, struct bitcoin_txid, &otx->txid), cmd_id ? " for " : "", cmd_id ? cmd_id : ""); @@ -372,7 +392,7 @@ static void update_feerates(struct bitcoind *bitcoind, /* Initial smoothed feerate is the polled feerate */ if (!old_feerates[i]) { - notify_feerate_changed = true; + notify_feerate_changed = true; old_feerates[i] = feerate; init_feerate_history(topo, i, feerate); diff --git a/lightningd/chaintopology.h b/lightningd/chaintopology.h index fa3b1f56aab5..486fab0f3e10 100644 --- a/lightningd/chaintopology.h +++ b/lightningd/chaintopology.h @@ -21,6 +21,7 @@ struct outgoing_tx { struct channel *channel; const struct bitcoin_tx *tx; struct bitcoin_txid txid; + u32 minblock; const char *cmd_id; void (*finished)(struct channel *channel, bool success, const char *err); bool (*refresh)(struct channel *, const struct bitcoin_tx **, void *arg); @@ -180,15 +181,16 @@ u32 penalty_feerate(struct chain_topology *topo); * @tx: the transaction * @cmd_id: the JSON command id which triggered this (or NULL). * @allowhighfees: set to true to override the high-fee checks in the backend. + * @minblock: minimum block we can send it at (or 0). * @finished: if non-NULL, call that and don't rebroadcast. * @refresh: if non-NULL, callback before re-broadcasting (can replace tx): * if returns false, delete. * @refresh_arg: argument for @refresh */ #define broadcast_tx(topo, channel, tx, cmd_id, allowhighfees, \ - finished, refresh, refresh_arg) \ + minblock, finished, refresh, refresh_arg) \ broadcast_tx_((topo), (channel), (tx), (cmd_id), (allowhighfees), \ - (finished), \ + (minblock), (finished), \ typesafe_cb_preargs(bool, void *, \ (refresh), (refresh_arg), \ struct channel *, \ @@ -198,7 +200,7 @@ u32 penalty_feerate(struct chain_topology *topo); void broadcast_tx_(struct chain_topology *topo, struct channel *channel, const struct bitcoin_tx *tx TAKES, - const char *cmd_id, bool allowhighfees, + const char *cmd_id, bool allowhighfees, u32 minblock, void (*finished)(struct channel *, bool success, const char *err), diff --git a/lightningd/onchain_control.c b/lightningd/onchain_control.c index a472e7355daa..c1372e5ad00b 100644 --- a/lightningd/onchain_control.c +++ b/lightningd/onchain_control.c @@ -345,7 +345,7 @@ static void handle_onchain_broadcast_tx(struct channel *channel, * set allowhighfees, as the transaction may be RBFed into * high feerates as protection against the MAD-HTLC attack. */ broadcast_tx(channel->peer->ld->topology, channel, - tx, NULL, is_rbf, + tx, NULL, is_rbf, 0, is_rbf ? &handle_onchain_broadcast_rbf_tx_cb : NULL, NULL, NULL); } diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 624cd4efa86c..bba5ef9e8449 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -284,7 +284,7 @@ static void sign_and_send_last(struct lightningd *ld, /* Keep broadcasting until we say stop (can fail due to dup, * if they beat us to the broadcast). */ - broadcast_tx(ld->topology, channel, last_tx, cmd_id, false, NULL, + broadcast_tx(ld->topology, channel, last_tx, cmd_id, false, 0, NULL, NULL, NULL); remove_sig(last_tx); diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index 0e999e83292f..fe9ea8022b08 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -55,7 +55,7 @@ char *bolt11_encode_(const tal_t *ctx UNNEEDED, void broadcast_tx_(struct chain_topology *topo UNNEEDED, struct channel *channel UNNEEDED, const struct bitcoin_tx *tx TAKES UNNEEDED, - const char *cmd_id UNNEEDED, bool allowhighfees UNNEEDED, + const char *cmd_id UNNEEDED, bool allowhighfees UNNEEDED, u32 minblock UNNEEDED, void (*finished)(struct channel * UNNEEDED, bool success UNNEEDED, const char *err) UNNEEDED, diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index b91e285a8c16..27b2abae5327 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -72,7 +72,7 @@ bool blinding_next_pubkey(const struct pubkey *pk UNNEEDED, void broadcast_tx_(struct chain_topology *topo UNNEEDED, struct channel *channel UNNEEDED, const struct bitcoin_tx *tx TAKES UNNEEDED, - const char *cmd_id UNNEEDED, bool allowhighfees UNNEEDED, + const char *cmd_id UNNEEDED, bool allowhighfees UNNEEDED, u32 minblock UNNEEDED, void (*finished)(struct channel * UNNEEDED, bool success UNNEEDED, const char *err) UNNEEDED, From eb7b956ed2ce3aa0d6d91791ef8402a605f14b21 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 23 Mar 2023 16:18:09 +1030 Subject: [PATCH 07/13] bitcoin: add tx_feerate() to reverse-calculate feerate a tx paid. Signed-off-by: Rusty Russell --- bitcoin/test/run-bitcoin_block_from_hex.c | 6 ++++ bitcoin/test/run-psbt-from-tx.c | 6 ++++ ...-tx-bitcoin_tx_2of2_input_witness_weight.c | 6 ++++ bitcoin/test/run-tx-encode.c | 6 ++++ bitcoin/tx.c | 11 ++++++++ bitcoin/tx.h | 6 ++++ channeld/commit_tx.c | 4 +-- channeld/test/run-commit_tx.c | 28 ++++++++++++++----- cli/test/run-human-mode.c | 6 ++++ cli/test/run-large-input.c | 6 ++++ cli/test/run-remove-hint.c | 6 ++++ common/test/run-base64.c | 6 ++++ common/test/run-bigsize.c | 6 ++++ common/test/run-blindedpath_enctlv.c | 6 ++++ common/test/run-blindedpath_onion.c | 6 ++++ common/test/run-bolt12_decode.c | 6 ++++ common/test/run-bolt12_period.c | 6 ++++ common/test/run-cryptomsg.c | 6 ++++ common/test/run-derive_basepoints.c | 6 ++++ common/test/run-features.c | 6 ++++ common/test/run-gossmap-fp16.c | 6 ++++ common/test/run-ip_port_parsing.c | 6 ++++ common/test/run-json_remove.c | 6 ++++ common/test/run-json_scan.c | 6 ++++ common/test/run-json_stream-filter.c | 6 ++++ common/test/run-key_derive.c | 6 ++++ common/test/run-onion-test-vector.c | 6 ++++ common/test/run-softref.c | 6 ++++ common/test/run-sphinx-xor_cipher_stream.c | 6 ++++ common/test/run-sphinx.c | 6 ++++ common/test/run-tlv_span.c | 6 ++++ common/test/run-wireaddr.c | 6 ++++ connectd/test/run-gossip_rcvd_filter.c | 6 ++++ connectd/test/run-initiator-success.c | 6 ++++ connectd/test/run-netaddress.c | 6 ++++ connectd/test/run-responder-success.c | 6 ++++ connectd/test/run-websocket.c | 6 ++++ 37 files changed, 238 insertions(+), 9 deletions(-) diff --git a/bitcoin/test/run-bitcoin_block_from_hex.c b/bitcoin/test/run-bitcoin_block_from_hex.c index 0e2eefa952a4..579916a69b90 100644 --- a/bitcoin/test/run-bitcoin_block_from_hex.c +++ b/bitcoin/test/run-bitcoin_block_from_hex.c @@ -24,12 +24,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/bitcoin/test/run-psbt-from-tx.c b/bitcoin/test/run-psbt-from-tx.c index f05809728489..f3908f377abe 100644 --- a/bitcoin/test/run-psbt-from-tx.c +++ b/bitcoin/test/run-psbt-from-tx.c @@ -23,12 +23,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/bitcoin/test/run-tx-bitcoin_tx_2of2_input_witness_weight.c b/bitcoin/test/run-tx-bitcoin_tx_2of2_input_witness_weight.c index 305c400c2272..582461423359 100644 --- a/bitcoin/test/run-tx-bitcoin_tx_2of2_input_witness_weight.c +++ b/bitcoin/test/run-tx-bitcoin_tx_2of2_input_witness_weight.c @@ -24,9 +24,15 @@ struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* Generated stub for amount_sat_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/bitcoin/test/run-tx-encode.c b/bitcoin/test/run-tx-encode.c index aecd28ab24a7..d45f51ee0d3a 100644 --- a/bitcoin/test/run-tx-encode.c +++ b/bitcoin/test/run-tx-encode.c @@ -25,12 +25,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/bitcoin/tx.c b/bitcoin/tx.c index cd132acc4259..37d2a9a616a2 100644 --- a/bitcoin/tx.c +++ b/bitcoin/tx.c @@ -980,3 +980,14 @@ struct amount_sat change_amount(struct amount_sat excess, u32 feerate_perkw, return excess; } + +u32 tx_feerate(const struct bitcoin_tx *tx) +{ + struct amount_sat fee = bitcoin_tx_compute_fee(tx); + + /* Fee should not overflow! */ + if (!amount_sat_mul(&fee, fee, 1000)) + abort(); + + return amount_sat_div(fee, bitcoin_tx_weight(tx)).satoshis; /* Raw: txfee */ +} diff --git a/bitcoin/tx.h b/bitcoin/tx.h index 476764b57aba..34c9afb56827 100644 --- a/bitcoin/tx.h +++ b/bitcoin/tx.h @@ -270,6 +270,12 @@ static inline size_t elements_tx_overhead(const struct chainparams *chainparams, */ struct amount_sat bitcoin_tx_compute_fee(const struct bitcoin_tx *tx); +/** + * Calculate the feerate for this transaction (in perkw) +*/ +u32 tx_feerate(const struct bitcoin_tx *tx); + + /* * Calculate the fees for this transaction, given a pre-computed input balance. * diff --git a/channeld/commit_tx.c b/channeld/commit_tx.c index 6f8c41c8320b..43851498ff53 100644 --- a/channeld/commit_tx.c +++ b/channeld/commit_tx.c @@ -156,8 +156,8 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx, base_fee = commit_tx_base_fee(feerate_per_kw, untrimmed, option_anchor_outputs); - SUPERVERBOSE("# base commitment transaction fee = %"PRIu64"\n", - base_fee.satoshis /* Raw: spec uses raw numbers */); + SUPERVERBOSE("# base commitment transaction fee = %"PRIu64" for %zu untrimmed\n", + base_fee.satoshis /* Raw: spec uses raw numbers */, untrimmed); /* BOLT #3: * If `option_anchors` applies to the commitment diff --git a/channeld/test/run-commit_tx.c b/channeld/test/run-commit_tx.c index f222e7ae3d59..546c4c097d73 100644 --- a/channeld/test/run-commit_tx.c +++ b/channeld/test/run-commit_tx.c @@ -380,7 +380,8 @@ static void report(struct bitcoin_tx *tx, const struct pubkey *remote_revocation_key, u32 feerate_per_kw, bool option_anchor_outputs, - const struct htlc **htlc_map) + const struct htlc **htlc_map, + size_t total_htlcs) { char *txhex; struct bitcoin_signature localsig, remotesig; @@ -410,6 +411,13 @@ static void report(struct bitcoin_tx *tx, txhex = tal_hex(tmpctx, linearize_tx(tx, tx)); printf("output commit_tx: %s\n", txhex); + /* Now signatures are attached, this should be correct. But note + * that spec uses worst-case weight, so we will be slightly higher. */ + assert(tx_feerate(tx) >= feerate_per_kw); + /* Of course, trimmed htlcs magnify this! */ + if (tx->wtx->num_outputs == total_htlcs + 2) + assert(tx_feerate(tx) <= feerate_per_kw * 1.01); + report_htlcs(tx, htlc_map, to_self_delay, local_htlcsecretkey, localkey, local_htlckey, local_delayedkey, @@ -837,7 +845,8 @@ int main(int argc, const char *argv[]) &remote_revocation_key, feerate_per_kw, option_anchor_outputs, - htlc_map); + htlc_map, + 0); /* BOLT #3: * @@ -903,7 +912,8 @@ int main(int argc, const char *argv[]) &remote_revocation_key, feerate_per_kw, option_anchor_outputs, - htlc_map); + htlc_map, + tal_count(htlcs)); do { struct bitcoin_tx *newtx; @@ -1000,7 +1010,8 @@ int main(int argc, const char *argv[]) &remote_revocation_key, feerate_per_kw-1, option_anchor_outputs, - htlc_map); + htlc_map, + tal_count(htlcs)); printf("\n" "name: commitment tx with %s untrimmed (minimum feerate)\n" @@ -1049,7 +1060,8 @@ int main(int argc, const char *argv[]) &remote_revocation_key, feerate_per_kw, option_anchor_outputs, - htlc_map); + htlc_map, + tal_count(htlcs)); assert(newtx->wtx->num_outputs != tx->wtx->num_outputs); @@ -1124,7 +1136,8 @@ int main(int argc, const char *argv[]) &remote_revocation_key, feerate_per_kw, option_anchor_outputs, - htlc_map); + htlc_map, + tal_count(htlcs)); break; } @@ -1195,7 +1208,8 @@ int main(int argc, const char *argv[]) &remote_revocation_key, feerate_per_kw, option_anchor_outputs, - htlc_map); + htlc_map, + tal_count(htlcs)); common_shutdown(); /* FIXME: Do BOLT comparison! */ diff --git a/cli/test/run-human-mode.c b/cli/test/run-human-mode.c index 96b1e31c0a0c..880a790ffa9b 100644 --- a/cli/test/run-human-mode.c +++ b/cli/test/run-human-mode.c @@ -45,12 +45,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/cli/test/run-large-input.c b/cli/test/run-large-input.c index be4f6eb2183f..2e2c0647c82c 100644 --- a/cli/test/run-large-input.c +++ b/cli/test/run-large-input.c @@ -45,12 +45,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/cli/test/run-remove-hint.c b/cli/test/run-remove-hint.c index 7d6dcfc3238c..06783b26fda0 100644 --- a/cli/test/run-remove-hint.c +++ b/cli/test/run-remove-hint.c @@ -48,12 +48,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-base64.c b/common/test/run-base64.c index 97571a5529ae..b3117201ee50 100644 --- a/common/test/run-base64.c +++ b/common/test/run-base64.c @@ -24,12 +24,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-bigsize.c b/common/test/run-bigsize.c index 46590bdb7a91..ef5deec69ad7 100644 --- a/common/test/run-bigsize.c +++ b/common/test/run-bigsize.c @@ -26,12 +26,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-blindedpath_enctlv.c b/common/test/run-blindedpath_enctlv.c index fd88d7cbb1e9..02b669017db7 100644 --- a/common/test/run-blindedpath_enctlv.c +++ b/common/test/run-blindedpath_enctlv.c @@ -26,12 +26,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-blindedpath_onion.c b/common/test/run-blindedpath_onion.c index 5aa521b25945..a25492d828fc 100644 --- a/common/test/run-blindedpath_onion.c +++ b/common/test/run-blindedpath_onion.c @@ -36,12 +36,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-bolt12_decode.c b/common/test/run-bolt12_decode.c index 9043b876e453..6ddf6656dc46 100644 --- a/common/test/run-bolt12_decode.c +++ b/common/test/run-bolt12_decode.c @@ -24,12 +24,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-bolt12_period.c b/common/test/run-bolt12_period.c index 8b44328bda10..d6a44638d9db 100644 --- a/common/test/run-bolt12_period.c +++ b/common/test/run-bolt12_period.c @@ -22,12 +22,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-cryptomsg.c b/common/test/run-cryptomsg.c index 39e18f9df6e1..0229fbe7230f 100644 --- a/common/test/run-cryptomsg.c +++ b/common/test/run-cryptomsg.c @@ -20,12 +20,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-derive_basepoints.c b/common/test/run-derive_basepoints.c index e53b89754eac..89ef438cb73a 100644 --- a/common/test/run-derive_basepoints.c +++ b/common/test/run-derive_basepoints.c @@ -26,12 +26,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-features.c b/common/test/run-features.c index 3e7dbd6db9c3..69ec5e3c8cd7 100644 --- a/common/test/run-features.c +++ b/common/test/run-features.c @@ -19,12 +19,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-gossmap-fp16.c b/common/test/run-gossmap-fp16.c index b7b5ff1ca05a..3ef15580735e 100644 --- a/common/test/run-gossmap-fp16.c +++ b/common/test/run-gossmap-fp16.c @@ -20,12 +20,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-ip_port_parsing.c b/common/test/run-ip_port_parsing.c index 37487f8ebc52..cb2f1b27e5de 100644 --- a/common/test/run-ip_port_parsing.c +++ b/common/test/run-ip_port_parsing.c @@ -21,12 +21,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-json_remove.c b/common/test/run-json_remove.c index 99ae0122a938..3b25bd141f71 100644 --- a/common/test/run-json_remove.c +++ b/common/test/run-json_remove.c @@ -21,12 +21,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-json_scan.c b/common/test/run-json_scan.c index 7dfdc8247931..64f931470dea 100644 --- a/common/test/run-json_scan.c +++ b/common/test/run-json_scan.c @@ -20,12 +20,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-json_stream-filter.c b/common/test/run-json_stream-filter.c index 37729726cd5d..4a4e7dcc3f4d 100644 --- a/common/test/run-json_stream-filter.c +++ b/common/test/run-json_stream-filter.c @@ -26,12 +26,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-key_derive.c b/common/test/run-key_derive.c index 25f246b27b64..eb8a51ce9350 100644 --- a/common/test/run-key_derive.c +++ b/common/test/run-key_derive.c @@ -24,12 +24,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-onion-test-vector.c b/common/test/run-onion-test-vector.c index 14a1be1b4e76..d760262c8007 100644 --- a/common/test/run-onion-test-vector.c +++ b/common/test/run-onion-test-vector.c @@ -42,12 +42,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-softref.c b/common/test/run-softref.c index 5f5642d143ab..e4294219b4c4 100644 --- a/common/test/run-softref.c +++ b/common/test/run-softref.c @@ -21,12 +21,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-sphinx-xor_cipher_stream.c b/common/test/run-sphinx-xor_cipher_stream.c index 7875d5ed8d3c..b103fad71bcd 100644 --- a/common/test/run-sphinx-xor_cipher_stream.c +++ b/common/test/run-sphinx-xor_cipher_stream.c @@ -18,12 +18,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-sphinx.c b/common/test/run-sphinx.c index 47de12e0558a..a682867c2072 100644 --- a/common/test/run-sphinx.c +++ b/common/test/run-sphinx.c @@ -32,12 +32,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-tlv_span.c b/common/test/run-tlv_span.c index 0fc9d03c804b..5502dc6d4a5f 100644 --- a/common/test/run-tlv_span.c +++ b/common/test/run-tlv_span.c @@ -20,12 +20,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/common/test/run-wireaddr.c b/common/test/run-wireaddr.c index 8712563b009a..2b1c852d9838 100644 --- a/common/test/run-wireaddr.c +++ b/common/test/run-wireaddr.c @@ -32,12 +32,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/connectd/test/run-gossip_rcvd_filter.c b/connectd/test/run-gossip_rcvd_filter.c index 17810ac3c101..bf080c0e6a81 100644 --- a/connectd/test/run-gossip_rcvd_filter.c +++ b/connectd/test/run-gossip_rcvd_filter.c @@ -20,12 +20,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/connectd/test/run-initiator-success.c b/connectd/test/run-initiator-success.c index 73e35875f5ce..c9f570fcf428 100644 --- a/connectd/test/run-initiator-success.c +++ b/connectd/test/run-initiator-success.c @@ -28,12 +28,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/connectd/test/run-netaddress.c b/connectd/test/run-netaddress.c index f92ea8aa7582..91fc359260fc 100644 --- a/connectd/test/run-netaddress.c +++ b/connectd/test/run-netaddress.c @@ -27,12 +27,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/connectd/test/run-responder-success.c b/connectd/test/run-responder-success.c index b5de1da5a9e7..8927c252159f 100644 --- a/connectd/test/run-responder-success.c +++ b/connectd/test/run-responder-success.c @@ -28,12 +28,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, diff --git a/connectd/test/run-websocket.c b/connectd/test/run-websocket.c index db4ff47eb805..93d4f9caade1 100644 --- a/connectd/test/run-websocket.c +++ b/connectd/test/run-websocket.c @@ -63,12 +63,18 @@ struct amount_sat amount_sat(u64 satoshis UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_div */ +struct amount_sat amount_sat_div(struct amount_sat sat UNNEEDED, u64 div UNNEEDED) +{ fprintf(stderr, "amount_sat_div called!\n"); abort(); } /* 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_greater_eq */ bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_mul */ +bool amount_sat_mul(struct amount_sat *res UNNEEDED, struct amount_sat sat UNNEEDED, u64 mul UNNEEDED) +{ fprintf(stderr, "amount_sat_mul called!\n"); abort(); } /* Generated stub for amount_sat_sub */ bool amount_sat_sub(struct amount_sat *val UNNEEDED, struct amount_sat a UNNEEDED, From fd3185d7e16360196093d74b10a6d4936e2f23da Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 23 Mar 2023 16:18:09 +1030 Subject: [PATCH 08/13] lightningd: use tx_feerate() for calculating fallback feerate for onchaind. Signed-off-by: Rusty Russell --- lightningd/onchain_control.c | 29 ++--------------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/lightningd/onchain_control.c b/lightningd/onchain_control.c index c1372e5ad00b..b97eb5321944 100644 --- a/lightningd/onchain_control.c +++ b/lightningd/onchain_control.c @@ -695,33 +695,8 @@ enum watch_result onchaind_funding_spent(struct channel *channel, /* We check them separately but there is a high chance that if estimation * failed for one, it failed for all.. */ for (size_t i = 0; i < 3; i++) { - if (!feerates[i]) { - /* We have at least one data point: the last tx's feerate. */ - struct amount_sat fee = channel->funding_sats; - for (size_t j = 0; - j < channel->last_tx->wtx->num_outputs; j++) { - struct amount_asset asset = - bitcoin_tx_output_get_amount(channel->last_tx, j); - struct amount_sat amt; - assert(amount_asset_is_main(&asset)); - amt = amount_asset_to_sat(&asset); - if (!amount_sat_sub(&fee, fee, amt)) { - log_broken(channel->log, "Could not get fee" - " funding %s tx %s", - type_to_string(tmpctx, - struct amount_sat, - &channel->funding_sats), - type_to_string(tmpctx, - struct bitcoin_tx, - channel->last_tx)); - return KEEP_WATCHING; - } - } - - feerates[i] = fee.satoshis / bitcoin_tx_weight(tx); /* Raw: reverse feerate extraction */ - if (feerates[i] < feerate_floor()) - feerates[i] = feerate_floor(); - } + if (!feerates[i]) + feerates[i] = tx_feerate(channel->last_tx); } /* This is 10x highest bitcoind estimate (depending on dev-max-fee-multiplier), * so cap at 2x */ From 3a9e1d270d18ea3cd6e30f7b318b8aea7718dfc6 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 23 Mar 2023 16:18:09 +1030 Subject: [PATCH 09/13] onchaind: simplify lightningd message handling into a switch statement. Signed-off-by: Rusty Russell --- onchaind/onchaind.c | 101 +++++++++++++++++++++++------- onchaind/test/run-grind_feerate.c | 3 + 2 files changed, 81 insertions(+), 23 deletions(-) diff --git a/onchaind/onchaind.c b/onchaind/onchaind.c index e440bddcce57..dc828b0eb2c6 100644 --- a/onchaind/onchaind.c +++ b/onchaind/onchaind.c @@ -2059,34 +2059,66 @@ static void memleak_remove_globals(struct htable *memtable, const tal_t *topctx) memleak_scan_obj(memtable, queued_msgs); } -static bool handle_dev_memleak(struct tracked_output **outs, const u8 *msg) +static void handle_dev_memleak(struct tracked_output ***outs, const u8 *msg) { struct htable *memtable; bool found_leak; if (!fromwire_onchaind_dev_memleak(msg)) - return false; + master_badmsg(WIRE_ONCHAIND_DEV_MEMLEAK, msg); memtable = memleak_start(tmpctx); memleak_ptr(memtable, msg); /* Top-level context is parent of outs */ - memleak_remove_globals(memtable, tal_parent(outs)); - memleak_scan_obj(memtable, outs); + memleak_remove_globals(memtable, tal_parent(*outs)); + memleak_scan_obj(memtable, *outs); found_leak = dump_memleak(memtable, memleak_status_broken); wire_sync_write(REQ_FD, take(towire_onchaind_dev_memleak_reply(NULL, found_leak))); - return true; } #else -static bool handle_dev_memleak(struct tracked_output **outs, const u8 *msg) +static void handle_dev_memleak(struct tracked_output ***outs, const u8 *msg) { - return false; + master_badmsg(WIRE_ONCHAIND_DEV_MEMLEAK, msg); } #endif /* !DEVELOPER */ +static void handle_onchaind_depth(struct tracked_output ***outs, const u8 *msg) +{ + struct bitcoin_txid txid; + u32 depth; + + if (!fromwire_onchaind_depth(msg, &txid, &depth)) + master_badmsg(WIRE_ONCHAIND_DEPTH, msg); + + tx_new_depth(*outs, &txid, depth); +} + +static void handle_onchaind_spent(struct tracked_output ***outs, const u8 *msg) +{ + struct tx_parts *tx_parts; + u32 input_num, tx_blockheight; + + if (!fromwire_onchaind_spent(msg, msg, &tx_parts, &input_num, + &tx_blockheight)) + master_badmsg(WIRE_ONCHAIND_SPENT, msg); + + output_spent(outs, tx_parts, input_num, tx_blockheight); +} + +static void handle_onchaind_known_preimage(struct tracked_output ***outs, + const u8 *msg) +{ + struct preimage preimage; + + if (!fromwire_onchaind_known_preimage(msg, &preimage)) + master_badmsg(WIRE_ONCHAIND_KNOWN_PREIMAGE, msg); + handle_preimage(*outs, &preimage); +} + /* BOLT #5: * * A node: @@ -2102,10 +2134,7 @@ static void wait_for_resolved(struct tracked_output **outs) while (num_not_irrevocably_resolved(outs) != 0) { u8 *msg; - struct bitcoin_txid txid; - u32 input_num, depth, tx_blockheight; - struct preimage preimage; - struct tx_parts *tx_parts; + enum onchaind_wire mtype; if (tal_count(queued_msgs)) { msg = tal_steal(outs, queued_msgs[0]); @@ -2113,19 +2142,45 @@ static void wait_for_resolved(struct tracked_output **outs) } else msg = wire_sync_read(outs, REQ_FD); - status_debug("Got new message %s", - onchaind_wire_name(fromwire_peektype(msg))); - - if (fromwire_onchaind_depth(msg, &txid, &depth)) - tx_new_depth(outs, &txid, depth); - else if (fromwire_onchaind_spent(msg, msg, &tx_parts, &input_num, - &tx_blockheight)) { - output_spent(&outs, tx_parts, input_num, tx_blockheight); - } else if (fromwire_onchaind_known_preimage(msg, &preimage)) - handle_preimage(outs, &preimage); - else if (!handle_dev_memleak(outs, msg)) - master_badmsg(-1, msg); + mtype = fromwire_peektype(msg); + status_debug("Got new message %s", onchaind_wire_name(mtype)); + + switch (mtype) { + case WIRE_ONCHAIND_DEPTH: + handle_onchaind_depth(&outs, msg); + goto handled; + case WIRE_ONCHAIND_SPENT: + handle_onchaind_spent(&outs, msg); + goto handled; + case WIRE_ONCHAIND_KNOWN_PREIMAGE: + handle_onchaind_known_preimage(&outs, msg); + goto handled; + case WIRE_ONCHAIND_DEV_MEMLEAK: + handle_dev_memleak(&outs, msg); + goto handled; + + /* Unexpected messages */ + case WIRE_ONCHAIND_INIT: + case WIRE_ONCHAIND_HTLCS: + + /* We send these, not receive! */ + case WIRE_ONCHAIND_INIT_REPLY: + case WIRE_ONCHAIND_BROADCAST_TX: + case WIRE_ONCHAIND_UNWATCH_TX: + case WIRE_ONCHAIND_EXTRACTED_PREIMAGE: + case WIRE_ONCHAIND_MISSING_HTLC_OUTPUT: + case WIRE_ONCHAIND_HTLC_TIMEOUT: + case WIRE_ONCHAIND_ALL_IRREVOCABLY_RESOLVED: + case WIRE_ONCHAIND_ADD_UTXO: + case WIRE_ONCHAIND_DEV_MEMLEAK_REPLY: + case WIRE_ONCHAIND_ANNOTATE_TXOUT: + case WIRE_ONCHAIND_ANNOTATE_TXIN: + case WIRE_ONCHAIND_NOTIFY_COIN_MVT: + break; + } + master_badmsg(-1, msg); + handled: billboard_update(outs); tal_free(msg); clean_tmpctx(); diff --git a/onchaind/test/run-grind_feerate.c b/onchaind/test/run-grind_feerate.c index 99e8ec1495e8..92292518a5c0 100644 --- a/onchaind/test/run-grind_feerate.c +++ b/onchaind/test/run-grind_feerate.c @@ -62,6 +62,9 @@ bool fromwire_onchaind_known_preimage(const void *p UNNEEDED, struct preimage *p /* Generated stub for fromwire_onchaind_spent */ bool fromwire_onchaind_spent(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct tx_parts **tx UNNEEDED, u32 *input_num UNNEEDED, u32 *blockheight UNNEEDED) { fprintf(stderr, "fromwire_onchaind_spent called!\n"); abort(); } +/* Generated stub for fromwire_peektype */ +int fromwire_peektype(const u8 *cursor UNNEEDED) +{ fprintf(stderr, "fromwire_peektype called!\n"); abort(); } /* Generated stub for fromwire_secp256k1_ecdsa_signature */ void fromwire_secp256k1_ecdsa_signature(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, secp256k1_ecdsa_signature *signature UNNEEDED) From 9b15c6d1aa9cc1fd1668ee3cd208319ef18a5d6a Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 23 Mar 2023 16:18:09 +1030 Subject: [PATCH 10/13] bitcoind: fix clone_bitcoin_tx() when tx is take(). We need to actually steal it onto requested context in this case! Signed-off-by: Rusty Russell --- bitcoin/tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bitcoin/tx.c b/bitcoin/tx.c index 37d2a9a616a2..d6fcd6c08194 100644 --- a/bitcoin/tx.c +++ b/bitcoin/tx.c @@ -597,7 +597,7 @@ struct bitcoin_tx *clone_bitcoin_tx(const tal_t *ctx, struct bitcoin_tx *newtx; if (taken(tx)) - return cast_const(struct bitcoin_tx *, tx); + return cast_const(struct bitcoin_tx *, tal_steal(ctx, tx)); newtx = tal(ctx, struct bitcoin_tx); From 7e45dcef9e9593215fe0e75abd544b024d224114 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 23 Mar 2023 16:18:09 +1030 Subject: [PATCH 11/13] onchaind: helper to read and queue unwanted messages. We only do this in one place now, but we're going to add another. Also, make queued messages const. Signed-off-by: Rusty Russell --- onchaind/onchaind.c | 45 ++++++++++++++++++------------- onchaind/test/run-grind_feerate.c | 3 +++ 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/onchaind/onchaind.c b/onchaind/onchaind.c index dc828b0eb2c6..654a6f72dcc5 100644 --- a/onchaind/onchaind.c +++ b/onchaind/onchaind.c @@ -71,8 +71,8 @@ static u32 reasonable_depth; /* The messages to send at that depth. */ static u8 **missing_htlc_msgs; -/* The messages which were sent to us before init_reply was processed. */ -static u8 **queued_msgs; +/* The messages which were sent to us while waiting for a specific msg. */ +static const u8 **queued_msgs; /* Our recorded channel balance at 'chain time' */ static struct amount_msat our_msat; @@ -151,6 +151,20 @@ static const char *output_type_name(enum output_type output_type) return "unknown"; } +static const u8 *queue_until_msg(const tal_t *ctx, enum onchaind_wire mtype) +{ + const u8 *msg; + + while ((msg = wire_sync_read(ctx, REQ_FD)) != NULL) { + if (fromwire_peektype(msg) == mtype) + return msg; + /* Process later */ + tal_arr_expand(&queued_msgs, tal_steal(queued_msgs, msg)); + } + status_failed(STATUS_FAIL_HSM_IO, "Waiting for %s: connection lost", + onchaind_wire_name(mtype)); +} + /* helper to compare output script with our tal'd script */ static bool wally_tx_output_scripteq(const struct wally_tx_output *out, const u8 *script) @@ -2133,7 +2147,7 @@ static void wait_for_resolved(struct tracked_output **outs) billboard_update(outs); while (num_not_irrevocably_resolved(outs) != 0) { - u8 *msg; + const u8 *msg; enum onchaind_wire mtype; if (tal_count(queued_msgs)) { @@ -2214,7 +2228,7 @@ static int cmp_htlc_with_tells_cltv(const struct htlc_with_tells *a, static struct htlcs_info *init_reply(const tal_t *ctx, const char *what) { struct htlcs_info *htlcs_info = tal(ctx, struct htlcs_info); - u8 *msg; + const u8 *msg; struct htlc_with_tells *htlcs; /* commit_num is 0 for mutual close, but we don't care about HTLCs @@ -2226,20 +2240,13 @@ static struct htlcs_info *init_reply(const tal_t *ctx, const char *what) peer_billboard(true, what); - /* Read in htlcs */ - for (;;) { - msg = wire_sync_read(queued_msgs, REQ_FD); - if (fromwire_onchaind_htlcs(tmpctx, msg, - &htlcs_info->htlcs, - &htlcs_info->tell_if_missing, - &htlcs_info->tell_immediately)) { - tal_free(msg); - break; - } - - /* Process later */ - tal_arr_expand(&queued_msgs, msg); - } + /* Read in htlcs (ignoring everything else for now) */ + msg = queue_until_msg(tmpctx, WIRE_ONCHAIND_HTLCS); + if (!fromwire_onchaind_htlcs(htlcs_info, msg, + &htlcs_info->htlcs, + &htlcs_info->tell_if_missing, + &htlcs_info->tell_immediately)) + master_badmsg(WIRE_ONCHAIND_HTLCS, msg); /* One convenient structure, so we sort them together! */ htlcs = tal_arr(tmpctx, struct htlc_with_tells, tal_count(htlcs_info->htlcs)); @@ -3914,7 +3921,7 @@ int main(int argc, char *argv[]) status_setup_sync(REQ_FD); missing_htlc_msgs = tal_arr(ctx, u8 *, 0); - queued_msgs = tal_arr(ctx, u8 *, 0); + queued_msgs = tal_arr(ctx, const u8 *, 0); msg = wire_sync_read(tmpctx, REQ_FD); if (!fromwire_onchaind_init(tmpctx, msg, diff --git a/onchaind/test/run-grind_feerate.c b/onchaind/test/run-grind_feerate.c index 92292518a5c0..1dc02abed507 100644 --- a/onchaind/test/run-grind_feerate.c +++ b/onchaind/test/run-grind_feerate.c @@ -227,6 +227,9 @@ enum mvt_tag *new_tag_arr(const tal_t *ctx UNNEEDED, enum mvt_tag tag UNNEEDED) /* Generated stub for notleak_ */ void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) { fprintf(stderr, "notleak_ called!\n"); abort(); } +/* Generated stub for onchaind_wire_name */ +const char *onchaind_wire_name(int e UNNEEDED) +{ fprintf(stderr, "onchaind_wire_name called!\n"); abort(); } /* Generated stub for peer_billboard */ void peer_billboard(bool perm UNNEEDED, const char *fmt UNNEEDED, ...) { fprintf(stderr, "peer_billboard called!\n"); abort(); } From 16edf90831e3e4719589cdf8d1be9a508998d5ff Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 23 Mar 2023 16:18:09 +1030 Subject: [PATCH 12/13] onchaind: two minor tidyups. Firstly, amount should not be `static`, so use a separate line to declare those (fee is static, as it's cached across calls). Secondly, new_tracked_output doesn't take(), it copies. Signed-off-by: Rusty Russell --- onchaind/onchaind.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/onchaind/onchaind.c b/onchaind/onchaind.c index 654a6f72dcc5..30c4c4386651 100644 --- a/onchaind/onchaind.c +++ b/onchaind/onchaind.c @@ -493,7 +493,8 @@ static bool set_htlc_timeout_fee(struct bitcoin_tx *tx, const struct bitcoin_signature *remotesig, const u8 *wscript) { - static struct amount_sat amount, fee = AMOUNT_SAT_INIT(UINT64_MAX); + static struct amount_sat fee = AMOUNT_SAT_INIT(UINT64_MAX); + struct amount_sat amount; struct amount_asset asset = bitcoin_tx_output_get_amount(tx, 0); size_t weight; @@ -541,7 +542,8 @@ static void set_htlc_success_fee(struct bitcoin_tx *tx, const struct bitcoin_signature *remotesig, const u8 *wscript) { - static struct amount_sat amt, fee = AMOUNT_SAT_INIT(UINT64_MAX); + static struct amount_sat fee = AMOUNT_SAT_INIT(UINT64_MAX); + struct amount_sat amt; struct amount_asset asset; size_t weight; @@ -990,7 +992,7 @@ new_tracked_output(struct tracked_output ***outs, enum output_type output_type, const struct htlc_stub *htlc, const u8 *wscript, - const struct bitcoin_signature *remote_htlc_sig TAKES) + const struct bitcoin_signature *remote_htlc_sig) { struct tracked_output *out = tal(*outs, struct tracked_output); From 85e28338d31900519c0273aff310fcc5766886b1 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 23 Mar 2023 16:18:09 +1030 Subject: [PATCH 13/13] plugins/bcli: use getmempoolinfo to determine minimum possible fee. Fixes: #4473 Signed-off-by: Rusty Russell Changelog-Fixed: wallet: we no longer make txs below minrelaytxfee or mempoolminfee. --- plugins/bcli.c | 86 ++++++++++++++++++++++++++++++++++++-------- tests/test_misc.py | 90 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 162 insertions(+), 14 deletions(-) diff --git a/plugins/bcli.c b/plugins/bcli.c index 47bc121f5d30..a79b67b1907a 100644 --- a/plugins/bcli.c +++ b/plugins/bcli.c @@ -472,6 +472,8 @@ enum feerate_levels { #define FEERATE_LEVEL_MAX (FEERATE_SLOW) struct estimatefees_stash { + /* This is max(mempoolminfee,minrelaytxfee) */ + u64 perkb_floor; u32 cursor; /* FIXME: We use u64 but lightningd will store them as u32. */ u64 perkb[FEERATE_LEVEL_MAX+1]; @@ -675,6 +677,24 @@ static const struct estimatefee_params estimatefee_params[] = { [FEERATE_SLOW] = { 100, "ECONOMICAL" }, }; +/* Add a feerate, but don't publish one that bitcoind won't accept. */ +static void json_add_feerate(struct json_stream *result, const char *fieldname, + struct command *cmd, + const struct estimatefees_stash *stash, + uint64_t value) +{ + /* 0 is special, it means "unknown" */ + if (value && value < stash->perkb_floor) { + plugin_log(cmd->plugin, LOG_DBG, + "Feerate %s raised from %"PRIu64 + " perkb to floor of %"PRIu64, + fieldname, value, stash->perkb_floor); + json_add_u64(result, fieldname, stash->perkb_floor); + } else { + json_add_u64(result, fieldname, value); + } +} + static struct command_result *estimatefees_next(struct command *cmd, struct estimatefees_stash *stash) { @@ -693,29 +713,64 @@ static struct command_result *estimatefees_next(struct command *cmd, } response = jsonrpc_stream_success(cmd); - json_add_u64(response, "opening", stash->perkb[FEERATE_NORMAL]); - json_add_u64(response, "mutual_close", stash->perkb[FEERATE_SLOW]); - json_add_u64(response, "unilateral_close", - stash->perkb[FEERATE_URGENT] * bitcoind->commit_fee_percent / 100); - json_add_u64(response, "delayed_to_us", stash->perkb[FEERATE_NORMAL]); - json_add_u64(response, "htlc_resolution", stash->perkb[FEERATE_URGENT]); - json_add_u64(response, "penalty", stash->perkb[FEERATE_NORMAL]); + json_add_feerate(response, "opening", cmd, stash, + stash->perkb[FEERATE_NORMAL]); + json_add_feerate(response, "mutual_close", cmd, stash, + stash->perkb[FEERATE_SLOW]); + json_add_feerate(response, "unilateral_close", cmd, stash, + stash->perkb[FEERATE_URGENT] * bitcoind->commit_fee_percent / 100); + json_add_feerate(response, "delayed_to_us", cmd, stash, + stash->perkb[FEERATE_NORMAL]); + json_add_feerate(response, "htlc_resolution", cmd, stash, + stash->perkb[FEERATE_URGENT]); + json_add_feerate(response, "penalty", cmd, stash, + stash->perkb[FEERATE_NORMAL]); /* We divide the slow feerate for the minimum acceptable, lightningd * will use floor if it's hit, though. */ - json_add_u64(response, "min_acceptable", - stash->perkb[FEERATE_SLOW] / 2); + json_add_feerate(response, "min_acceptable", cmd, stash, + stash->perkb[FEERATE_SLOW] / 2); /* BOLT #2: * * Given the variance in fees, and the fact that the transaction may be * spent in the future, it's a good idea for the fee payer to keep a good * margin (say 5x the expected fee requirement) */ - json_add_u64(response, "max_acceptable", - stash->perkb[FEERATE_HIGHEST] - * bitcoind->max_fee_multiplier); + json_add_feerate(response, "max_acceptable", cmd, stash, + stash->perkb[FEERATE_HIGHEST] + * bitcoind->max_fee_multiplier); return command_finished(cmd, response); } +static struct command_result *getminfees_done(struct bitcoin_cli *bcli) +{ + const jsmntok_t *tokens; + const char *err; + u64 mempoolfee, relayfee; + struct estimatefees_stash *stash = bcli->stash; + + if (*bcli->exitstatus != 0) + return estimatefees_null_response(bcli); + + tokens = json_parse_simple(bcli->output, + bcli->output, bcli->output_bytes); + if (!tokens) + return command_err_bcli_badjson(bcli, + "cannot parse getmempoolinfo"); + + /* Look at minrelaytxfee they configured, and current min fee to get + * into mempool. */ + err = json_scan(tmpctx, bcli->output, tokens, + "{mempoolminfee:%,minrelaytxfee:%}", + JSON_SCAN(json_to_bitcoin_amount, &mempoolfee), + JSON_SCAN(json_to_bitcoin_amount, &relayfee)); + if (err) + return command_err_bcli_badjson(bcli, err); + + stash->perkb_floor = max_u64(mempoolfee, relayfee); + stash->cursor = 0; + return estimatefees_next(bcli->cmd, stash); +} + /* Get the current feerates. We use an urgent feerate for unilateral_close and max, * a slightly less urgent feerate for htlc_resolution and penalty transactions, * a slow feerate for min, and a normal one for all others. @@ -729,8 +784,11 @@ static struct command_result *estimatefees(struct command *cmd, if (!param(cmd, buf, toks, NULL)) return command_param_failed(); - stash->cursor = 0; - return estimatefees_next(cmd, stash); + start_bitcoin_cli(NULL, cmd, getminfees_done, true, + BITCOIND_LOW_PRIO, stash, + "getmempoolinfo", + NULL); + return command_still_pending(cmd); } static struct command_result *estimatefees_done(struct bitcoin_cli *bcli) diff --git a/tests/test_misc.py b/tests/test_misc.py index 6b8f046107f2..79b4a111f7d3 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -1883,8 +1883,10 @@ def test_bitcoind_fail_first(node_factory, bitcoind): def mock_fail(*args): raise ValueError() + # If any of these succeed, they reset fail timeout. l1.daemon.rpcproxy.mock_rpc('getblockhash', mock_fail) l1.daemon.rpcproxy.mock_rpc('estimatesmartfee', mock_fail) + l1.daemon.rpcproxy.mock_rpc('getmempoolinfo', mock_fail) l1.daemon.start(wait_for_initialized=False, stderr_redir=True) l1.daemon.wait_for_logs([r'getblockhash [a-z0-9]* exited with status 1', @@ -1898,6 +1900,94 @@ def mock_fail(*args): l1.daemon.rpcproxy.mock_rpc('estimatesmartfee', None) +@unittest.skipIf(TEST_NETWORK == 'liquid-regtest', "Fees on elements are different") +def test_bitcoind_feerate_floor(node_factory, bitcoind): + """Don't return a feerate less than minrelaytxfee/mempoolnifee.""" + l1 = node_factory.get_node() + + anchors = EXPERIMENTAL_FEATURES + assert l1.rpc.feerates('perkb') == { + "perkb": { + "opening": 30000, + "mutual_close": 15000, + "unilateral_close": 44000, + "delayed_to_us": 30000, + "htlc_resolution": 44000, + "penalty": 30000, + "min_acceptable": 7500, + "max_acceptable": 600000 + }, + "onchain_fee_estimates": { + "opening_channel_satoshis": 5265, + "mutual_close_satoshis": 2523, + "unilateral_close_satoshis": 6578, + "htlc_timeout_satoshis": 7326 if anchors else 7293, + "htlc_success_satoshis": 7766 if anchors else 7733, + } + } + + l1.daemon.rpcproxy.mock_rpc('getmempoolinfo', + { + "mempoolminfee": 0.00010001, + "minrelaytxfee": 0.00020001 + }) + l1.restart() + assert l1.rpc.feerates('perkb') == { + "perkb": { + "opening": 30000, + # This has increased (rounded up) + "mutual_close": 20004, + "unilateral_close": 44000, + "delayed_to_us": 30000, + "htlc_resolution": 44000, + "penalty": 30000, + # This has increased (rounded up!) + "min_acceptable": 20004, + "max_acceptable": 600000 + }, + "onchain_fee_estimates": { + "opening_channel_satoshis": 5265, + # This increases too + "mutual_close_satoshis": 3365, + "unilateral_close_satoshis": 6578, + "htlc_timeout_satoshis": 7326 if anchors else 7293, + "htlc_success_satoshis": 7766 if anchors else 7733, + } + } + + l1.daemon.rpcproxy.mock_rpc('getmempoolinfo', + { + "mempoolminfee": 0.00030001, + "minrelaytxfee": 0.00010001 + }) + l1.restart() + assert l1.rpc.feerates('perkb') == { + "perkb": { + # This has increased (rounded up!) + "opening": 30004, + # This has increased (rounded up!) + "mutual_close": 30004, + "unilateral_close": 44000, + # This has increased (rounded up!) + "delayed_to_us": 30004, + "htlc_resolution": 44000, + # This has increased (rounded up!) + "penalty": 30004, + # This has increased (rounded up!) + "min_acceptable": 30004, + "max_acceptable": 600000 + }, + "onchain_fee_estimates": { + "opening_channel_satoshis": 5265, + # This increases too + "mutual_close_satoshis": 5048, + "unilateral_close_satoshis": 6578, + "htlc_timeout_satoshis": 7326 if anchors else 7293, + "htlc_success_satoshis": 7766 if anchors else 7733, + } + } + + @pytest.mark.developer("needs --dev-force-bip32-seed") @unittest.skipIf(TEST_NETWORK != 'regtest', "Addresses are network specific") def test_dev_force_bip32_seed(node_factory):