diff --git a/lightningd/onchain_control.c b/lightningd/onchain_control.c index bbd047e1b..2265cf99b 100644 --- a/lightningd/onchain_control.c +++ b/lightningd/onchain_control.c @@ -213,17 +213,68 @@ static void handle_onchain_log_coin_move(struct channel *channel, const u8 *msg) tal_free(mvt); } -static void handle_onchain_broadcast_tx(struct channel *channel, const u8 *msg) +/** handle_onchain_broadcast_rbf_tx_cb + * + * @brief suppresses the rebroadcast of a + * transaction. + * + * @desc when using the `bitcoin_tx` function, + * if a callback is not given, the transaction + * will be rebroadcast automatically by + * chaintopology. + * However, in the case of an RBF transaction + * from `onchaind`, `onchaind` will periodically + * create a new, higher-fee replacement, thus + * `onchaind` will trigger rebroadcast (with a + * higher fee) by itself, which the `lightningd` + * chaintopology should not repeat. + * This callback exists to suppress the + * rebroadcast behavior of chaintopology. + * + * @param channel - the channel for which the + * transaction was broadcast. + * @param success - whether the tx was broadcast. + * @param err - the error received from the + * underlying sendrawtx. + */ +static void handle_onchain_broadcast_rbf_tx_cb(struct channel *channel, + bool success, + const char *err) +{ + /* Victory is boring. */ + if (success) + return; + + /* Failure is unusual but not broken: it is possible that just + * as we were about to broadcast, a new block came in which + * contains a previous version of the transaction, thus + * causing the higher-fee replacement to fail broadcast. + * + * ...or it could be a bug in onchaind which prevents it from + * successfully RBFing out the transaction, in which case we + * should log it for devs to check. + */ + log_unusual(channel->log, + "Broadcast of RBF tx failed, " + "did a new block just come in? " + "error: %s", + err); +} + +static void handle_onchain_broadcast_tx(struct channel *channel, + const u8 *msg) { struct bitcoin_tx *tx; struct wallet *w = channel->peer->ld->wallet; struct bitcoin_txid txid; enum wallet_tx_type type; + bool is_rbf; - if (!fromwire_onchaind_broadcast_tx(msg, msg, &tx, &type)) { + if (!fromwire_onchaind_broadcast_tx(msg, msg, &tx, &type, &is_rbf)) { channel_internal_error(channel, "Invalid onchain_broadcast_tx"); return; } + tx->chainparams = chainparams; bitcoin_txid(tx, &txid); @@ -231,7 +282,8 @@ static void handle_onchain_broadcast_tx(struct channel *channel, const u8 *msg) wallet_transaction_annotate(w, &txid, type, channel->dbid); /* We don't really care if it fails, we'll respond via watch. */ - broadcast_tx(channel->peer->ld->topology, channel, tx, NULL); + broadcast_tx(channel->peer->ld->topology, channel, tx, + is_rbf ? &handle_onchain_broadcast_rbf_tx_cb : NULL); } static void handle_onchain_unwatch_tx(struct channel *channel, const u8 *msg) diff --git a/onchaind/onchaind.c b/onchaind/onchaind.c index 04a816628..b667eb7f3 100644 --- a/onchaind/onchaind.c +++ b/onchaind/onchaind.c @@ -842,7 +842,8 @@ static void proposal_meets_depth(struct tracked_output *out, bool is_replay) REQ_FD, take(towire_onchaind_broadcast_tx( NULL, out->proposal->tx, - onchain_txtype_to_wallet_txtype(out->proposal->tx_type)))); + onchain_txtype_to_wallet_txtype(out->proposal->tx_type), + false))); /* Don't wait for this if we're ignoring the tiny payment. */ if (out->proposal->tx_type == IGNORING_TINY_PAYMENT) { diff --git a/onchaind/onchaind_wire.csv b/onchaind/onchaind_wire.csv index 00a6496cc..d0e88eef2 100644 --- a/onchaind/onchaind_wire.csv +++ b/onchaind/onchaind_wire.csv @@ -64,9 +64,13 @@ msgdata,onchaind_htlc,tell_immediately,bool, msgtype,onchaind_init_reply,5101 # onchaind->master: Send out a tx. +# If is_rbf is false then master should rebroadcast the tx. +# If is_rbf is true then onchaind is responsible for rebroadcasting +# it with a higher fee. msgtype,onchaind_broadcast_tx,5003 msgdata,onchaind_broadcast_tx,tx,bitcoin_tx, msgdata,onchaind_broadcast_tx,type,enum wallet_tx_type, +msgdata,onchaind_broadcast_tx,is_rbf,bool, # master->onchaind: Notifier that an output has been spent by input_num of tx. msgtype,onchaind_spent,5004 diff --git a/onchaind/onchaind_wiregen.c b/onchaind/onchaind_wiregen.c index fb71c755e..d3ef707fc 100644 --- a/onchaind/onchaind_wiregen.c +++ b/onchaind/onchaind_wiregen.c @@ -259,17 +259,21 @@ bool fromwire_onchaind_init_reply(const void *p) /* WIRE: ONCHAIND_BROADCAST_TX */ /* onchaind->master: Send out a tx. */ -u8 *towire_onchaind_broadcast_tx(const tal_t *ctx, const struct bitcoin_tx *tx, enum wallet_tx_type type) +/* If is_rbf is false then master should rebroadcast the tx. */ +/* If is_rbf is true then onchaind is responsible for rebroadcasting */ +/* it with a higher fee. */ +u8 *towire_onchaind_broadcast_tx(const tal_t *ctx, const struct bitcoin_tx *tx, enum wallet_tx_type type, bool is_rbf) { u8 *p = tal_arr(ctx, u8, 0); towire_u16(&p, WIRE_ONCHAIND_BROADCAST_TX); towire_bitcoin_tx(&p, tx); towire_wallet_tx_type(&p, type); + towire_bool(&p, is_rbf); return memcheck(p, tal_count(p)); } -bool fromwire_onchaind_broadcast_tx(const tal_t *ctx, const void *p, struct bitcoin_tx **tx, enum wallet_tx_type *type) +bool fromwire_onchaind_broadcast_tx(const tal_t *ctx, const void *p, struct bitcoin_tx **tx, enum wallet_tx_type *type, bool *is_rbf) { const u8 *cursor = p; size_t plen = tal_count(p); @@ -278,6 +282,7 @@ bool fromwire_onchaind_broadcast_tx(const tal_t *ctx, const void *p, struct bitc return false; *tx = fromwire_bitcoin_tx(ctx, &cursor, &plen); *type = fromwire_wallet_tx_type(&cursor, &plen); + *is_rbf = fromwire_bool(&cursor, &plen); return cursor != NULL; } @@ -631,4 +636,4 @@ bool fromwire_onchaind_notify_coin_mvt(const void *p, struct chain_coin_mvt *mvt return cursor != NULL; } -// SHA256STAMP:de5e8db17d4d8d22e8a44b27ffaf035a1d16100d2cedde40e0fcf6c44bf2b15b +// SHA256STAMP:e21aeee2bb2e0c56f77595f7083aaacecdaf2b88b6808b33a63de4adcce58de8 diff --git a/onchaind/onchaind_wiregen.h b/onchaind/onchaind_wiregen.h index 5d0035270..9fc99665d 100644 --- a/onchaind/onchaind_wiregen.h +++ b/onchaind/onchaind_wiregen.h @@ -22,6 +22,9 @@ enum onchaind_wire { /* This says we're ready; give us preimages. */ WIRE_ONCHAIND_INIT_REPLY = 5101, /* onchaind->master: Send out a tx. */ + /* If is_rbf is false then master should rebroadcast the tx. */ + /* If is_rbf is true then onchaind is responsible for rebroadcasting */ + /* it with a higher fee. */ WIRE_ONCHAIND_BROADCAST_TX = 5003, /* master->onchaind: Notifier that an output has been spent by input_num of tx. */ WIRE_ONCHAIND_SPENT = 5004, @@ -81,8 +84,11 @@ bool fromwire_onchaind_init_reply(const void *p); /* WIRE: ONCHAIND_BROADCAST_TX */ /* onchaind->master: Send out a tx. */ -u8 *towire_onchaind_broadcast_tx(const tal_t *ctx, const struct bitcoin_tx *tx, enum wallet_tx_type type); -bool fromwire_onchaind_broadcast_tx(const tal_t *ctx, const void *p, struct bitcoin_tx **tx, enum wallet_tx_type *type); +/* If is_rbf is false then master should rebroadcast the tx. */ +/* If is_rbf is true then onchaind is responsible for rebroadcasting */ +/* it with a higher fee. */ +u8 *towire_onchaind_broadcast_tx(const tal_t *ctx, const struct bitcoin_tx *tx, enum wallet_tx_type type, bool is_rbf); +bool fromwire_onchaind_broadcast_tx(const tal_t *ctx, const void *p, struct bitcoin_tx **tx, enum wallet_tx_type *type, bool *is_rbf); /* WIRE: ONCHAIND_SPENT */ /* master->onchaind: Notifier that an output has been spent by input_num of tx. */ @@ -156,4 +162,4 @@ bool fromwire_onchaind_notify_coin_mvt(const void *p, struct chain_coin_mvt *mvt #endif /* LIGHTNING_ONCHAIND_ONCHAIND_WIREGEN_H */ -// SHA256STAMP:de5e8db17d4d8d22e8a44b27ffaf035a1d16100d2cedde40e0fcf6c44bf2b15b +// SHA256STAMP:e21aeee2bb2e0c56f77595f7083aaacecdaf2b88b6808b33a63de4adcce58de8 diff --git a/onchaind/test/run-grind_feerate-bug.c b/onchaind/test/run-grind_feerate-bug.c index d72ebd982..2576d6995 100644 --- a/onchaind/test/run-grind_feerate-bug.c +++ b/onchaind/test/run-grind_feerate-bug.c @@ -246,7 +246,7 @@ u8 *towire_onchaind_annotate_txin(const tal_t *ctx UNNEEDED, const struct bitcoi u8 *towire_onchaind_annotate_txout(const tal_t *ctx UNNEEDED, const struct bitcoin_txid *txid UNNEEDED, u32 outnum UNNEEDED, enum wallet_tx_type type UNNEEDED) { fprintf(stderr, "towire_onchaind_annotate_txout called!\n"); abort(); } /* Generated stub for towire_onchaind_broadcast_tx */ -u8 *towire_onchaind_broadcast_tx(const tal_t *ctx UNNEEDED, const struct bitcoin_tx *tx UNNEEDED, enum wallet_tx_type type UNNEEDED) +u8 *towire_onchaind_broadcast_tx(const tal_t *ctx UNNEEDED, const struct bitcoin_tx *tx UNNEEDED, enum wallet_tx_type type UNNEEDED, bool is_rbf UNNEEDED) { fprintf(stderr, "towire_onchaind_broadcast_tx called!\n"); abort(); } /* Generated stub for towire_onchaind_dev_memleak_reply */ u8 *towire_onchaind_dev_memleak_reply(const tal_t *ctx UNNEEDED, bool leak UNNEEDED) diff --git a/onchaind/test/run-grind_feerate.c b/onchaind/test/run-grind_feerate.c index faa110575..17aa445f3 100644 --- a/onchaind/test/run-grind_feerate.c +++ b/onchaind/test/run-grind_feerate.c @@ -266,7 +266,7 @@ u8 *towire_onchaind_annotate_txin(const tal_t *ctx UNNEEDED, const struct bitcoi u8 *towire_onchaind_annotate_txout(const tal_t *ctx UNNEEDED, const struct bitcoin_txid *txid UNNEEDED, u32 outnum UNNEEDED, enum wallet_tx_type type UNNEEDED) { fprintf(stderr, "towire_onchaind_annotate_txout called!\n"); abort(); } /* Generated stub for towire_onchaind_broadcast_tx */ -u8 *towire_onchaind_broadcast_tx(const tal_t *ctx UNNEEDED, const struct bitcoin_tx *tx UNNEEDED, enum wallet_tx_type type UNNEEDED) +u8 *towire_onchaind_broadcast_tx(const tal_t *ctx UNNEEDED, const struct bitcoin_tx *tx UNNEEDED, enum wallet_tx_type type UNNEEDED, bool is_rbf UNNEEDED) { fprintf(stderr, "towire_onchaind_broadcast_tx called!\n"); abort(); } /* Generated stub for towire_onchaind_dev_memleak_reply */ u8 *towire_onchaind_dev_memleak_reply(const tal_t *ctx UNNEEDED, bool leak UNNEEDED)