lightningd/bitcoind: use the Bitcoin plugin for getutxout

This commit is contained in:
darosior 2020-01-09 16:38:12 +01:00 committed by Rusty Russell
parent 78cb921b80
commit c79ab0f1b0
8 changed files with 137 additions and 131 deletions

View File

@ -781,89 +781,88 @@ void bitcoind_getchaininfo_(struct bitcoind *bitcoind,
req);
}
struct get_output {
/* `getutxout`
*
* Get informations about an UTXO. If the TXO is spent, the plugin will set
* all fields to `null`.
* {
* "amount": <The output's amount in *sats*>,
* "script": "The output's scriptPubKey",
* }
*/
struct getutxout_call {
struct bitcoind *bitcoind;
unsigned int blocknum, txnum, outnum;
/* The real callback */
void (*cb)(struct bitcoind *bitcoind, const struct bitcoin_tx_output *txout, void *arg);
void (*cb)(struct bitcoind *bitcoind,
const struct bitcoin_tx_output *txout, void *arg);
/* The real callback arg */
void *cbarg;
void *cb_arg;
};
static bool process_gettxout(struct bitcoin_cli *bcli)
static void getutxout_callback(const char *buf, const jsmntok_t *toks,
const jsmntok_t *idtok,
struct getutxout_call *call)
{
void (*cb)(struct bitcoind *bitcoind,
const struct bitcoin_tx_output *output,
void *arg) = bcli->cb;
const jsmntok_t *tokens, *valuetok, *scriptpubkeytok, *hextok;
struct bitcoin_tx_output out;
bool valid;
const jsmntok_t *resulttok, *amounttok, *scripttok;
struct bitcoin_tx_output txout;
/* As of at least v0.15.1.0, bitcoind returns "success" but an empty
string on a spent gettxout */
if (*bcli->exitstatus != 0 || bcli->output_bytes == 0) {
cb(bcli->bitcoind, NULL, bcli->cb_arg);
return true;
resulttok = json_get_member(buf, toks, "result");
if (!resulttok)
bitcoin_plugin_error(call->bitcoind, buf, toks, "getutxout",
"bad 'result' field");
scripttok = json_get_member(buf, resulttok, "script");
if (!scripttok)
bitcoin_plugin_error(call->bitcoind, buf, toks, "getutxout",
"bad 'script' field");
if (json_tok_is_null(buf, scripttok)) {
db_begin_transaction(call->bitcoind->ld->wallet->db);
call->cb(call->bitcoind, NULL, call->cb_arg);
db_commit_transaction(call->bitcoind->ld->wallet->db);
goto clean;
}
txout.script = json_tok_bin_from_hex(tmpctx, buf, scripttok);
tokens = json_parse_input(bcli->output, bcli->output, bcli->output_bytes,
&valid);
if (!tokens)
fatal("%s: %s response",
bcli_args(tmpctx, bcli), valid ? "partial" : "invalid");
amounttok = json_get_member(buf, resulttok, "amount");
if (!amounttok)
bitcoin_plugin_error(call->bitcoind, buf, toks, "getutxout",
"bad 'amount' field");
if (!json_to_sat(buf, amounttok, &txout.amount))
bitcoin_plugin_error(call->bitcoind, buf, toks, "getutxout",
"bad sats amount");
if (tokens[0].type != JSMN_OBJECT)
fatal("%s: gave non-object (%.*s)?",
bcli_args(tmpctx, bcli),
(int)bcli->output_bytes, bcli->output);
db_begin_transaction(call->bitcoind->ld->wallet->db);
call->cb(call->bitcoind, &txout, call->cb_arg);
db_commit_transaction(call->bitcoind->ld->wallet->db);
valuetok = json_get_member(bcli->output, tokens, "value");
if (!valuetok)
fatal("%s: had no value member (%.*s)?",
bcli_args(tmpctx, bcli),
(int)bcli->output_bytes, bcli->output);
if (!json_to_bitcoin_amount(bcli->output, valuetok, &out.amount.satoshis)) /* Raw: talking to bitcoind */
fatal("%s: had bad value (%.*s)?",
bcli_args(tmpctx, bcli),
(int)bcli->output_bytes, bcli->output);
scriptpubkeytok = json_get_member(bcli->output, tokens, "scriptPubKey");
if (!scriptpubkeytok)
fatal("%s: had no scriptPubKey member (%.*s)?",
bcli_args(tmpctx, bcli),
(int)bcli->output_bytes, bcli->output);
hextok = json_get_member(bcli->output, scriptpubkeytok, "hex");
if (!hextok)
fatal("%s: had no scriptPubKey->hex member (%.*s)?",
bcli_args(tmpctx, bcli),
(int)bcli->output_bytes, bcli->output);
out.script = tal_hexdata(bcli, bcli->output + hextok->start,
hextok->end - hextok->start);
if (!out.script)
fatal("%s: scriptPubKey->hex invalid hex (%.*s)?",
bcli_args(tmpctx, bcli),
(int)bcli->output_bytes, bcli->output);
cb(bcli->bitcoind, &out, bcli->cb_arg);
return true;
clean:
tal_free(call);
}
void bitcoind_gettxout(struct bitcoind *bitcoind,
const struct bitcoin_txid *txid, const u32 outnum,
void (*cb)(struct bitcoind *bitcoind,
const struct bitcoin_tx_output *txout,
void *arg),
void *arg)
void bitcoind_getutxout_(struct bitcoind *bitcoind,
const struct bitcoin_txid *txid, const u32 outnum,
void (*cb)(struct bitcoind *bitcoind,
const struct bitcoin_tx_output *txout,
void *arg),
void *cb_arg)
{
start_bitcoin_cli(bitcoind, NULL,
process_gettxout, true, BITCOIND_LOW_PRIO, cb, arg,
"gettxout",
take(type_to_string(NULL, struct bitcoin_txid, txid)),
take(tal_fmt(NULL, "%u", outnum)),
NULL);
struct jsonrpc_request *req;
struct getutxout_call *call = tal(bitcoind, struct getutxout_call);
call->bitcoind = bitcoind;
call->cb = cb;
call->cb_arg = cb_arg;
req = jsonrpc_request_start(bitcoind, "getutxout", bitcoind->log,
getutxout_callback, call);
json_add_txid(req->stream, "txid", txid);
json_add_num(req->stream, "vout", outnum);
jsonrpc_request_end(req);
plugin_request_send(strmap_get(&bitcoind->pluginsmap, "getutxout"),
req);
}
/* Context for the getfilteredblock call. Wraps the actual arguments while we
@ -901,7 +900,7 @@ process_getfilteredblock_step2(struct bitcoind *bitcoind,
call->current_outpoint++;
if (call->current_outpoint < tal_count(call->outpoints)) {
o = call->outpoints[call->current_outpoint];
bitcoind_gettxout(bitcoind, &o->txid, o->outnum,
bitcoind_getutxout(bitcoind, &o->txid, o->outnum,
process_getfilteredblock_step2, call);
} else {
/* If there were no more outpoints to check, we call the callback. */
@ -969,7 +968,7 @@ static void process_getfilteredblock_step1(struct bitcoind *bitcoind,
* store the one's that are unspent in
* call->result->outpoints. */
o = call->outpoints[call->current_outpoint];
bitcoind_gettxout(bitcoind, &o->txid, o->outnum,
bitcoind_getutxout(bitcoind, &o->txid, o->outnum,
process_getfilteredblock_step2, call);
}
}

View File

@ -166,12 +166,19 @@ void bitcoind_getrawblockbyheight_(struct bitcoind *bitcoind,
struct bitcoin_block *),\
(arg))
void bitcoind_gettxout(struct bitcoind *bitcoind,
const struct bitcoin_txid *txid, const u32 outnum,
void (*cb)(struct bitcoind *bitcoind,
const struct bitcoin_tx_output *txout,
void *arg),
void *arg);
void bitcoind_getutxout_(struct bitcoind *bitcoind,
const struct bitcoin_txid *txid, const u32 outnum,
void (*cb)(struct bitcoind *bitcoind,
const struct bitcoin_tx_output *txout,
void *arg),
void *arg);
#define bitcoind_getutxout(bitcoind_, txid_, vout_, cb, arg) \
bitcoind_getutxout_((bitcoind_), (txid_), (vout_), \
typesafe_cb_preargs(void, void *, \
(cb), (arg), \
struct bitcoind *, \
struct bitcoin_tx_output *),\
(arg))
void bitcoind_getclientversion(struct bitcoind *bitcoind);

View File

@ -774,11 +774,11 @@ struct command_result *cancel_channel_before_broadcast(struct command *cmd,
/* Note: The above check and this check can't completely ensure that
* the funding transaction isn't broadcast. We can't know if the funding
* is broadcast by external wallet and the transaction hasn't been onchain. */
bitcoind_gettxout(cmd->ld->topology->bitcoind,
&cancel_channel->funding_txid,
cancel_channel->funding_outnum,
process_check_funding_broadcast,
notleak(cc));
bitcoind_getutxout(cmd->ld->topology->bitcoind,
&cancel_channel->funding_txid,
cancel_channel->funding_outnum,
process_check_funding_broadcast,
notleak(cc));
return command_still_pending(cmd);
}

View File

@ -2266,10 +2266,10 @@ static struct command_result *json_dev_forget_channel(struct command *cmd,
"or `dev-fail` instead.");
}
bitcoind_gettxout(cmd->ld->topology->bitcoind,
&forget->channel->funding_txid,
forget->channel->funding_outnum,
process_dev_forget_channel, forget);
bitcoind_getutxout(cmd->ld->topology->bitcoind,
&forget->channel->funding_txid,
forget->channel->funding_outnum,
process_dev_forget_channel, forget);
return command_still_pending(cmd);
}

View File

@ -13,14 +13,14 @@ size_t bigsize_get(const u8 *p UNNEEDED, size_t max UNNEEDED, bigsize_t *val UNN
/* Generated stub for bigsize_put */
size_t bigsize_put(u8 buf[BIGSIZE_MAX_LEN] UNNEEDED, bigsize_t v UNNEEDED)
{ fprintf(stderr, "bigsize_put called!\n"); abort(); }
/* Generated stub for bitcoind_gettxout */
void bitcoind_gettxout(struct bitcoind *bitcoind UNNEEDED,
const struct bitcoin_txid *txid UNNEEDED, const u32 outnum UNNEEDED,
void (*cb)(struct bitcoind *bitcoind UNNEEDED,
const struct bitcoin_tx_output *txout UNNEEDED,
void *arg) UNNEEDED,
void *arg UNNEEDED)
{ fprintf(stderr, "bitcoind_gettxout called!\n"); abort(); }
/* Generated stub for bitcoind_getutxout_ */
void bitcoind_getutxout_(struct bitcoind *bitcoind UNNEEDED,
const struct bitcoin_txid *txid UNNEEDED, const u32 outnum UNNEEDED,
void (*cb)(struct bitcoind *bitcoind UNNEEDED,
const struct bitcoin_tx_output *txout UNNEEDED,
void *arg) UNNEEDED,
void *arg UNNEEDED)
{ fprintf(stderr, "bitcoind_getutxout_ called!\n"); abort(); }
/* Generated stub for bolt11_decode */
struct bolt11 *bolt11_decode(const tal_t *ctx UNNEEDED, const char *str UNNEEDED,
const char *description UNNEEDED, char **fail UNNEEDED)
@ -90,7 +90,7 @@ struct fee_states *dup_fee_states(const tal_t *ctx UNNEEDED,
/* Generated stub for encode_scriptpubkey_to_addr */
char *encode_scriptpubkey_to_addr(const tal_t *ctx UNNEEDED,
const struct chainparams *chainparams UNNEEDED,
const u8 *scriptPubkey UNNEEDED)
const u8 *scriptPubkey UNNEEDED)
{ fprintf(stderr, "encode_scriptpubkey_to_addr called!\n"); abort(); }
/* Generated stub for fatal */
void fatal(const char *fmt UNNEEDED, ...)
@ -198,6 +198,10 @@ enum address_parse_result json_to_address_scriptpubkey(const tal_t *ctx UNNEEDED
const char *buffer UNNEEDED,
const jsmntok_t *tok UNNEEDED, const u8 **scriptpubkey UNNEEDED)
{ fprintf(stderr, "json_to_address_scriptpubkey called!\n"); abort(); }
/* Generated stub for json_tok_channel_id */
bool json_tok_channel_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
struct channel_id *cid UNNEEDED)
{ fprintf(stderr, "json_tok_channel_id called!\n"); abort(); }
/* Generated stub for json_to_node_id */
bool json_to_node_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
struct node_id *id UNNEEDED)
@ -206,10 +210,6 @@ bool json_to_node_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
bool json_to_short_channel_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
struct short_channel_id *scid UNNEEDED)
{ fprintf(stderr, "json_to_short_channel_id called!\n"); abort(); }
/* Generated stub for json_tok_channel_id */
bool json_tok_channel_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
struct channel_id *cid UNNEEDED)
{ fprintf(stderr, "json_tok_channel_id called!\n"); abort(); }
/* Generated stub for kill_uncommitted_channel */
void kill_uncommitted_channel(struct uncommitted_channel *uc UNNEEDED,
const char *why UNNEEDED)

View File

@ -37,14 +37,14 @@ size_t bigsize_get(const u8 *p UNNEEDED, size_t max UNNEEDED, bigsize_t *val UNN
/* Generated stub for bigsize_put */
size_t bigsize_put(u8 buf[BIGSIZE_MAX_LEN] UNNEEDED, bigsize_t v UNNEEDED)
{ fprintf(stderr, "bigsize_put called!\n"); abort(); }
/* Generated stub for bitcoind_gettxout */
void bitcoind_gettxout(struct bitcoind *bitcoind UNNEEDED,
const struct bitcoin_txid *txid UNNEEDED, const u32 outnum UNNEEDED,
void (*cb)(struct bitcoind *bitcoind UNNEEDED,
const struct bitcoin_tx_output *txout UNNEEDED,
void *arg) UNNEEDED,
void *arg UNNEEDED)
{ fprintf(stderr, "bitcoind_gettxout called!\n"); abort(); }
/* Generated stub for bitcoind_getutxout_ */
void bitcoind_getutxout_(struct bitcoind *bitcoind UNNEEDED,
const struct bitcoin_txid *txid UNNEEDED, const u32 outnum UNNEEDED,
void (*cb)(struct bitcoind *bitcoind UNNEEDED,
const struct bitcoin_tx_output *txout UNNEEDED,
void *arg) UNNEEDED,
void *arg UNNEEDED)
{ fprintf(stderr, "bitcoind_getutxout_ 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,
@ -89,7 +89,7 @@ void delay_then_reconnect(struct channel *channel UNNEEDED, u32 seconds_delay UN
/* Generated stub for encode_scriptpubkey_to_addr */
char *encode_scriptpubkey_to_addr(const tal_t *ctx UNNEEDED,
const struct chainparams *chainparams UNNEEDED,
const u8 *scriptPubkey UNNEEDED)
const u8 *scriptPubkey UNNEEDED)
{ fprintf(stderr, "encode_scriptpubkey_to_addr called!\n"); abort(); }
/* Generated stub for fatal */
void fatal(const char *fmt UNNEEDED, ...)
@ -343,21 +343,6 @@ enum address_parse_result json_to_address_scriptpubkey(const tal_t *ctx UNNEEDED
/* Generated stub for json_to_bool */
bool json_to_bool(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, bool *b UNNEEDED)
{ fprintf(stderr, "json_to_bool called!\n"); abort(); }
/* Generated stub for json_to_node_id */
bool json_to_node_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
struct node_id *id UNNEEDED)
{ fprintf(stderr, "json_to_node_id called!\n"); abort(); }
/* Generated stub for json_to_number */
bool json_to_number(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
unsigned int *num UNNEEDED)
{ fprintf(stderr, "json_to_number called!\n"); abort(); }
/* Generated stub for json_to_preimage */
bool json_to_preimage(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, struct preimage *preimage UNNEEDED)
{ fprintf(stderr, "json_to_preimage called!\n"); abort(); }
/* Generated stub for json_to_short_channel_id */
bool json_to_short_channel_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
struct short_channel_id *scid UNNEEDED)
{ fprintf(stderr, "json_to_short_channel_id called!\n"); abort(); }
/* Generated stub for json_tok_bin_from_hex */
u8 *json_tok_bin_from_hex(const tal_t *ctx UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED)
{ fprintf(stderr, "json_tok_bin_from_hex called!\n"); abort(); }
@ -374,6 +359,21 @@ int json_tok_full_len(const jsmntok_t *t UNNEEDED)
/* Generated stub for json_tok_streq */
bool json_tok_streq(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, const char *str UNNEEDED)
{ fprintf(stderr, "json_tok_streq called!\n"); abort(); }
/* Generated stub for json_to_node_id */
bool json_to_node_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
struct node_id *id UNNEEDED)
{ fprintf(stderr, "json_to_node_id called!\n"); abort(); }
/* Generated stub for json_to_number */
bool json_to_number(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
unsigned int *num UNNEEDED)
{ fprintf(stderr, "json_to_number called!\n"); abort(); }
/* Generated stub for json_to_preimage */
bool json_to_preimage(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, struct preimage *preimage UNNEEDED)
{ fprintf(stderr, "json_to_preimage called!\n"); abort(); }
/* Generated stub for json_to_short_channel_id */
bool json_to_short_channel_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
struct short_channel_id *scid UNNEEDED)
{ fprintf(stderr, "json_to_short_channel_id called!\n"); abort(); }
/* Generated stub for kill_uncommitted_channel */
void kill_uncommitted_channel(struct uncommitted_channel *uc UNNEEDED,
const char *why UNNEEDED)
@ -587,12 +587,12 @@ u8 *towire_channel_got_revoke_reply(const tal_t *ctx UNNEEDED)
/* Generated stub for towire_channel_offer_htlc */
u8 *towire_channel_offer_htlc(const tal_t *ctx UNNEEDED, struct amount_msat amount_msat UNNEEDED, u32 cltv_expiry UNNEEDED, const struct sha256 *payment_hash UNNEEDED, const u8 onion_routing_packet[1366])
{ fprintf(stderr, "towire_channel_offer_htlc called!\n"); abort(); }
/* Generated stub for towire_channel_send_shutdown */
u8 *towire_channel_send_shutdown(const tal_t *ctx UNNEEDED, const u8 *shutdown_scriptpubkey UNNEEDED)
{ fprintf(stderr, "towire_channel_send_shutdown called!\n"); abort(); }
/* Generated stub for towire_channel_sending_commitsig_reply */
u8 *towire_channel_sending_commitsig_reply(const tal_t *ctx UNNEEDED)
{ fprintf(stderr, "towire_channel_sending_commitsig_reply called!\n"); abort(); }
/* Generated stub for towire_channel_send_shutdown */
u8 *towire_channel_send_shutdown(const tal_t *ctx UNNEEDED, const u8 *shutdown_scriptpubkey UNNEEDED)
{ fprintf(stderr, "towire_channel_send_shutdown called!\n"); abort(); }
/* Generated stub for towire_channel_specific_feerates */
u8 *towire_channel_specific_feerates(const tal_t *ctx UNNEEDED, u32 feerate_base UNNEEDED, u32 feerate_ppm UNNEEDED)
{ fprintf(stderr, "towire_channel_specific_feerates called!\n"); abort(); }

View File

@ -3599,8 +3599,8 @@ static void process_utxo_result(struct bitcoind *bitcoind,
/* If we have more, resolve them too. */
tal_arr_remove(&utxos, 0);
if (tal_count(utxos) != 0) {
bitcoind_gettxout(bitcoind, &utxos[0]->txid, utxos[0]->outnum,
process_utxo_result, utxos);
bitcoind_getutxout(bitcoind, &utxos[0]->txid, utxos[0]->outnum,
process_utxo_result, utxos);
} else
tal_free(utxos);
}
@ -3610,8 +3610,8 @@ void wallet_clean_utxos(struct wallet *w, struct bitcoind *bitcoind)
struct utxo **utxos = wallet_get_utxos(NULL, w, output_state_reserved);
if (tal_count(utxos) != 0) {
bitcoind_gettxout(bitcoind, &utxos[0]->txid, utxos[0]->outnum,
process_utxo_result, notleak(utxos));
bitcoind_getutxout(bitcoind, &utxos[0]->txid, utxos[0]->outnum,
process_utxo_result, notleak(utxos));
} else
tal_free(utxos);
}

View File

@ -930,7 +930,7 @@ static void process_utxo_result(struct bitcoind *bitcoind,
json_array_end(rescan->response);
was_pending(command_success(rescan->cmd, rescan->response));
} else {
bitcoind_gettxout(
bitcoind_getutxout(
bitcoind->ld->topology->bitcoind, &rescan->utxos[0]->txid,
rescan->utxos[0]->outnum, process_utxo_result, rescan);
}
@ -956,7 +956,7 @@ static struct command_result *json_dev_rescan_outputs(struct command *cmd,
json_array_end(rescan->response);
return command_success(cmd, rescan->response);
}
bitcoind_gettxout(cmd->ld->topology->bitcoind, &rescan->utxos[0]->txid,
bitcoind_getutxout(cmd->ld->topology->bitcoind, &rescan->utxos[0]->txid,
rescan->utxos[0]->outnum, process_utxo_result,
rescan);
return command_still_pending(cmd);