Skip to content

Commit

Permalink
plugins/bcli.c: sendrawtransaction now has a required `allowhighfee…
Browse files Browse the repository at this point in the history
…s` argument.

Changelog-Changed: plugin: `bcli` replacements should note that `sendrawtransaction` now has a second required Boolean argument, `allowhighfees`, which if `true`, means ignore any fee limits and just broadcast the transaction.
  • Loading branch information
ZmnSCPxj committed Jul 23, 2020
1 parent d93c79d commit b1d49f1
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 17 deletions.
7 changes: 5 additions & 2 deletions doc/PLUGINS.md
Original file line number Diff line number Diff line change
Expand Up @@ -1155,8 +1155,11 @@ The plugin must respond to `gettxout` with the following fields:

### `sendrawtransaction`

This call takes one parameter, a string representing a hex-encoded Bitcoin
transaction.
This call takes two parameters,
a string `tx` representing a hex-encoded Bitcoin transaction,
and a boolean `allowhighfees`, which if set means suppress
any high-fees check implemented in the backend, since the given
transaction may have fees that are very high.

The plugin must broadcast it and respond with the following fields:
- `success` (boolean), which is `true` if the broadcast succeeded
Expand Down
21 changes: 16 additions & 5 deletions lightningd/bitcoind.c
Original file line number Diff line number Diff line change
Expand Up @@ -293,11 +293,12 @@ static void sendrawtx_callback(const char *buf, const jsmntok_t *toks,
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)
void bitcoind_sendrawtx_ahf_(struct bitcoind *bitcoind,
const char *hextx,
bool allowhighfees,
void (*cb)(struct bitcoind *bitcoind,
bool success, const char *msg, void *),
void *cb_arg)
{
struct jsonrpc_request *req;
struct sendrawtx_call *call = tal(bitcoind, struct sendrawtx_call);
Expand All @@ -311,10 +312,20 @@ void bitcoind_sendrawtx_(struct bitcoind *bitcoind,
bitcoind->log, sendrawtx_callback,
call);
json_add_string(req->stream, "tx", hextx);
json_add_bool(req->stream, "allowhighfees", allowhighfees);
jsonrpc_request_end(req);
bitcoin_plugin_send(bitcoind, req);
}

void bitcoind_sendrawtx_(struct bitcoind *bitcoind,
const char *hextx,
void (*cb)(struct bitcoind *bitcoind,
bool success, const char *msg, void *),
void *arg)
{
return bitcoind_sendrawtx_ahf_(bitcoind, hextx, false, cb, arg);
}

/* `getrawblockbyheight`
*
* If no block were found at that height, will set each field to `null`.
Expand Down
15 changes: 15 additions & 0 deletions lightningd/bitcoind.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,21 @@ void bitcoind_estimate_fees_(struct bitcoind *bitcoind,
const u32 *), \
(arg))

void bitcoind_sendrawtx_ahf_(struct bitcoind *bitcoind,
const char *hextx,
bool allowhighfees,
void (*cb)(struct bitcoind *bitcoind,
bool success, const char *msg, void *),
void *arg);
#define bitcoind_sendrawtx_ahf(bitcoind_, hextx, allowhighfees, cb, arg)\
bitcoind_sendrawtx_ahf_((bitcoind_), (hextx), \
(allowhighfees), \
typesafe_cb_preargs(void, void *, \
(cb), (arg), \
struct bitcoind *, \
bool, const char *),\
(arg))

void bitcoind_sendrawtx_(struct bitcoind *bitcoind,
const char *hextx,
void (*cb)(struct bitcoind *bitcoind,
Expand Down
24 changes: 18 additions & 6 deletions lightningd/chaintopology.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,12 @@ 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,
bool success, const char *err))
void broadcast_tx_ahf(struct chain_topology *topo,
struct channel *channel, const struct bitcoin_tx *tx,
bool allowhighfees,
void (*failed)(struct channel *channel,
bool success,
const char *err))
{
/* Channel might vanish: topo owns it to start with. */
struct outgoing_tx *otx = tal(topo, struct outgoing_tx);
Expand All @@ -228,16 +230,26 @@ void broadcast_tx(struct chain_topology *topo,
otx->channel = channel;
bitcoin_txid(tx, &otx->txid);
otx->hextx = tal_hex(otx, rawtx);
otx->failed_or_success = failed_or_success;
otx->failed_or_success = failed;
tal_free(rawtx);
tal_add_destructor2(channel, clear_otx_channel, otx);

log_debug(topo->log, "Broadcasting txid %s",
type_to_string(tmpctx, struct bitcoin_txid, &otx->txid));

wallet_transaction_add(topo->ld->wallet, tx, 0, 0);
bitcoind_sendrawtx(topo->bitcoind, otx->hextx, broadcast_done, otx);
bitcoind_sendrawtx_ahf(topo->bitcoind, otx->hextx, allowhighfees,
broadcast_done, otx);
}
void broadcast_tx(struct chain_topology *topo,
struct channel *channel, const struct bitcoin_tx *tx,
void (*failed)(struct channel *channel,
bool success,
const char *err))
{
return broadcast_tx_ahf(topo, channel, tx, false, failed);
}


static enum watch_result closeinfo_txid_confirmed(struct lightningd *ld,
struct channel *channel,
Expand Down
8 changes: 8 additions & 0 deletions lightningd/chaintopology.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,14 @@ void broadcast_tx(struct chain_topology *topo,
void (*failed)(struct channel *channel,
bool success,
const char *err));
/* Like the above, but with an additional `allowhighfees` parameter.
* If true, suppress any high-fee checks in the backend. */
void broadcast_tx_ahf(struct chain_topology *topo,
struct channel *channel, const struct bitcoin_tx *tx,
bool allowhighfees,
void (*failed)(struct channel *channel,
bool success,
const char *err));

struct chain_topology *new_topology(struct lightningd *ld, struct log *log);
void setup_topology(struct chain_topology *topology, struct timers *timers,
Expand Down
8 changes: 6 additions & 2 deletions lightningd/onchain_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,12 @@ static void handle_onchain_broadcast_tx(struct channel *channel,
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,
is_rbf ? &handle_onchain_broadcast_rbf_tx_cb : NULL);
/* If the onchaind signals this as RBF-able, then we also
* set allowhighfees, as the transaction may be RBFed into
* high feerates as protection against the MAD-HTLC attack. */
broadcast_tx_ahf(channel->peer->ld->topology, channel,
tx, is_rbf,
is_rbf ? &handle_onchain_broadcast_rbf_tx_cb : NULL);
}

static void handle_onchain_unwatch_tx(struct channel *channel, const u8 *msg)
Expand Down
51 changes: 49 additions & 2 deletions plugins/bcli.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <ccan/tal/grab_file/grab_file.h>
#include <ccan/tal/path/path.h>
#include <ccan/tal/str/str.h>
#include <common/json.h>
#include <common/json_helpers.h>
#include <common/memleak.h>
#include <common/utils.h>
Expand Down Expand Up @@ -87,6 +88,30 @@ struct bitcoin_cli {
void *stash;
};

static u32 bitcoind_version = 0;
static void parse_getnetworkinfo_result(const char *buf)
{
const jsmntok_t *result;
const jsmntok_t *version;
bool valid;

result = json_parse_input(NULL,
buf, strlen(buf),
&valid);
if (!result || !valid)
goto end;

version = json_get_member(buf, result, "version");
if (!version)
goto end;

if (!json_to_u32(buf, version, &bitcoind_version))
bitcoind_version = 0;

end:
tal_free(result);
}

/* Add the n'th arg to *args, incrementing n and keeping args of size n+1 */
static void add_arg(const char ***args, const char *arg)
{
Expand Down Expand Up @@ -790,13 +815,29 @@ static struct command_result *sendrawtransaction(struct command *cmd,
const jsmntok_t *toks)
{
const char **params = tal_arr(cmd, const char *, 1);
bool *allowhighfees;

/* bitcoin-cli wants strings. */
if (!param(cmd, buf, toks,
p_req("tx", param_string, &params[0]),
p_req("allowhighfees", param_bool, &allowhighfees),
NULL))
return command_param_failed();

if (*allowhighfees) {
if (bitcoind_version >= 190001)
/* Starting in 19.0.1, second argument is
* maxfeerate, which when set to 0 means
* no max feerate.
*/
tal_arr_expand(&params, "0");
else
/* in older versions, second arg is allowhighfees,
* set to 1 to allow high fees.
*/
tal_arr_expand(&params, "1");
}

start_bitcoin_cli(NULL, cmd, process_sendrawtransaction, true,
BITCOIND_HIGH_PRIO, "sendrawtransaction", params, NULL);

Expand Down Expand Up @@ -838,10 +879,13 @@ static void wait_for_bitcoind(struct plugin *p)
{
int from, status, ret;
pid_t child;
const char **cmd = gather_args(bitcoind, "echo", NULL);
const char **cmd = gather_args(bitcoind, "getnetworkinfo", NULL);
char *output = NULL;
bool printed = false;

for (;;) {
output = tal_free(output);

child = pipecmdarr(NULL, &from, &from, cast_const2(char **,cmd));
if (child < 0) {
if (errno == ENOENT)
Expand All @@ -850,7 +894,7 @@ static void wait_for_bitcoind(struct plugin *p)
plugin_err(p, "%s exec failed: %s", cmd[0], strerror(errno));
}

char *output = grab_fd(cmd, from);
output = grab_fd(cmd, from);

while ((ret = waitpid(child, &status, 0)) < 0 && errno == EINTR);
if (ret != child)
Expand Down Expand Up @@ -881,6 +925,9 @@ static void wait_for_bitcoind(struct plugin *p)
}
sleep(1);
}

parse_getnetworkinfo_result(output);

tal_free(cmd);
}

Expand Down

0 comments on commit b1d49f1

Please sign in to comment.