mirror of
https://github.com/aljazceru/lightning.git
synced 2026-02-04 13:44:22 +01:00
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.
This commit is contained in:
@@ -495,33 +495,6 @@ void bitcoind_estimate_fees_(struct bitcoind *bitcoind,
|
|||||||
do_one_estimatefee(bitcoind, efee);
|
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)
|
static bool process_rawblock(struct bitcoin_cli *bcli)
|
||||||
{
|
{
|
||||||
struct bitcoin_block *blk;
|
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);
|
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`
|
/* `getrawblockbyheight`
|
||||||
*
|
*
|
||||||
* If no block were found at that height, will set each field to `null`.
|
* If no block were found at that height, will set each field to `null`.
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ void bitcoind_estimate_fees_(struct bitcoind *bitcoind,
|
|||||||
void bitcoind_sendrawtx_(struct bitcoind *bitcoind,
|
void bitcoind_sendrawtx_(struct bitcoind *bitcoind,
|
||||||
const char *hextx,
|
const char *hextx,
|
||||||
void (*cb)(struct bitcoind *bitcoind,
|
void (*cb)(struct bitcoind *bitcoind,
|
||||||
int exitstatus, const char *msg, void *),
|
bool success, const char *msg, void *),
|
||||||
void *arg);
|
void *arg);
|
||||||
|
|
||||||
#define bitcoind_sendrawtx(bitcoind_, hextx, cb, arg) \
|
#define bitcoind_sendrawtx(bitcoind_, hextx, cb, arg) \
|
||||||
@@ -115,7 +115,7 @@ void bitcoind_sendrawtx_(struct bitcoind *bitcoind,
|
|||||||
typesafe_cb_preargs(void, void *, \
|
typesafe_cb_preargs(void, void *, \
|
||||||
(cb), (arg), \
|
(cb), (arg), \
|
||||||
struct bitcoind *, \
|
struct bitcoind *, \
|
||||||
int, const char *), \
|
bool, const char *), \
|
||||||
(arg))
|
(arg))
|
||||||
|
|
||||||
/* blkid is NULL if call fails. */
|
/* blkid is NULL if call fails. */
|
||||||
|
|||||||
@@ -127,13 +127,13 @@ struct txs_to_broadcast {
|
|||||||
|
|
||||||
/* We just sent the last entry in txs[]. Shrink and send the next last. */
|
/* We just sent the last entry in txs[]. Shrink and send the next last. */
|
||||||
static void broadcast_remainder(struct bitcoind *bitcoind,
|
static void broadcast_remainder(struct bitcoind *bitcoind,
|
||||||
int exitstatus, const char *msg,
|
bool success, const char *msg,
|
||||||
struct txs_to_broadcast *txs)
|
struct txs_to_broadcast *txs)
|
||||||
{
|
{
|
||||||
/* These are expected. */
|
/* These are expected. */
|
||||||
if (strstr(msg, "txn-mempool-conflict")
|
if (strstr(msg, "txn-mempool-conflict")
|
||||||
|| strstr(msg, "transaction already in block chain")
|
|| strstr(msg, "transaction already in block chain")
|
||||||
|| exitstatus)
|
|| !success)
|
||||||
log_debug(bitcoind->log,
|
log_debug(bitcoind->log,
|
||||||
"Expected error broadcasting tx %s: %s",
|
"Expected error broadcasting tx %s: %s",
|
||||||
txs->txs[txs->cursor], msg);
|
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. */
|
/* Let this do the dirty work. */
|
||||||
txs->cursor = (size_t)-1;
|
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)
|
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,
|
static void broadcast_done(struct bitcoind *bitcoind,
|
||||||
int exitstatus, const char *msg,
|
bool success, const char *msg,
|
||||||
struct outgoing_tx *otx)
|
struct outgoing_tx *otx)
|
||||||
{
|
{
|
||||||
/* Channel gone? Stop. */
|
/* Channel gone? Stop. */
|
||||||
@@ -203,7 +203,7 @@ static void broadcast_done(struct bitcoind *bitcoind,
|
|||||||
tal_del_destructor2(otx->channel, clear_otx_channel, otx);
|
tal_del_destructor2(otx->channel, clear_otx_channel, otx);
|
||||||
|
|
||||||
if (otx->failed_or_success) {
|
if (otx->failed_or_success) {
|
||||||
otx->failed_or_success(otx->channel, exitstatus, msg);
|
otx->failed_or_success(otx->channel, success, msg);
|
||||||
tal_free(otx);
|
tal_free(otx);
|
||||||
} else {
|
} else {
|
||||||
/* For continual rebroadcasting, until channel freed. */
|
/* For continual rebroadcasting, until channel freed. */
|
||||||
@@ -216,7 +216,7 @@ static void broadcast_done(struct bitcoind *bitcoind,
|
|||||||
void broadcast_tx(struct chain_topology *topo,
|
void broadcast_tx(struct chain_topology *topo,
|
||||||
struct channel *channel, const struct bitcoin_tx *tx,
|
struct channel *channel, const struct bitcoin_tx *tx,
|
||||||
void (*failed_or_success)(struct channel *channel,
|
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. */
|
/* Channel might vanish: topo owns it to start with. */
|
||||||
struct outgoing_tx *otx = tal(topo, struct outgoing_tx);
|
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)
|
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,
|
void setup_topology(struct chain_topology *topo,
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ struct outgoing_tx {
|
|||||||
struct channel *channel;
|
struct channel *channel;
|
||||||
const char *hextx;
|
const char *hextx;
|
||||||
struct bitcoin_txid txid;
|
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 {
|
struct block {
|
||||||
@@ -166,7 +166,7 @@ struct command_result *param_feerate_estimate(struct command *cmd,
|
|||||||
void broadcast_tx(struct chain_topology *topo,
|
void broadcast_tx(struct chain_topology *topo,
|
||||||
struct channel *channel, const struct bitcoin_tx *tx,
|
struct channel *channel, const struct bitcoin_tx *tx,
|
||||||
void (*failed)(struct channel *channel,
|
void (*failed)(struct channel *channel,
|
||||||
int exitstatus,
|
bool success,
|
||||||
const char *err));
|
const char *err));
|
||||||
|
|
||||||
struct chain_topology *new_topology(struct lightningd *ld, struct log *log);
|
struct chain_topology *new_topology(struct lightningd *ld, struct log *log);
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ char *bolt11_encode_(const tal_t *ctx UNNEEDED,
|
|||||||
void broadcast_tx(struct chain_topology *topo UNNEEDED,
|
void broadcast_tx(struct chain_topology *topo UNNEEDED,
|
||||||
struct channel *channel UNNEEDED, const struct bitcoin_tx *tx UNNEEDED,
|
struct channel *channel UNNEEDED, const struct bitcoin_tx *tx UNNEEDED,
|
||||||
void (*failed)(struct channel *channel UNNEEDED,
|
void (*failed)(struct channel *channel UNNEEDED,
|
||||||
int exitstatus UNNEEDED,
|
bool success UNNEEDED,
|
||||||
const char *err))
|
const char *err))
|
||||||
{ fprintf(stderr, "broadcast_tx called!\n"); abort(); }
|
{ fprintf(stderr, "broadcast_tx called!\n"); abort(); }
|
||||||
/* Generated stub for channel_tell_depth */
|
/* Generated stub for channel_tell_depth */
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ void bitcoind_gettxout(struct bitcoind *bitcoind UNNEEDED,
|
|||||||
void broadcast_tx(struct chain_topology *topo UNNEEDED,
|
void broadcast_tx(struct chain_topology *topo UNNEEDED,
|
||||||
struct channel *channel UNNEEDED, const struct bitcoin_tx *tx UNNEEDED,
|
struct channel *channel UNNEEDED, const struct bitcoin_tx *tx UNNEEDED,
|
||||||
void (*failed)(struct channel *channel UNNEEDED,
|
void (*failed)(struct channel *channel UNNEEDED,
|
||||||
int exitstatus UNNEEDED,
|
bool success UNNEEDED,
|
||||||
const char *err))
|
const char *err))
|
||||||
{ fprintf(stderr, "broadcast_tx called!\n"); abort(); }
|
{ fprintf(stderr, "broadcast_tx called!\n"); abort(); }
|
||||||
/* Generated stub for channel_tell_depth */
|
/* Generated stub for channel_tell_depth */
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
* available outputs.
|
* available outputs.
|
||||||
*/
|
*/
|
||||||
static void wallet_withdrawal_broadcast(struct bitcoind *bitcoind UNUSED,
|
static void wallet_withdrawal_broadcast(struct bitcoind *bitcoind UNUSED,
|
||||||
int exitstatus, const char *msg,
|
bool success, const char *msg,
|
||||||
struct unreleased_tx *utx)
|
struct unreleased_tx *utx)
|
||||||
{
|
{
|
||||||
struct command *cmd = utx->wtx->cmd;
|
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! */
|
/* FIXME: This won't be necessary once we use ccan/json_out! */
|
||||||
/* Massage output into shape so it doesn't kill the JSON serialization */
|
/* 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);
|
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 */
|
/* Mark used outputs as spent */
|
||||||
wallet_confirm_utxos(ld->wallet, utx->wtx->utxos);
|
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);
|
struct json_stream *response = json_stream_success(cmd);
|
||||||
json_add_tx(response, "tx", utx->tx);
|
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));
|
was_pending(command_success(cmd, response));
|
||||||
} else {
|
} else {
|
||||||
was_pending(command_fail(cmd, LIGHTNINGD,
|
was_pending(command_fail(cmd, LIGHTNINGD,
|
||||||
|
|||||||
Reference in New Issue
Block a user