diff --git a/lightningd/bitcoind.c b/lightningd/bitcoind.c index f1bf7b7fe..662455f5b 100644 --- a/lightningd/bitcoind.c +++ b/lightningd/bitcoind.c @@ -495,33 +495,6 @@ void bitcoind_estimate_fees_(struct bitcoind *bitcoind, do_one_estimatefee(bitcoind, efee); } -static bool process_sendrawtx(struct bitcoin_cli *bcli) -{ - void (*cb)(struct bitcoind *bitcoind, - int, const char *msg, void *) = bcli->cb; - const char *msg = tal_strndup(bcli, bcli->output, - bcli->output_bytes); - - log_debug(bcli->bitcoind->log, "sendrawtx exit %u, gave %s", - *bcli->exitstatus, msg); - - cb(bcli->bitcoind, *bcli->exitstatus, msg, bcli->cb_arg); - return true; -} - -void bitcoind_sendrawtx_(struct bitcoind *bitcoind, - const char *hextx, - void (*cb)(struct bitcoind *bitcoind, - int exitstatus, const char *msg, void *), - void *arg) -{ - log_debug(bitcoind->log, "sendrawtransaction: %s", hextx); - start_bitcoin_cli(bitcoind, NULL, process_sendrawtx, true, - BITCOIND_HIGH_PRIO, - cb, arg, - "sendrawtransaction", hextx, NULL); -} - static bool process_rawblock(struct bitcoin_cli *bcli) { struct bitcoin_block *blk; @@ -567,6 +540,85 @@ static void bitcoin_plugin_error(struct bitcoind *bitcoind, const char *buf, toks->end - toks->start, buf + toks->start); } +/* `sendrawtransaction` + * + * Send a transaction to the Bitcoin backend plugin. If the broadcast was + * not successful on its end, the plugin will populate the `errmsg` with + * the reason. + * + * Plugin response: + * { + * "success": , + * "errmsg": "" + * } + */ + +struct sendrawtx_call { + struct bitcoind *bitcoind; + void (*cb)(struct bitcoind *bitcoind, + bool success, + const char *err_msg, + void *); + void *cb_arg; +}; + +static void sendrawtx_callback(const char *buf, const jsmntok_t *toks, + const jsmntok_t *idtok, + struct sendrawtx_call *call) +{ + const jsmntok_t *resulttok, *successtok, *errtok; + bool success = false; + + resulttok = json_get_member(buf, toks, "result"); + if (!resulttok) + bitcoin_plugin_error(call->bitcoind, buf, toks, + "sendrawtransaction", + "bad 'result' field"); + + successtok = json_get_member(buf, resulttok, "success"); + if (!successtok || !json_to_bool(buf, successtok, &success)) + bitcoin_plugin_error(call->bitcoind, buf, toks, + "sendrawtransaction", + "bad 'success' field"); + + errtok = json_get_member(buf, resulttok, "errmsg"); + if (!success && !errtok) + bitcoin_plugin_error(call->bitcoind, buf, toks, + "sendrawtransaction", + "bad 'errmsg' field"); + + db_begin_transaction(call->bitcoind->ld->wallet->db); + call->cb(call->bitcoind, success, + errtok ? json_strdup(tmpctx, buf, errtok) : NULL, + call->cb_arg); + db_commit_transaction(call->bitcoind->ld->wallet->db); + + tal_free(call); +} + +void bitcoind_sendrawtx_(struct bitcoind *bitcoind, + const char *hextx, + void (*cb)(struct bitcoind *bitcoind, + bool success, const char *err_msg, void *), + void *cb_arg) +{ + struct jsonrpc_request *req; + struct sendrawtx_call *call = tal(bitcoind, struct sendrawtx_call); + + call->bitcoind = bitcoind; + call->cb = cb; + call->cb_arg = cb_arg; + log_debug(bitcoind->log, "sendrawtransaction: %s", hextx); + + req = jsonrpc_request_start(bitcoind, "sendrawtransaction", + bitcoind->log, sendrawtx_callback, + call); + json_add_string(req->stream, "tx", hextx); + jsonrpc_request_end(req); + plugin_request_send(strmap_get(&bitcoind->pluginsmap, + "sendrawtransaction"), req); +} + /* `getrawblockbyheight` * * If no block were found at that height, will set each field to `null`. diff --git a/lightningd/bitcoind.h b/lightningd/bitcoind.h index 7ccb8141b..fc8719b4c 100644 --- a/lightningd/bitcoind.h +++ b/lightningd/bitcoind.h @@ -107,7 +107,7 @@ void bitcoind_estimate_fees_(struct bitcoind *bitcoind, void bitcoind_sendrawtx_(struct bitcoind *bitcoind, const char *hextx, void (*cb)(struct bitcoind *bitcoind, - int exitstatus, const char *msg, void *), + bool success, const char *msg, void *), void *arg); #define bitcoind_sendrawtx(bitcoind_, hextx, cb, arg) \ @@ -115,7 +115,7 @@ void bitcoind_sendrawtx_(struct bitcoind *bitcoind, typesafe_cb_preargs(void, void *, \ (cb), (arg), \ struct bitcoind *, \ - int, const char *), \ + bool, const char *), \ (arg)) /* blkid is NULL if call fails. */ diff --git a/lightningd/chaintopology.c b/lightningd/chaintopology.c index b9bfcc859..1d5cd6a68 100644 --- a/lightningd/chaintopology.c +++ b/lightningd/chaintopology.c @@ -127,13 +127,13 @@ struct txs_to_broadcast { /* We just sent the last entry in txs[]. Shrink and send the next last. */ static void broadcast_remainder(struct bitcoind *bitcoind, - int exitstatus, const char *msg, + bool success, const char *msg, struct txs_to_broadcast *txs) { /* These are expected. */ if (strstr(msg, "txn-mempool-conflict") || strstr(msg, "transaction already in block chain") - || exitstatus) + || !success) log_debug(bitcoind->log, "Expected error broadcasting tx %s: %s", txs->txs[txs->cursor], msg); @@ -174,7 +174,7 @@ static void rebroadcast_txs(struct chain_topology *topo, struct command *cmd) /* Let this do the dirty work. */ txs->cursor = (size_t)-1; - broadcast_remainder(topo->bitcoind, 0, "", txs); + broadcast_remainder(topo->bitcoind, true, "", txs); } static void destroy_outgoing_tx(struct outgoing_tx *otx) @@ -190,7 +190,7 @@ static void clear_otx_channel(struct channel *channel, struct outgoing_tx *otx) } static void broadcast_done(struct bitcoind *bitcoind, - int exitstatus, const char *msg, + bool success, const char *msg, struct outgoing_tx *otx) { /* Channel gone? Stop. */ @@ -203,7 +203,7 @@ static void broadcast_done(struct bitcoind *bitcoind, tal_del_destructor2(otx->channel, clear_otx_channel, otx); if (otx->failed_or_success) { - otx->failed_or_success(otx->channel, exitstatus, msg); + otx->failed_or_success(otx->channel, success, msg); tal_free(otx); } else { /* For continual rebroadcasting, until channel freed. */ @@ -216,7 +216,7 @@ static void broadcast_done(struct bitcoind *bitcoind, void broadcast_tx(struct chain_topology *topo, struct channel *channel, const struct bitcoin_tx *tx, void (*failed_or_success)(struct channel *channel, - int exitstatus, const char *err)) + bool success, const char *err)) { /* Channel might vanish: topo owns it to start with. */ struct outgoing_tx *otx = tal(topo, struct outgoing_tx); @@ -985,7 +985,7 @@ check_chain(struct bitcoind *bitcoind, const char *chain, static void retry_check_chain(struct chain_topology *topo) { - bitcoind_getchaininfo(topo->bitcoind, true, check_chain, topo); + bitcoind_getchaininfo(topo->bitcoind, false, check_chain, topo); } void setup_topology(struct chain_topology *topo, diff --git a/lightningd/chaintopology.h b/lightningd/chaintopology.h index 816c537f9..03b25c0b4 100644 --- a/lightningd/chaintopology.h +++ b/lightningd/chaintopology.h @@ -37,7 +37,7 @@ struct outgoing_tx { struct channel *channel; const char *hextx; struct bitcoin_txid txid; - void (*failed_or_success)(struct channel *channel, int exitstatus, const char *err); + void (*failed_or_success)(struct channel *channel, bool success, const char *err); }; struct block { @@ -166,7 +166,7 @@ struct command_result *param_feerate_estimate(struct command *cmd, void broadcast_tx(struct chain_topology *topo, struct channel *channel, const struct bitcoin_tx *tx, void (*failed)(struct channel *channel, - int exitstatus, + bool success, const char *err)); struct chain_topology *new_topology(struct lightningd *ld, struct log *log); diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index e227c282b..bd44eccef 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -38,7 +38,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 UNNEEDED, void (*failed)(struct channel *channel UNNEEDED, - int exitstatus UNNEEDED, + bool success UNNEEDED, const char *err)) { fprintf(stderr, "broadcast_tx called!\n"); abort(); } /* Generated stub for channel_tell_depth */ diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 7b4932f67..0f705cc38 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -49,7 +49,7 @@ void bitcoind_gettxout(struct bitcoind *bitcoind UNNEEDED, void broadcast_tx(struct chain_topology *topo UNNEEDED, struct channel *channel UNNEEDED, const struct bitcoin_tx *tx UNNEEDED, void (*failed)(struct channel *channel UNNEEDED, - int exitstatus UNNEEDED, + bool success UNNEEDED, const char *err)) { fprintf(stderr, "broadcast_tx called!\n"); abort(); } /* Generated stub for channel_tell_depth */ diff --git a/wallet/walletrpc.c b/wallet/walletrpc.c index dbef2a874..311a6569e 100644 --- a/wallet/walletrpc.c +++ b/wallet/walletrpc.c @@ -43,7 +43,7 @@ * available outputs. */ static void wallet_withdrawal_broadcast(struct bitcoind *bitcoind UNUSED, - int exitstatus, const char *msg, + bool success, const char *msg, struct unreleased_tx *utx) { struct command *cmd = utx->wtx->cmd; @@ -53,7 +53,7 @@ static void wallet_withdrawal_broadcast(struct bitcoind *bitcoind UNUSED, /* FIXME: This won't be necessary once we use ccan/json_out! */ /* Massage output into shape so it doesn't kill the JSON serialization */ char *output = tal_strjoin(cmd, tal_strsplit(cmd, msg, "\n", STR_NO_EMPTY), " ", STR_NO_TRAIL); - if (exitstatus == 0) { + if (success) { /* Mark used outputs as spent */ wallet_confirm_utxos(ld->wallet, utx->wtx->utxos); @@ -66,7 +66,7 @@ static void wallet_withdrawal_broadcast(struct bitcoind *bitcoind UNUSED, struct json_stream *response = json_stream_success(cmd); json_add_tx(response, "tx", utx->tx); - json_add_string(response, "txid", output); + json_add_txid(response, "txid", &utx->txid); was_pending(command_success(cmd, response)); } else { was_pending(command_fail(cmd, LIGHTNINGD,