Browse Source

lightningd/bitcoind: use the Bitcoin plugin to send transactions

This restrains the informations we get about how the sending went to
an errmsg as we cant rely on bitcoin-cli specific output nor its exit code.
travis-debug
darosior 5 years ago
committed by Rusty Russell
parent
commit
947f5ddde1
  1. 106
      lightningd/bitcoind.c
  2. 4
      lightningd/bitcoind.h
  3. 14
      lightningd/chaintopology.c
  4. 4
      lightningd/chaintopology.h
  5. 2
      lightningd/test/run-invoice-select-inchan.c
  6. 2
      wallet/test/run-wallet.c
  7. 6
      wallet/walletrpc.c

106
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": <true|false>,
* "errmsg": "<not empty if !success>"
* }
*/
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`.

4
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. */

14
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,

4
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);

2
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 */

2
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 */

6
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,

Loading…
Cancel
Save