Add DEVELOPER flag, set by default.

This is a bit messier than I'd like, but we want to clearly remove all
dev code (not just have it uncalled), so we remove fields and functions
altogether rather than stub them out.  This means we put #ifdefs in callers
in some places, but at least it's explicit.

We still run tests, but only a subset, and we run with NO_VALGRIND under
Travis to avoid increasing test times too much.

See-also: #176
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2017-10-24 12:36:14 +10:30 committed by Christian Decker
parent 8d9818ff9c
commit 3c6eec87e3
21 changed files with 301 additions and 168 deletions

View File

@ -3,13 +3,14 @@ dist: trusty
sudo: true sudo: true
env: env:
- NO_VALGRIND=1 ARCH=32 - NO_VALGRIND=1 ARCH=32 DEVELOPER=1
- NO_VALGRIND=1 ARCH=64 - NO_VALGRIND=1 ARCH=64 DEVELOPER=1
- NO_VALGRIND=0 ARCH=64 - NO_VALGRIND=0 ARCH=64 DEVELOPER=1
- NO_VALGRIND=0 ARCH=64 DEVELOPER=0
# Trusty (aka 14.04) is way way too old, so run in docker... # Trusty (aka 14.04) is way way too old, so run in docker...
script: script:
- docker pull cdecker/lightning-ci:${ARCH}bit > /dev/null - docker pull cdecker/lightning-ci:${ARCH}bit > /dev/null
- docker run --rm=true -v "${TRAVIS_BUILD_DIR}":/build -t cdecker/lightning-ci:${ARCH}bit make -j3 - docker run --rm=true -v "${TRAVIS_BUILD_DIR}":/build -t cdecker/lightning-ci:${ARCH}bit make -j3 DEVELOPER=${DEVELOPER}
- docker run --rm=true -e NO_VALGRIND=${NO_VALGRIND:-0} -e TEST_DEBUG=${TEST_DEBUG:-0} -v "${TRAVIS_BUILD_DIR}":/build -t cdecker/lightning-ci:${ARCH}bit make check - docker run --rm=true -e NO_VALGRIND=${NO_VALGRIND:-0} -e TEST_DEBUG=${TEST_DEBUG:-0} -v "${TRAVIS_BUILD_DIR}":/build -t cdecker/lightning-ci:${ARCH}bit make check DEVELOPER=${DEVELOPER}
- docker run --rm=true -v "${TRAVIS_BUILD_DIR}":/build -t cdecker/lightning-ci:${ARCH}bit make check-source - docker run --rm=true -v "${TRAVIS_BUILD_DIR}":/build -t cdecker/lightning-ci:${ARCH}bit make check-source

View File

@ -16,6 +16,15 @@ VALGRIND=valgrind -q --error-exitcode=7
VALGRIND_TEST_ARGS = --track-origins=yes --leak-check=full --show-reachable=yes --errors-for-leak-kinds=all VALGRIND_TEST_ARGS = --track-origins=yes --leak-check=full --show-reachable=yes --errors-for-leak-kinds=all
endif endif
# By default, we are in DEVELOPER mode, use DEVELOPER= on cmdline to override.
DEVELOPER := 1
ifeq ($(DEVELOPER),1)
DEV_CFLAGS=-DDEVELOPER=1
else
DEV_CFLAGS=-DDEVELOPER=0
endif
ifeq ($(COVERAGE),1) ifeq ($(COVERAGE),1)
COVFLAGS = --coverage COVFLAGS = --coverage
endif endif
@ -132,7 +141,7 @@ ALL_PROGRAMS =
CWARNFLAGS := -Werror -Wall -Wundef -Wmissing-prototypes -Wmissing-declarations -Wstrict-prototypes -Wold-style-definition CWARNFLAGS := -Werror -Wall -Wundef -Wmissing-prototypes -Wmissing-declarations -Wstrict-prototypes -Wold-style-definition
CDEBUGFLAGS := -std=gnu11 -g -fstack-protector CDEBUGFLAGS := -std=gnu11 -g -fstack-protector
CFLAGS = $(CWARNFLAGS) $(CDEBUGFLAGS) -I $(CCANDIR) $(EXTERNAL_INCLUDE_FLAGS) -I . $(FEATURES) $(COVFLAGS) -DSHACHAIN_BITS=48 -DCCAN_TAKE_DEBUG=1 CFLAGS = $(CWARNFLAGS) $(CDEBUGFLAGS) -I $(CCANDIR) $(EXTERNAL_INCLUDE_FLAGS) -I . $(FEATURES) $(COVFLAGS) $(DEV_CFLAGS) -DSHACHAIN_BITS=48 -DCCAN_TAKE_DEBUG=1
LDLIBS = -lgmp -lsqlite3 $(COVFLAGS) LDLIBS = -lgmp -lsqlite3 $(COVFLAGS)

View File

@ -615,12 +615,14 @@ static void send_commit(struct peer *peer)
u8 *msg; u8 *msg;
const struct htlc **changed_htlcs; const struct htlc **changed_htlcs;
#if DEVELOPER
/* Hack to suppress all commit sends if dev_disconnect says to */ /* Hack to suppress all commit sends if dev_disconnect says to */
if (dev_suppress_commit) { if (dev_suppress_commit) {
peer->commit_timer = NULL; peer->commit_timer = NULL;
tal_free(tmpctx); tal_free(tmpctx);
return; return;
} }
#endif
/* FIXME: Document this requirement in BOLT 2! */ /* FIXME: Document this requirement in BOLT 2! */
/* We can't send two commits in a row. */ /* We can't send two commits in a row. */
@ -1910,6 +1912,7 @@ static void handle_shutdown_cmd(struct peer *peer, const u8 *inmsg)
start_commit_timer(peer); start_commit_timer(peer);
} }
#if DEVELOPER
static void handle_dev_reenable_commit(struct peer *peer) static void handle_dev_reenable_commit(struct peer *peer)
{ {
dev_suppress_commit = false; dev_suppress_commit = false;
@ -1918,6 +1921,7 @@ static void handle_dev_reenable_commit(struct peer *peer)
wire_sync_write(MASTER_FD, wire_sync_write(MASTER_FD,
take(towire_channel_dev_reenable_commit_reply(peer))); take(towire_channel_dev_reenable_commit_reply(peer)));
} }
#endif
static void req_in(struct peer *peer, const u8 *msg) static void req_in(struct peer *peer, const u8 *msg)
{ {
@ -1946,8 +1950,10 @@ static void req_in(struct peer *peer, const u8 *msg)
handle_shutdown_cmd(peer, msg); handle_shutdown_cmd(peer, msg);
goto out; goto out;
case WIRE_CHANNEL_DEV_REENABLE_COMMIT: case WIRE_CHANNEL_DEV_REENABLE_COMMIT:
#if DEVELOPER
handle_dev_reenable_commit(peer); handle_dev_reenable_commit(peer);
goto out; goto out;
#endif /* DEVELOPER */
case WIRE_CHANNEL_NORMAL_OPERATION: case WIRE_CHANNEL_NORMAL_OPERATION:
case WIRE_CHANNEL_INIT: case WIRE_CHANNEL_INIT:
case WIRE_CHANNEL_OFFER_HTLC_REPLY: case WIRE_CHANNEL_OFFER_HTLC_REPLY:

View File

@ -11,11 +11,14 @@
bool sync_crypto_write(struct crypto_state *cs, int fd, const void *msg TAKES) bool sync_crypto_write(struct crypto_state *cs, int fd, const void *msg TAKES)
{ {
#if DEVELOPER
bool post_sabotage = false;
int type = fromwire_peektype(msg); int type = fromwire_peektype(msg);
#endif
u8 *enc = cryptomsg_encrypt_msg(NULL, cs, msg); u8 *enc = cryptomsg_encrypt_msg(NULL, cs, msg);
bool ret; bool ret;
bool post_sabotage = false;
#if DEVELOPER
switch (dev_disconnect(type)) { switch (dev_disconnect(type)) {
case DEV_DISCONNECT_BEFORE: case DEV_DISCONNECT_BEFORE:
dev_sabotage_fd(fd); dev_sabotage_fd(fd);
@ -31,11 +34,14 @@ bool sync_crypto_write(struct crypto_state *cs, int fd, const void *msg TAKES)
case DEV_DISCONNECT_NORMAL: case DEV_DISCONNECT_NORMAL:
break; break;
} }
#endif
ret = write_all(fd, enc, tal_len(enc)); ret = write_all(fd, enc, tal_len(enc));
tal_free(enc); tal_free(enc);
#if DEVELOPER
if (post_sabotage) if (post_sabotage)
dev_sabotage_fd(fd); dev_sabotage_fd(fd);
#endif
return ret; return ret;
} }

View File

@ -326,6 +326,7 @@ u8 *cryptomsg_encrypt_msg(const tal_t *ctx,
return out; return out;
} }
#if DEVELOPER
static struct io_plan *peer_write_postclose(struct io_conn *conn, static struct io_plan *peer_write_postclose(struct io_conn *conn,
struct peer_crypto_state *pcs) struct peer_crypto_state *pcs)
{ {
@ -333,6 +334,7 @@ static struct io_plan *peer_write_postclose(struct io_conn *conn,
dev_sabotage_fd(io_conn_fd(conn)); dev_sabotage_fd(io_conn_fd(conn));
return pcs->next_out(conn, pcs->peer); return pcs->next_out(conn, pcs->peer);
} }
#endif
struct io_plan *peer_write_message(struct io_conn *conn, struct io_plan *peer_write_message(struct io_conn *conn,
struct peer_crypto_state *pcs, struct peer_crypto_state *pcs,
@ -341,7 +343,10 @@ struct io_plan *peer_write_message(struct io_conn *conn,
struct peer *)) struct peer *))
{ {
struct io_plan *(*post)(struct io_conn *, struct peer_crypto_state *); struct io_plan *(*post)(struct io_conn *, struct peer_crypto_state *);
#if DEVELOPER
int type = fromwire_peektype(msg); int type = fromwire_peektype(msg);
#endif
assert(!pcs->out); assert(!pcs->out);
pcs->out = cryptomsg_encrypt_msg(conn, &pcs->cs, msg); pcs->out = cryptomsg_encrypt_msg(conn, &pcs->cs, msg);
@ -349,6 +354,7 @@ struct io_plan *peer_write_message(struct io_conn *conn,
post = peer_write_done; post = peer_write_done;
#if DEVELOPER
switch (dev_disconnect(type)) { switch (dev_disconnect(type)) {
case DEV_DISCONNECT_BEFORE: case DEV_DISCONNECT_BEFORE:
dev_sabotage_fd(io_conn_fd(conn)); dev_sabotage_fd(io_conn_fd(conn));
@ -364,6 +370,7 @@ struct io_plan *peer_write_message(struct io_conn *conn,
case DEV_DISCONNECT_NORMAL: case DEV_DISCONNECT_NORMAL:
break; break;
} }
#endif /* DEVELOPER */
/* BOLT #8: /* BOLT #8:
* * Send `lc || c` over the network buffer. * * Send `lc || c` over the network buffer.

View File

@ -50,13 +50,16 @@ static void crashlog_activate(void)
void subdaemon_debug(int argc, char *argv[]) void subdaemon_debug(int argc, char *argv[])
{ {
#if DEVELOPER
int i; int i;
bool printed = false; bool printed = false;
#endif
err_set_progname(argv[0]); err_set_progname(argv[0]);
backtrace_state = backtrace_create_state(argv[0], 0, NULL, NULL); backtrace_state = backtrace_create_state(argv[0], 0, NULL, NULL);
crashlog_activate(); crashlog_activate();
#if DEVELOPER
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {
if (strstarts(argv[i], "--dev-disconnect=")) { if (strstarts(argv[i], "--dev-disconnect=")) {
dev_disconnect_init(atoi(argv[i] dev_disconnect_init(atoi(argv[i]
@ -73,4 +76,5 @@ void subdaemon_debug(int argc, char *argv[])
printed = true; printed = true;
} }
} }
#endif
} }

View File

@ -11,6 +11,7 @@
#include <unistd.h> #include <unistd.h>
#include <wire/gen_peer_wire.h> #include <wire/gen_peer_wire.h>
#if DEVELOPER
/* We move the fd IFF we do a disconnect. */ /* We move the fd IFF we do a disconnect. */
static int dev_disconnect_fd = -1; static int dev_disconnect_fd = -1;
static char dev_disconnect_line[200]; static char dev_disconnect_line[200];
@ -132,3 +133,4 @@ void dev_blackhole_fd(int fd)
dup2(fds[1], fd); dup2(fds[1], fd);
close(fds[1]); close(fds[1]);
} }
#endif

View File

@ -3,6 +3,7 @@
#include "config.h" #include "config.h"
#include <stdbool.h> #include <stdbool.h>
#if DEVELOPER
enum dev_disconnect { enum dev_disconnect {
/* Do nothing. */ /* Do nothing. */
DEV_DISCONNECT_NORMAL = '=', DEV_DISCONNECT_NORMAL = '=',
@ -30,5 +31,6 @@ void dev_disconnect_init(int fd);
/* Hack for channeld to do DEV_DISCONNECT_SUPPRESS_COMMIT. */ /* Hack for channeld to do DEV_DISCONNECT_SUPPRESS_COMMIT. */
extern bool dev_suppress_commit; extern bool dev_suppress_commit;
#endif /* DEVELOPER */
#endif /* LIGHTNING_COMMON_DEV_DISCONNECT_H */ #endif /* LIGHTNING_COMMON_DEV_DISCONNECT_H */

View File

@ -188,8 +188,10 @@ static void rebroadcast_txs(struct chain_topology *topo, struct command *cmd)
struct txs_to_broadcast *txs; struct txs_to_broadcast *txs;
struct outgoing_tx *otx; struct outgoing_tx *otx;
#if DEVELOPER
if (topo->dev_no_broadcast) if (topo->dev_no_broadcast)
return; return;
#endif /* DEVELOPER */
txs = tal(topo, struct txs_to_broadcast); txs = tal(topo, struct txs_to_broadcast);
txs->cmd = cmd; txs->cmd = cmd;
@ -263,11 +265,13 @@ void broadcast_tx(struct chain_topology *topo,
log_add(topo->log, " (tx %s)", log_add(topo->log, " (tx %s)",
type_to_string(ltmp, struct sha256_double, &otx->txid)); type_to_string(ltmp, struct sha256_double, &otx->txid));
if (topo->dev_no_broadcast) #if DEVELOPER
if (topo->dev_no_broadcast) {
broadcast_done(topo->bitcoind, 0, "dev_no_broadcast", otx); broadcast_done(topo->bitcoind, 0, "dev_no_broadcast", otx);
else return;
bitcoind_sendrawtx(topo->bitcoind, otx->hextx, }
broadcast_done, otx); #endif
bitcoind_sendrawtx(topo->bitcoind, otx->hextx, broadcast_done, otx);
} }
static void free_blocks(struct chain_topology *topo, struct block *b) static void free_blocks(struct chain_topology *topo, struct block *b)
@ -484,6 +488,7 @@ struct txlocator *locate_tx(const void *ctx, const struct chain_topology *topo,
return tal_free(loc); return tal_free(loc);
} }
#if DEVELOPER
void json_dev_broadcast(struct command *cmd, void json_dev_broadcast(struct command *cmd,
struct chain_topology *topo, struct chain_topology *topo,
const char *buffer, const jsmntok_t *params) const char *buffer, const jsmntok_t *params)
@ -534,6 +539,7 @@ static const struct json_command dev_blockheight = {
"Returns { blockheight: u32 } on success" "Returns { blockheight: u32 } on success"
}; };
AUTODATA(json_command, &dev_blockheight); AUTODATA(json_command, &dev_blockheight);
#endif /* DEVELOPER */
/* On shutdown, peers get deleted last. That frees from our list, so /* On shutdown, peers get deleted last. That frees from our list, so
* do it now instead. */ * do it now instead. */
@ -556,8 +562,10 @@ struct chain_topology *new_topology(const tal_t *ctx, struct log *log)
topo->log = log; topo->log = log;
topo->default_fee_rate = 40000; topo->default_fee_rate = 40000;
topo->override_fee_rate = 0; topo->override_fee_rate = 0;
topo->dev_no_broadcast = false;
topo->bitcoind = new_bitcoind(topo, log); topo->bitcoind = new_bitcoind(topo, log);
#if DEVELOPER
topo->dev_no_broadcast = false;
#endif
return topo; return topo;
} }

View File

@ -113,8 +113,10 @@ struct chain_topology {
struct txwatch_hash txwatches; struct txwatch_hash txwatches;
struct txowatch_hash txowatches; struct txowatch_hash txowatches;
#if DEVELOPER
/* Suppress broadcast (for testing) */ /* Suppress broadcast (for testing) */
bool dev_no_broadcast; bool dev_no_broadcast;
#endif
}; };
/* Information relevant to locating a TX in a blockchain. */ /* Information relevant to locating a TX in a blockchain. */
@ -156,8 +158,9 @@ struct txlocator *locate_tx(const void *ctx, const struct chain_topology *topo,
void notify_new_block(struct chain_topology *topo, unsigned int height); void notify_new_block(struct chain_topology *topo, unsigned int height);
#if DEVELOPER
void json_dev_broadcast(struct command *cmd, void json_dev_broadcast(struct command *cmd,
struct chain_topology *topo, struct chain_topology *topo,
const char *buffer, const jsmntok_t *params); const char *buffer, const jsmntok_t *params);
#endif
#endif /* LIGHTNING_LIGHTNINGD_CHAINTOPOLOGY_H */ #endif /* LIGHTNING_LIGHTNINGD_CHAINTOPOLOGY_H */

View File

@ -186,6 +186,7 @@ static const struct json_command getlog_command = {
}; };
AUTODATA(json_command, &getlog_command); AUTODATA(json_command, &getlog_command);
#if DEVELOPER
static void json_rhash(struct command *cmd, static void json_rhash(struct command *cmd,
const char *buffer, const jsmntok_t *params) const char *buffer, const jsmntok_t *params)
{ {
@ -238,6 +239,7 @@ static const struct json_command dev_crash_command = {
"Simple crash test for developers" "Simple crash test for developers"
}; };
AUTODATA(json_command, &dev_crash_command); AUTODATA(json_command, &dev_crash_command);
#endif /* DEVELOPER */
static void json_getinfo(struct command *cmd, static void json_getinfo(struct command *cmd,
const char *buffer, const jsmntok_t *params) const char *buffer, const jsmntok_t *params)

View File

@ -71,11 +71,8 @@ static struct lightningd *new_lightningd(const tal_t *ctx,
struct lightningd *ld = tal(ctx, struct lightningd); struct lightningd *ld = tal(ctx, struct lightningd);
list_head_init(&ld->peers); list_head_init(&ld->peers);
ld->dev_debug_subdaemon = NULL;
htlc_in_map_init(&ld->htlcs_in); htlc_in_map_init(&ld->htlcs_in);
htlc_out_map_init(&ld->htlcs_out); htlc_out_map_init(&ld->htlcs_out);
ld->dev_disconnect_fd = -1;
ld->dev_hsm_seed = NULL;
ld->log_book = log_book; ld->log_book = log_book;
ld->log = new_log(log_book, log_book, "lightningd(%u):", (int)getpid()); ld->log = new_log(log_book, log_book, "lightningd(%u):", (int)getpid());
ld->alias = NULL; ld->alias = NULL;
@ -88,6 +85,13 @@ static struct lightningd *new_lightningd(const tal_t *ctx,
/* FIXME: Move into invoice daemon. */ /* FIXME: Move into invoice daemon. */
ld->invoices = invoices_init(ld); ld->invoices = invoices_init(ld);
#if DEVELOPER
ld->dev_debug_subdaemon = NULL;
ld->dev_disconnect_fd = -1;
ld->dev_hsm_seed = NULL;
#endif
return ld; return ld;
} }

View File

@ -114,18 +114,6 @@ struct lightningd {
/* Our chain topology. */ /* Our chain topology. */
struct chain_topology *topology; struct chain_topology *topology;
/* If we want to debug a subdaemon. */
const char *dev_debug_subdaemon;
/* If we want to set a specific non-random HSM seed. */
const u8 *dev_hsm_seed;
/* If we have a --dev-disconnect file */
int dev_disconnect_fd;
/* If we have --dev-fail-on-subdaemon-fail */
bool dev_subdaemon_fail;
/* HTLCs in flight. */ /* HTLCs in flight. */
struct htlc_in_map htlcs_in; struct htlc_in_map htlcs_in;
struct htlc_out_map htlcs_out; struct htlc_out_map htlcs_out;
@ -139,6 +127,20 @@ struct lightningd {
/* Any outstanding "pay" commands. */ /* Any outstanding "pay" commands. */
struct list_head pay_commands; struct list_head pay_commands;
#if DEVELOPER
/* If we want to debug a subdaemon. */
const char *dev_debug_subdaemon;
/* If we want to set a specific non-random HSM seed. */
const u8 *dev_hsm_seed;
/* If we have a --dev-disconnect file */
int dev_disconnect_fd;
/* If we have --dev-fail-on-subdaemon-fail */
bool dev_subdaemon_fail;
#endif /* DEVELOPER */
}; };
/** /**

View File

@ -285,6 +285,7 @@ static void config_register_opts(struct lightningd *ld)
" regtest, or litecoin)"); " regtest, or litecoin)");
} }
#if DEVELOPER
static char *opt_set_hsm_seed(const char *arg, struct lightningd *ld) static char *opt_set_hsm_seed(const char *arg, struct lightningd *ld)
{ {
ld->dev_hsm_seed = tal_hexdata(ld, arg, strlen(arg)); ld->dev_hsm_seed = tal_hexdata(ld, arg, strlen(arg));
@ -310,6 +311,7 @@ static void dev_register_opts(struct lightningd *ld)
opt_register_arg("--dev-hsm-seed=<seed>", opt_set_hsm_seed, opt_register_arg("--dev-hsm-seed=<seed>", opt_set_hsm_seed,
NULL, ld, "Hex-encoded seed for HSM"); NULL, ld, "Hex-encoded seed for HSM");
} }
#endif
static const struct config testnet_config = { static const struct config testnet_config = {
/* 6 blocks to catch cheating attempts. */ /* 6 blocks to catch cheating attempts. */
@ -560,7 +562,9 @@ void register_opts(struct lightningd *ld)
configdir_register_opts(ld, &ld->config_dir, &ld->rpc_filename); configdir_register_opts(ld, &ld->config_dir, &ld->rpc_filename);
config_register_opts(ld); config_register_opts(ld);
#if DEVELOPER
dev_register_opts(ld); dev_register_opts(ld);
#endif
} }
/* Names stolen from https://github.com/ternus/nsaproductgenerator/blob/master/nsa.js */ /* Names stolen from https://github.com/ternus/nsaproductgenerator/blob/master/nsa.js */
@ -634,6 +638,7 @@ bool handle_opts(struct lightningd *ld, int argc, char *argv[])
check_config(ld); check_config(ld);
#if DEVELOPER
if (ld->dev_hsm_seed) { if (ld->dev_hsm_seed) {
int fd; int fd;
unlink("hsm_secret"); unlink("hsm_secret");
@ -645,6 +650,7 @@ bool handle_opts(struct lightningd *ld, int argc, char *argv[])
strerror(errno)); strerror(errno));
close(fd); close(fd);
} }
#endif
return newdir; return newdir;
} }

View File

@ -204,10 +204,12 @@ void peer_fail_transient(struct peer *peer, const char *fmt, ...)
logv_add(peer->log, fmt, ap); logv_add(peer->log, fmt, ap);
va_end(ap); va_end(ap);
#if DEVELOPER
if (dev_disconnect_permanent(peer->ld)) { if (dev_disconnect_permanent(peer->ld)) {
peer_internal_error(peer, "dev_disconnect permfail"); peer_internal_error(peer, "dev_disconnect permfail");
return; return;
} }
#endif
peer_set_owner(peer, NULL); peer_set_owner(peer, NULL);
@ -759,88 +761,6 @@ static const struct json_command connect_command = {
}; };
AUTODATA(json_command, &connect_command); AUTODATA(json_command, &connect_command);
static void json_dev_fail(struct command *cmd,
const char *buffer, const jsmntok_t *params)
{
jsmntok_t *peertok;
struct peer *peer;
if (!json_get_params(buffer, params,
"id", &peertok,
NULL)) {
command_fail(cmd, "Need id");
return;
}
peer = peer_from_json(cmd->ld, buffer, peertok);
if (!peer) {
command_fail(cmd, "Could not find peer with that id");
return;
}
peer_internal_error(peer, "Failing due to dev-fail command");
command_success(cmd, null_response(cmd));
}
static const struct json_command dev_fail_command = {
"dev-fail",
json_dev_fail,
"Fail with peer {id}",
"Returns {} on success"
};
AUTODATA(json_command, &dev_fail_command);
static void dev_reenable_commit_finished(struct subd *channeld,
const u8 *resp,
const int *fds,
struct command *cmd)
{
command_success(cmd, null_response(cmd));
}
static void json_dev_reenable_commit(struct command *cmd,
const char *buffer, const jsmntok_t *params)
{
jsmntok_t *peertok;
struct peer *peer;
u8 *msg;
if (!json_get_params(buffer, params,
"id", &peertok,
NULL)) {
command_fail(cmd, "Need id");
return;
}
peer = peer_from_json(cmd->ld, buffer, peertok);
if (!peer) {
command_fail(cmd, "Could not find peer with that id");
return;
}
if (!peer->owner) {
command_fail(cmd, "Peer has no owner");
return;
}
if (!streq(peer->owner->name, "lightning_channeld")) {
command_fail(cmd, "Peer owned by %s", peer->owner->name);
return;
}
msg = towire_channel_dev_reenable_commit(peer);
subd_req(peer, peer->owner, take(msg), -1, 0,
dev_reenable_commit_finished, cmd);
}
static const struct json_command dev_reenable_commit = {
"dev-reenable-commit",
json_dev_reenable_commit,
"Reenable the commit timer on peer {id}",
"Returns {} on success"
};
AUTODATA(json_command, &dev_reenable_commit);
struct log_info { struct log_info {
enum log_level level; enum log_level level;
struct json_result *response; struct json_result *response;
@ -1700,52 +1620,6 @@ void peer_last_tx(struct peer *peer, struct bitcoin_tx *tx,
peer->last_tx = tal_steal(peer, tx); peer->last_tx = tal_steal(peer, tx);
} }
/* FIXME: Guard with heavy dev-only #ifdefs! */
static void json_sign_last_tx(struct command *cmd,
const char *buffer, const jsmntok_t *params)
{
jsmntok_t *peertok;
struct peer *peer;
struct json_result *response = new_json_result(cmd);
u8 *linear;
if (!json_get_params(buffer, params,
"id", &peertok,
NULL)) {
command_fail(cmd, "Need id");
return;
}
peer = peer_from_json(cmd->ld, buffer, peertok);
if (!peer) {
command_fail(cmd, "Could not find peer with that id");
return;
}
if (!peer->last_tx) {
command_fail(cmd, "Peer has no final transaction");
return;
}
log_debug(peer->log, "dev-sign-last-tx: signing tx with %zu outputs",
tal_count(peer->last_tx->output));
sign_last_tx(peer);
linear = linearize_tx(cmd, peer->last_tx);
json_object_start(response, NULL);
json_add_hex(response, "tx", linear, tal_len(linear));
json_object_end(response);
command_success(cmd, response);
}
static const struct json_command dev_sign_last_tx = {
"dev-sign-last-tx",
json_sign_last_tx,
"Sign and return the last commitment transaction",
"Sign last transaction with peer @id, return as @tx."
" This should never be called outside testing!"
};
AUTODATA(json_command, &dev_sign_last_tx);
/* Is this better than the last tx we were holding? */ /* Is this better than the last tx we were holding? */
static bool better_closing_fee(struct peer *peer, const struct bitcoin_tx *tx) static bool better_closing_fee(struct peer *peer, const struct bitcoin_tx *tx)
{ {
@ -2673,3 +2547,132 @@ const char *peer_state_name(enum peer_state state)
return enum_peer_state_names[i].name; return enum_peer_state_names[i].name;
return "unknown"; return "unknown";
} }
#if DEVELOPER
static void json_sign_last_tx(struct command *cmd,
const char *buffer, const jsmntok_t *params)
{
jsmntok_t *peertok;
struct peer *peer;
struct json_result *response = new_json_result(cmd);
u8 *linear;
if (!json_get_params(buffer, params,
"id", &peertok,
NULL)) {
command_fail(cmd, "Need id");
return;
}
peer = peer_from_json(cmd->ld, buffer, peertok);
if (!peer) {
command_fail(cmd, "Could not find peer with that id");
return;
}
if (!peer->last_tx) {
command_fail(cmd, "Peer has no final transaction");
return;
}
log_debug(peer->log, "dev-sign-last-tx: signing tx with %zu outputs",
tal_count(peer->last_tx->output));
sign_last_tx(peer);
linear = linearize_tx(cmd, peer->last_tx);
json_object_start(response, NULL);
json_add_hex(response, "tx", linear, tal_len(linear));
json_object_end(response);
command_success(cmd, response);
}
static const struct json_command dev_sign_last_tx = {
"dev-sign-last-tx",
json_sign_last_tx,
"Sign and return the last commitment transaction",
"Sign last transaction with peer @id, return as @tx."
" This should never be called outside testing!"
};
AUTODATA(json_command, &dev_sign_last_tx);
static void json_dev_fail(struct command *cmd,
const char *buffer, const jsmntok_t *params)
{
jsmntok_t *peertok;
struct peer *peer;
if (!json_get_params(buffer, params,
"id", &peertok,
NULL)) {
command_fail(cmd, "Need id");
return;
}
peer = peer_from_json(cmd->ld, buffer, peertok);
if (!peer) {
command_fail(cmd, "Could not find peer with that id");
return;
}
peer_internal_error(peer, "Failing due to dev-fail command");
command_success(cmd, null_response(cmd));
}
static const struct json_command dev_fail_command = {
"dev-fail",
json_dev_fail,
"Fail with peer {id}",
"Returns {} on success"
};
AUTODATA(json_command, &dev_fail_command);
static void dev_reenable_commit_finished(struct subd *channeld,
const u8 *resp,
const int *fds,
struct command *cmd)
{
command_success(cmd, null_response(cmd));
}
static void json_dev_reenable_commit(struct command *cmd,
const char *buffer, const jsmntok_t *params)
{
jsmntok_t *peertok;
struct peer *peer;
u8 *msg;
if (!json_get_params(buffer, params,
"id", &peertok,
NULL)) {
command_fail(cmd, "Need id");
return;
}
peer = peer_from_json(cmd->ld, buffer, peertok);
if (!peer) {
command_fail(cmd, "Could not find peer with that id");
return;
}
if (!peer->owner) {
command_fail(cmd, "Peer has no owner");
return;
}
if (!streq(peer->owner->name, "lightning_channeld")) {
command_fail(cmd, "Peer owned by %s", peer->owner->name);
return;
}
msg = towire_channel_dev_reenable_commit(peer);
subd_req(peer, peer->owner, take(msg), -1, 0,
dev_reenable_commit_finished, cmd);
}
static const struct json_command dev_reenable_commit = {
"dev-reenable-commit",
json_dev_reenable_commit,
"Reenable the commit timer on peer {id}",
"Returns {} on success"
};
AUTODATA(json_command, &dev_reenable_commit);
#endif /* DEVELOPER */

View File

@ -134,7 +134,6 @@ static int subd(const char *dir, const char *name, const char *debug_subdaemon,
int childmsg[2], execfail[2]; int childmsg[2], execfail[2];
pid_t childpid; pid_t childpid;
int err, *fd; int err, *fd;
bool debug = debug_subdaemon && strends(name, debug_subdaemon);
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, childmsg) != 0) if (socketpair(AF_LOCAL, SOCK_STREAM, 0, childmsg) != 0)
goto fail; goto fail;
@ -188,10 +187,12 @@ static int subd(const char *dir, const char *name, const char *debug_subdaemon,
if (i != dev_disconnect_fd) if (i != dev_disconnect_fd)
close(i); close(i);
#if DEVELOPER
if (dev_disconnect_fd != -1) if (dev_disconnect_fd != -1)
debug_arg[0] = tal_fmt(NULL, "--dev-disconnect=%i", dev_disconnect_fd); debug_arg[0] = tal_fmt(NULL, "--dev-disconnect=%i", dev_disconnect_fd);
if (debug) if (debug_subdaemon && strends(name, debug_subdaemon))
debug_arg[debug_arg[0] ? 1 : 0] = "--debugger"; debug_arg[debug_arg[0] ? 1 : 0] = "--debugger";
#endif
execl(path_join(NULL, dir, name), name, debug_arg[0], debug_arg[1], NULL); execl(path_join(NULL, dir, name), name, debug_arg[0], debug_arg[1], NULL);
child_errno_fail: child_errno_fail:
@ -236,9 +237,16 @@ int subd_raw(struct lightningd *ld, const char *name)
{ {
pid_t pid; pid_t pid;
int msg_fd; int msg_fd;
const char *debug_subd = NULL;
int disconnect_fd = -1;
pid = subd(ld->daemon_dir, name, ld->dev_debug_subdaemon, #if DEVELOPER
&msg_fd, ld->dev_disconnect_fd, NULL); debug_subd = ld->dev_debug_subdaemon;
disconnect_fd = ld->dev_disconnect_fd;
#endif /* DEVELOPER */
pid = subd(ld->daemon_dir, name, debug_subd, &msg_fd, disconnect_fd,
NULL);
if (pid == (pid_t)-1) { if (pid == (pid_t)-1) {
log_unusual(ld->log, "subd %s failed: %s", log_unusual(ld->log, "subd %s failed: %s",
name, strerror(errno)); name, strerror(errno));
@ -342,8 +350,10 @@ static void subdaemon_malformed_msg(struct subd *sd, const u8 *msg)
msg + sizeof(be16), msg + sizeof(be16),
tal_count(msg) - sizeof(be16))); tal_count(msg) - sizeof(be16)));
#if DEVELOPER
if (sd->ld->dev_subdaemon_fail) if (sd->ld->dev_subdaemon_fail)
fatal("Subdaemon %s sent malformed message", sd->name); fatal("Subdaemon %s sent malformed message", sd->name);
#endif
} }
/* Returns true if logged, false if malformed. */ /* Returns true if logged, false if malformed. */
@ -388,8 +398,10 @@ log_str_peer:
log_str_broken: log_str_broken:
log_broken(sd->log, "%s: %.*s", name, str_len, str); log_broken(sd->log, "%s: %.*s", name, str_len, str);
#if DEVELOPER
if (sd->ld->dev_subdaemon_fail) if (sd->ld->dev_subdaemon_fail)
fatal("Subdaemon %s hit error", sd->name); fatal("Subdaemon %s hit error", sd->name);
#endif
return true; return true;
} }
@ -491,7 +503,11 @@ next:
static void destroy_subd(struct subd *sd) static void destroy_subd(struct subd *sd)
{ {
int status; int status;
bool fail_if_subd_fails = sd->ld->dev_subdaemon_fail; bool fail_if_subd_fails = false;
#if DEVELOPER
fail_if_subd_fails = sd->ld->dev_subdaemon_fail;
#endif
switch (waitpid(sd->pid, &status, WNOHANG)) { switch (waitpid(sd->pid, &status, WNOHANG)) {
case 0: case 0:
@ -568,9 +584,16 @@ static struct subd *new_subd(struct lightningd *ld,
{ {
struct subd *sd = tal(ld, struct subd); struct subd *sd = tal(ld, struct subd);
int msg_fd; int msg_fd;
const char *debug_subd = NULL;
int disconnect_fd = -1;
sd->pid = subd(ld->daemon_dir, name, ld->dev_debug_subdaemon, #if DEVELOPER
&msg_fd, ld->dev_disconnect_fd, ap); debug_subd = ld->dev_debug_subdaemon;
disconnect_fd = ld->dev_disconnect_fd;
#endif /* DEVELOPER */
sd->pid = subd(ld->daemon_dir, name, debug_subd, &msg_fd, disconnect_fd,
ap);
if (sd->pid == (pid_t)-1) { if (sd->pid == (pid_t)-1) {
log_unusual(ld->log, "subd %s failed: %s", log_unusual(ld->log, "subd %s failed: %s",
name, strerror(errno)); name, strerror(errno));
@ -696,6 +719,7 @@ void subd_release_peer(struct subd *owner, struct peer *peer)
} }
} }
#if DEVELOPER
char *opt_subd_debug(const char *optarg, struct lightningd *ld) char *opt_subd_debug(const char *optarg, struct lightningd *ld)
{ {
ld->dev_debug_subdaemon = optarg; ld->dev_debug_subdaemon = optarg;
@ -731,3 +755,4 @@ bool dev_disconnect_permanent(struct lightningd *ld)
lseek(ld->dev_disconnect_fd, -r, SEEK_CUR); lseek(ld->dev_disconnect_fd, -r, SEEK_CUR);
return false; return false;
} }
#endif /* DEVELOPER */

View File

@ -163,8 +163,10 @@ void subd_release_peer(struct subd *owner, struct peer *peer);
*/ */
void subd_shutdown(struct subd *subd, unsigned int seconds); void subd_shutdown(struct subd *subd, unsigned int seconds);
#if DEVELOPER
char *opt_subd_debug(const char *optarg, struct lightningd *ld); char *opt_subd_debug(const char *optarg, struct lightningd *ld);
char *opt_subd_dev_disconnect(const char *optarg, struct lightningd *ld); char *opt_subd_dev_disconnect(const char *optarg, struct lightningd *ld);
bool dev_disconnect_permanent(struct lightningd *ld); bool dev_disconnect_permanent(struct lightningd *ld);
#endif /* DEVELOPER */
#endif /* LIGHTNING_LIGHTNINGD_SUBD_H */ #endif /* LIGHTNING_LIGHTNINGD_SUBD_H */

View File

@ -39,6 +39,7 @@ static void do_write(const void *buf, size_t len)
#define status_trace(fmt, ...) \ #define status_trace(fmt, ...) \
printf(fmt "\n", __VA_ARGS__) printf(fmt "\n", __VA_ARGS__)
#if DEVELOPER
/* AUTOGENERATED MOCKS START */ /* AUTOGENERATED MOCKS START */
/* Generated stub for dev_blackhole_fd */ /* Generated stub for dev_blackhole_fd */
void dev_blackhole_fd(int fd UNNEEDED) void dev_blackhole_fd(int fd UNNEEDED)
@ -52,6 +53,7 @@ enum dev_disconnect dev_disconnect(int pkt_type)
{ {
return DEV_DISCONNECT_NORMAL; return DEV_DISCONNECT_NORMAL;
} }
#endif /* DEVELOPER */
/* We test what look like unknown messages. */ /* We test what look like unknown messages. */
#define is_unknown_msg_discardable(x) 0 #define is_unknown_msg_discardable(x) 0

View File

@ -88,6 +88,16 @@ struct wallet *wallet_new(const tal_t *ctx UNNEEDED, struct log *log UNNEEDED)
{ fprintf(stderr, "wallet_new called!\n"); abort(); } { fprintf(stderr, "wallet_new called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */ /* AUTOGENERATED MOCKS END */
/* We only need these in developer mode */
#if DEVELOPER
/* Generated stub for opt_subd_debug */
char *opt_subd_debug(const char *optarg UNNEEDED, struct lightningd *ld UNNEEDED)
{ fprintf(stderr, "opt_subd_debug called!\n"); abort(); }
/* Generated stub for opt_subd_dev_disconnect */
char *opt_subd_dev_disconnect(const char *optarg UNNEEDED, struct lightningd *ld UNNEEDED)
{ fprintf(stderr, "opt_subd_dev_disconnect called!\n"); abort(); }
#endif
#undef main #undef main
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {

View File

@ -23,6 +23,7 @@ import utils
bitcoind = None bitcoind = None
TEST_DIR = tempfile.mkdtemp(prefix='lightning-') TEST_DIR = tempfile.mkdtemp(prefix='lightning-')
VALGRIND = os.getenv("NO_VALGRIND", "0") == "0" VALGRIND = os.getenv("NO_VALGRIND", "0") == "0"
DEVELOPER = os.getenv("DEVELOPER", "0") == "1"
TEST_DEBUG = os.getenv("TEST_DEBUG", "0") == "1" TEST_DEBUG = os.getenv("TEST_DEBUG", "0") == "1"
print("Testing results are in {}".format(TEST_DIR)) print("Testing results are in {}".format(TEST_DIR))
@ -104,7 +105,8 @@ class NodeFactory(object):
with open(os.path.join(lightning_dir, "dev_disconnect"), "w") as f: with open(os.path.join(lightning_dir, "dev_disconnect"), "w") as f:
f.write("\n".join(disconnect)) f.write("\n".join(disconnect))
daemon.cmd_line.append("--dev-disconnect=dev_disconnect") daemon.cmd_line.append("--dev-disconnect=dev_disconnect")
daemon.cmd_line.append("--dev-fail-on-subdaemon-fail") if DEVELOPER:
daemon.cmd_line.append("--dev-fail-on-subdaemon-fail")
opts = [] if options is None else options opts = [] if options is None else options
for opt in opts: for opt in opts:
daemon.cmd_line.append(opt) daemon.cmd_line.append(opt)
@ -441,6 +443,7 @@ class LightningDTests(BaseLightningDTests):
l2.daemon.wait_for_log('sendrawtx exit 0') l2.daemon.wait_for_log('sendrawtx exit 0')
assert l1.bitcoin.rpc.getmempoolinfo()['size'] == 1 assert l1.bitcoin.rpc.getmempoolinfo()['size'] == 1
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_permfail(self): def test_permfail(self):
l1,l2 = self.connect() l1,l2 = self.connect()
@ -485,6 +488,7 @@ class LightningDTests(BaseLightningDTests):
bitcoind.rpc.generate(6) bitcoind.rpc.generate(6)
l2.daemon.wait_for_log('onchaind complete, forgetting peer') l2.daemon.wait_for_log('onchaind complete, forgetting peer')
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_onchain_first_commit(self): def test_onchain_first_commit(self):
"""Onchain handling where funder immediately drops to chain""" """Onchain handling where funder immediately drops to chain"""
@ -527,6 +531,7 @@ class LightningDTests(BaseLightningDTests):
bitcoind.rpc.generate(6) bitcoind.rpc.generate(6)
l1.daemon.wait_for_log('onchaind complete, forgetting peer') l1.daemon.wait_for_log('onchaind complete, forgetting peer')
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_onchain_dust_out(self): def test_onchain_dust_out(self):
"""Onchain handling of outgoing dust htlcs (they should fail)""" """Onchain handling of outgoing dust htlcs (they should fail)"""
# HTLC 1->2, 1 fails after it's irrevocably committed # HTLC 1->2, 1 fails after it's irrevocably committed
@ -579,6 +584,7 @@ class LightningDTests(BaseLightningDTests):
# Payment failed, BTW # Payment failed, BTW
assert l2.rpc.listinvoice('onchain_dust_out')[0]['complete'] == False assert l2.rpc.listinvoice('onchain_dust_out')[0]['complete'] == False
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_onchain_timeout(self): def test_onchain_timeout(self):
"""Onchain handling of outgoing failed htlcs""" """Onchain handling of outgoing failed htlcs"""
# HTLC 1->2, 1 fails just after it's irrevocably committed # HTLC 1->2, 1 fails just after it's irrevocably committed
@ -634,6 +640,7 @@ class LightningDTests(BaseLightningDTests):
# Payment failed, BTW # Payment failed, BTW
assert l2.rpc.listinvoice('onchain_timeout')[0]['complete'] == False assert l2.rpc.listinvoice('onchain_timeout')[0]['complete'] == False
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_onchain_middleman(self): def test_onchain_middleman(self):
# HTLC 1->2->3, 1->2 goes down after 2 gets preimage from 3. # HTLC 1->2->3, 1->2 goes down after 2 gets preimage from 3.
disconnects = ['-WIRE_UPDATE_FULFILL_HTLC', 'permfail'] disconnects = ['-WIRE_UPDATE_FULFILL_HTLC', 'permfail']
@ -708,6 +715,7 @@ class LightningDTests(BaseLightningDTests):
l1.bitcoin.rpc.generate(100) l1.bitcoin.rpc.generate(100)
l2.daemon.wait_for_log('onchaind complete, forgetting peer') l2.daemon.wait_for_log('onchaind complete, forgetting peer')
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_penalty_inhtlc(self): def test_penalty_inhtlc(self):
"""Test penalty transaction with an incoming HTLC""" """Test penalty transaction with an incoming HTLC"""
# We suppress each one after first commit; HTLC gets added not fulfilled. # We suppress each one after first commit; HTLC gets added not fulfilled.
@ -829,6 +837,7 @@ class LightningDTests(BaseLightningDTests):
# FIXME: Test wallet balance... # FIXME: Test wallet balance...
l2.daemon.wait_for_log('onchaind complete, forgetting peer') l2.daemon.wait_for_log('onchaind complete, forgetting peer')
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_permfail_new_commit(self): def test_permfail_new_commit(self):
# Test case where we have two possible commits: it will use new one. # Test case where we have two possible commits: it will use new one.
disconnects = ['-WIRE_REVOKE_AND_ACK', 'permfail'] disconnects = ['-WIRE_REVOKE_AND_ACK', 'permfail']
@ -864,6 +873,7 @@ class LightningDTests(BaseLightningDTests):
l1.daemon.wait_for_log('onchaind complete, forgetting peer') l1.daemon.wait_for_log('onchaind complete, forgetting peer')
l2.daemon.wait_for_log('onchaind complete, forgetting peer') l2.daemon.wait_for_log('onchaind complete, forgetting peer')
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_permfail_htlc_in(self): def test_permfail_htlc_in(self):
# Test case where we fail with unsettled incoming HTLC. # Test case where we fail with unsettled incoming HTLC.
disconnects = ['-WIRE_UPDATE_FULFILL_HTLC', 'permfail'] disconnects = ['-WIRE_UPDATE_FULFILL_HTLC', 'permfail']
@ -905,6 +915,7 @@ class LightningDTests(BaseLightningDTests):
bitcoind.rpc.generate(6) bitcoind.rpc.generate(6)
l2.daemon.wait_for_log('onchaind complete, forgetting peer') l2.daemon.wait_for_log('onchaind complete, forgetting peer')
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_permfail_htlc_out(self): def test_permfail_htlc_out(self):
# Test case where we fail with unsettled outgoing HTLC. # Test case where we fail with unsettled outgoing HTLC.
disconnects = ['+WIRE_REVOKE_AND_ACK', 'permfail'] disconnects = ['+WIRE_REVOKE_AND_ACK', 'permfail']
@ -1003,6 +1014,7 @@ class LightningDTests(BaseLightningDTests):
ret = l1.rpc.dev_ping(l2.info['id'], 1000, s) ret = l1.rpc.dev_ping(l2.info['id'], 1000, s)
assert ret['totlen'] == 0 assert ret['totlen'] == 0
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_ping(self): def test_ping(self):
l1,l2 = self.connect() l1,l2 = self.connect()
@ -1014,6 +1026,7 @@ class LightningDTests(BaseLightningDTests):
# channeld pinging # channeld pinging
self.ping_tests(l1, l2) self.ping_tests(l1, l2)
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_routing_gossip_reconnect(self): def test_routing_gossip_reconnect(self):
# Connect two peers, reconnect and then see if we resume the # Connect two peers, reconnect and then see if we resume the
# gossip. # gossip.
@ -1042,6 +1055,7 @@ class LightningDTests(BaseLightningDTests):
self.fund_channel(l1, l2, 10**6) self.fund_channel(l1, l2, 10**6)
self.fund_channel(l1, l3, 10**6) self.fund_channel(l1, l3, 10**6)
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1 for --dev-broadcast-interval")
def test_routing_gossip(self): def test_routing_gossip(self):
nodes = [self.node_factory.get_node() for _ in range(5)] nodes = [self.node_factory.get_node() for _ in range(5)]
l1 = nodes[0] l1 = nodes[0]
@ -1142,6 +1156,7 @@ class LightningDTests(BaseLightningDTests):
route = copy.deepcopy(baseroute) route = copy.deepcopy(baseroute)
l1.rpc.sendpay(to_json(route), rhash) l1.rpc.sendpay(to_json(route), rhash)
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_disconnect(self): def test_disconnect(self):
# These should all make us fail, and retry. # These should all make us fail, and retry.
# FIXME: Configure short timeout for reconnect! # FIXME: Configure short timeout for reconnect!
@ -1157,6 +1172,7 @@ class LightningDTests(BaseLightningDTests):
l1.daemon.wait_for_log('Failed connected out for {}, will try again' l1.daemon.wait_for_log('Failed connected out for {}, will try again'
.format(l2.info['id'])) .format(l2.info['id']))
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_disconnect_funder(self): def test_disconnect_funder(self):
# Now error on funder side duringchannel open. # Now error on funder side duringchannel open.
disconnects = ['-WIRE_OPEN_CHANNEL', disconnects = ['-WIRE_OPEN_CHANNEL',
@ -1177,6 +1193,7 @@ class LightningDTests(BaseLightningDTests):
self.assertRaises(ValueError, l1.rpc.fundchannel, l2.info['id'], 20000) self.assertRaises(ValueError, l1.rpc.fundchannel, l2.info['id'], 20000)
assert l1.rpc.getpeer(l2.info['id']) == None assert l1.rpc.getpeer(l2.info['id']) == None
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_disconnect_fundee(self): def test_disconnect_fundee(self):
# Now error on fundee side during channel open. # Now error on fundee side during channel open.
disconnects = ['-WIRE_ACCEPT_CHANNEL', disconnects = ['-WIRE_ACCEPT_CHANNEL',
@ -1195,6 +1212,7 @@ class LightningDTests(BaseLightningDTests):
self.assertRaises(ValueError, l1.rpc.fundchannel, l2.info['id'], 20000) self.assertRaises(ValueError, l1.rpc.fundchannel, l2.info['id'], 20000)
assert l1.rpc.getpeer(l2.info['id']) == None assert l1.rpc.getpeer(l2.info['id']) == None
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_disconnect_half_signed(self): def test_disconnect_half_signed(self):
# Now, these are the corner cases. Fundee sends funding_signed, # Now, these are the corner cases. Fundee sends funding_signed,
# but funder doesn't receive it. # but funder doesn't receive it.
@ -1214,6 +1232,7 @@ class LightningDTests(BaseLightningDTests):
assert l1.rpc.getpeer(l2.info['id']) == None assert l1.rpc.getpeer(l2.info['id']) == None
assert l2.rpc.getpeer(l1.info['id'])['peerid'] == l1.info['id'] assert l2.rpc.getpeer(l1.info['id'])['peerid'] == l1.info['id']
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_reconnect_signed(self): def test_reconnect_signed(self):
# This will fail *after* both sides consider channel opening. # This will fail *after* both sides consider channel opening.
disconnects = ['+WIRE_FUNDING_SIGNED'] disconnects = ['+WIRE_FUNDING_SIGNED']
@ -1243,6 +1262,7 @@ class LightningDTests(BaseLightningDTests):
l1.daemon.wait_for_log('-> CHANNELD_NORMAL') l1.daemon.wait_for_log('-> CHANNELD_NORMAL')
l2.daemon.wait_for_log('-> CHANNELD_NORMAL') l2.daemon.wait_for_log('-> CHANNELD_NORMAL')
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_reconnect_openingd(self): def test_reconnect_openingd(self):
# Openingd thinks we're still opening; funder reconnects.. # Openingd thinks we're still opening; funder reconnects..
disconnects = ['0WIRE_ACCEPT_CHANNEL'] disconnects = ['0WIRE_ACCEPT_CHANNEL']
@ -1272,6 +1292,7 @@ class LightningDTests(BaseLightningDTests):
# Just to be sure, second openingd hand over to channeld. # Just to be sure, second openingd hand over to channeld.
l2.daemon.wait_for_log('lightning_openingd.*REPLY WIRE_OPENING_FUNDEE_REPLY with 2 fds') l2.daemon.wait_for_log('lightning_openingd.*REPLY WIRE_OPENING_FUNDEE_REPLY with 2 fds')
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_reconnect_normal(self): def test_reconnect_normal(self):
# Should reconnect fine even if locked message gets lost. # Should reconnect fine even if locked message gets lost.
disconnects = ['-WIRE_FUNDING_LOCKED', disconnects = ['-WIRE_FUNDING_LOCKED',
@ -1283,6 +1304,7 @@ class LightningDTests(BaseLightningDTests):
self.fund_channel(l1, l2, 10**6) self.fund_channel(l1, l2, 10**6)
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_reconnect_sender_add1(self): def test_reconnect_sender_add1(self):
# Fail after add is OK, will cause payment failure though. # Fail after add is OK, will cause payment failure though.
disconnects = ['-WIRE_UPDATE_ADD_HTLC-nocommit', disconnects = ['-WIRE_UPDATE_ADD_HTLC-nocommit',
@ -1309,6 +1331,7 @@ class LightningDTests(BaseLightningDTests):
# This will send commit, so will reconnect as required. # This will send commit, so will reconnect as required.
l1.rpc.sendpay(to_json(route), rhash) l1.rpc.sendpay(to_json(route), rhash)
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_reconnect_sender_add(self): def test_reconnect_sender_add(self):
disconnects = ['-WIRE_COMMITMENT_SIGNED', disconnects = ['-WIRE_COMMITMENT_SIGNED',
'@WIRE_COMMITMENT_SIGNED', '@WIRE_COMMITMENT_SIGNED',
@ -1334,6 +1357,7 @@ class LightningDTests(BaseLightningDTests):
for i in range(0,len(disconnects)): for i in range(0,len(disconnects)):
l1.daemon.wait_for_log('Already have funding locked in') l1.daemon.wait_for_log('Already have funding locked in')
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_reconnect_receiver_add(self): def test_reconnect_receiver_add(self):
disconnects = ['-WIRE_COMMITMENT_SIGNED', disconnects = ['-WIRE_COMMITMENT_SIGNED',
'@WIRE_COMMITMENT_SIGNED', '@WIRE_COMMITMENT_SIGNED',
@ -1357,6 +1381,7 @@ class LightningDTests(BaseLightningDTests):
l1.daemon.wait_for_log('Already have funding locked in') l1.daemon.wait_for_log('Already have funding locked in')
assert l2.rpc.listinvoice('testpayment2')[0]['complete'] == True assert l2.rpc.listinvoice('testpayment2')[0]['complete'] == True
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_reconnect_receiver_fulfill(self): def test_reconnect_receiver_fulfill(self):
# Ordering matters: after +WIRE_UPDATE_FULFILL_HTLC, channeld # Ordering matters: after +WIRE_UPDATE_FULFILL_HTLC, channeld
# will continue and try to send WIRE_COMMITMENT_SIGNED: if # will continue and try to send WIRE_COMMITMENT_SIGNED: if
@ -1386,6 +1411,7 @@ class LightningDTests(BaseLightningDTests):
l1.daemon.wait_for_log('Already have funding locked in') l1.daemon.wait_for_log('Already have funding locked in')
assert l2.rpc.listinvoice('testpayment2')[0]['complete'] == True assert l2.rpc.listinvoice('testpayment2')[0]['complete'] == True
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_shutdown_reconnect(self): def test_shutdown_reconnect(self):
disconnects = ['-WIRE_SHUTDOWN', disconnects = ['-WIRE_SHUTDOWN',
'@WIRE_SHUTDOWN', '@WIRE_SHUTDOWN',
@ -1413,6 +1439,7 @@ class LightningDTests(BaseLightningDTests):
l2.daemon.wait_for_logs(['sendrawtx exit 0', '-> CLOSINGD_COMPLETE']) l2.daemon.wait_for_logs(['sendrawtx exit 0', '-> CLOSINGD_COMPLETE'])
assert l1.bitcoin.rpc.getmempoolinfo()['size'] == 1 assert l1.bitcoin.rpc.getmempoolinfo()['size'] == 1
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_closing_negotiation_reconnect(self): def test_closing_negotiation_reconnect(self):
disconnects = ['-WIRE_CLOSING_SIGNED', disconnects = ['-WIRE_CLOSING_SIGNED',
'@WIRE_CLOSING_SIGNED', '@WIRE_CLOSING_SIGNED',
@ -1511,6 +1538,7 @@ class LightningDTests(BaseLightningDTests):
assert outputs[0] > 8990000 assert outputs[0] > 8990000
assert outputs[2] == 10000000 assert outputs[2] == 10000000
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_channel_persistence(self): def test_channel_persistence(self):
# Start two nodes and open a channel (to remember). l2 will # Start two nodes and open a channel (to remember). l2 will
# mysteriously die while committing the first HTLC so we can # mysteriously die while committing the first HTLC so we can

View File

@ -25,6 +25,7 @@ LIGHTNINGD_CONFIG = {
"locktime-blocks": 6, "locktime-blocks": 6,
} }
DEVELOPER = os.getenv("DEVELOPER", "0") == "1"
def write_config(filename, opts): def write_config(filename, opts):
with open(filename, 'w') as f: with open(filename, 'w') as f:
@ -237,11 +238,11 @@ class LightningD(TailableProc):
'--bitcoin-datadir={}'.format(bitcoin_dir), '--bitcoin-datadir={}'.format(bitcoin_dir),
'--lightning-dir={}'.format(lightning_dir), '--lightning-dir={}'.format(lightning_dir),
'--port={}'.format(port), '--port={}'.format(port),
'--network=regtest', '--network=regtest'
'--dev-broadcast-interval=1000',
'--dev-hsm-seed={}'.format(seed.hex())
] ]
if DEVELOPER:
self.cmd_line += ['--dev-broadcast-interval=1000',
'--dev-hsm-seed={}'.format(seed.hex())]
self.cmd_line += ["--{}={}".format(k, v) for k, v in LIGHTNINGD_CONFIG.items()] self.cmd_line += ["--{}={}".format(k, v) for k, v in LIGHTNINGD_CONFIG.items()]
self.prefix = 'lightningd(%d)' % (port) self.prefix = 'lightningd(%d)' % (port)