From 1fe83f47a9a2c9fd9e7625c6efc6f2f283b7c758 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 9 Nov 2016 17:14:21 +1030 Subject: [PATCH] dev-broadcast: control whether we send out transactions. Good for testing; we also flush broadcast when it's re-enabled. Signed-off-by: Rusty Russell --- daemon/chaintopology.c | 61 +++++++++++++++++++++++++++++++++++++++--- daemon/jsonrpc.c | 1 + daemon/jsonrpc.h | 1 + daemon/lightningd.c | 3 +++ daemon/lightningd.h | 3 +++ 5 files changed, 65 insertions(+), 4 deletions(-) diff --git a/daemon/chaintopology.c b/daemon/chaintopology.c index 13365dd65..e3073c83e 100644 --- a/daemon/chaintopology.c +++ b/daemon/chaintopology.c @@ -2,6 +2,7 @@ #include "bitcoin/tx.h" #include "bitcoind.h" #include "chaintopology.h" +#include "jsonrpc.h" #include "lightningd.h" #include "log.h" #include "peer.h" @@ -218,6 +219,9 @@ struct txs_to_broadcast { size_t cursor; /* These are hex encoded already, for bitcoind_sendrawtx */ const char **txs; + + /* Command to complete when we're done, iff dev-broadcast triggered */ + struct command *cmd; }; /* We just sent the last entry in txs[]. Shrink and send the next last. */ @@ -237,6 +241,8 @@ static void broadcast_remainder(struct lightningd_state *dstate, txs->cursor++; if (txs->cursor == tal_count(txs->txs)) { + if (txs->cmd) + command_success(txs->cmd, null_response(txs->cmd)); tal_free(txs); return; } @@ -248,13 +254,20 @@ static void broadcast_remainder(struct lightningd_state *dstate, /* FIXME: This is dumb. We can group txs and avoid bothering bitcoind * if any one tx is in the main chain. */ -static void rebroadcast_txs(struct lightningd_state *dstate) +static void rebroadcast_txs(struct lightningd_state *dstate, + struct command *cmd) { /* Copy txs now (peers may go away, and they own txs). */ size_t num_txs = 0; - struct txs_to_broadcast *txs = tal(dstate, struct txs_to_broadcast); + struct txs_to_broadcast *txs; struct peer *peer; + if (dstate->dev_no_broadcast) + return; + + txs = tal(dstate, struct txs_to_broadcast); + txs->cmd = cmd; + /* Put any txs we want to broadcast in ->txs. */ txs->txs = tal_arr(txs, const char *, 0); list_for_each(&dstate->peers, peer, list) { @@ -309,7 +322,11 @@ void broadcast_tx(struct peer *peer, const struct bitcoin_tx *tx, log_add_struct(peer->log, " (tx %s)", struct sha256_double, &otx->txid); - bitcoind_sendrawtx(peer, peer->dstate, otx->hextx, broadcast_done, otx); + if (peer->dstate->dev_no_broadcast) + broadcast_done(peer->dstate, 0, "dev_no_broadcast", otx); + else + bitcoind_sendrawtx(peer, peer->dstate, otx->hextx, + broadcast_done, otx); } static void free_blocks(struct lightningd_state *dstate, struct block *b) @@ -356,7 +373,7 @@ static void topology_changed(struct lightningd_state *dstate, watch_topology_changed(dstate); /* Maybe need to rebroadcast. */ - rebroadcast_txs(dstate); + rebroadcast_txs(dstate, NULL); /* Once per new block head, update fee estimate. */ bitcoind_estimate_fee(dstate, update_fee, &dstate->topology->feerate); @@ -537,6 +554,42 @@ struct txlocator *locate_tx(const void *ctx, struct lightningd_state *dstate, return loc; } +static void json_dev_broadcast(struct command *cmd, + const char *buffer, const jsmntok_t *params) +{ + jsmntok_t *enabletok; + bool enable; + + if (!json_get_params(buffer, params, + "enable", &enabletok, + NULL)) { + command_fail(cmd, "Need enable"); + return; + } + + if (!json_tok_bool(buffer, enabletok, &enable)) { + command_fail(cmd, "enable must be true or false"); + return; + } + + log_debug(cmd->dstate->base_log, "dev-broadcast: broadcast %s", + enable ? "enabled" : "disabled"); + cmd->dstate->dev_no_broadcast = !enable; + + /* If enabling, flush and wait. */ + if (enable) + rebroadcast_txs(cmd->dstate, cmd); + else + command_success(cmd, null_response(cmd)); +} + +const struct json_command dev_broadcast_command = { + "dev-broadcast", + json_dev_broadcast, + "Pretend we broadcast txs, but don't send to bitcoind", + "Returns an empty result on success (waits for flush if enabled)" +}; + void setup_topology(struct lightningd_state *dstate) { dstate->topology = tal(dstate, struct topology); diff --git a/daemon/jsonrpc.c b/daemon/jsonrpc.c index 7fb2b0d27..6980da296 100644 --- a/daemon/jsonrpc.c +++ b/daemon/jsonrpc.c @@ -316,6 +316,7 @@ static const struct json_command *cmdlist[] = { &dev_output_command, &dev_add_route_command, &dev_routefail_command, + &dev_broadcast_command, }; static void json_help(struct command *cmd, diff --git a/daemon/jsonrpc.h b/daemon/jsonrpc.h index 274f0d4b3..9d4eb5faa 100644 --- a/daemon/jsonrpc.h +++ b/daemon/jsonrpc.h @@ -90,4 +90,5 @@ extern const struct json_command dev_signcommit_command; extern const struct json_command dev_output_command; extern const struct json_command dev_routefail_command; extern const struct json_command dev_feerate_command; +extern const struct json_command dev_broadcast_command; #endif /* LIGHTNING_DAEMON_JSONRPC_H */ diff --git a/daemon/lightningd.c b/daemon/lightningd.c index 3d3938ead..8fa6bcac0 100644 --- a/daemon/lightningd.c +++ b/daemon/lightningd.c @@ -172,6 +172,8 @@ static void dev_register_opts(struct lightningd_state *dstate) controlled_time_register_opts(); opt_register_noarg("--dev-no-routefail", opt_set_bool, &dstate->dev_never_routefail, opt_hidden); + opt_register_noarg("--dev-no-broadcast", opt_set_bool, + &dstate->dev_no_broadcast, opt_hidden); } static const struct config testnet_config = { @@ -355,6 +357,7 @@ static struct lightningd_state *lightningd_state(void) list_head_init(&dstate->invoice_waiters); list_head_init(&dstate->addresses); dstate->dev_never_routefail = false; + dstate->dev_no_broadcast = false; dstate->bitcoin_req_running = false; dstate->nodes = empty_node_map(dstate); dstate->reexec = NULL; diff --git a/daemon/lightningd.h b/daemon/lightningd.h index 520fc6c9a..c2dadc24b 100644 --- a/daemon/lightningd.h +++ b/daemon/lightningd.h @@ -137,6 +137,9 @@ struct lightningd_state { /* For testing: don't fail if we can't route. */ bool dev_never_routefail; + /* For testing: don't broadcast txs (but pretend it worked)(. */ + bool dev_no_broadcast; + /* Re-exec hack for testing. */ char **reexec;