From 038ef0250a3cc9498130b49578a921d16f6c780d Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 4 Jan 2017 13:22:29 +1030 Subject: [PATCH] options: move option and config code into its own file. For the moment, the new lightningd will share all this anyway. Signed-off-by: Rusty Russell --- daemon/Makefile | 2 + daemon/lightningd.c | 461 +---------------------------------------- daemon/options.c | 495 ++++++++++++++++++++++++++++++++++++++++++++ daemon/options.h | 11 + 4 files changed, 513 insertions(+), 456 deletions(-) create mode 100644 daemon/options.c create mode 100644 daemon/options.h diff --git a/daemon/Makefile b/daemon/Makefile index fa7aca974..9c54d97c5 100644 --- a/daemon/Makefile +++ b/daemon/Makefile @@ -29,6 +29,7 @@ DAEMON_SRC := \ daemon/jsonrpc.c \ daemon/lightningd.c \ daemon/netaddr.c \ + daemon/options.c \ daemon/opt_time.c \ daemon/output_to_htlc.c \ daemon/p2p_announce.c \ @@ -80,6 +81,7 @@ DAEMON_HEADERS := \ daemon/log.h \ daemon/names.h \ daemon/netaddr.h \ + daemon/options.h \ daemon/opt_time.h \ daemon/output_to_htlc.h \ daemon/p2p_announce.h \ diff --git a/daemon/lightningd.c b/daemon/lightningd.c index d02d6e8e1..539a1dcc2 100644 --- a/daemon/lightningd.c +++ b/daemon/lightningd.c @@ -1,13 +1,12 @@ #include "bitcoind.h" #include "chaintopology.h" -#include "configdir.h" #include "db.h" #include "invoice.h" #include "irc_announce.h" #include "jsonrpc.h" #include "lightningd.h" #include "log.h" -#include "opt_time.h" +#include "options.h" #include "p2p_announce.h" #include "peer.h" #include "routing.h" @@ -26,323 +25,9 @@ #include #include #include -#include -#include -#include -#include #include #include -/* FIXME: Put into ccan/time. */ -#define TIME_FROM_SEC(sec) { { .tv_nsec = 0, .tv_sec = sec } } -#define TIME_FROM_MSEC(msec) \ - { { .tv_nsec = ((msec) % 1000) * 1000000, .tv_sec = (msec) / 1000 } } - -static char *opt_set_u64(const char *arg, u64 *u) -{ - char *endp; - unsigned long long l; - - /* This is how the manpage says to do it. Yech. */ - errno = 0; - l = strtoull(arg, &endp, 0); - if (*endp || !arg[0]) - return tal_fmt(NULL, "'%s' is not a number", arg); - *u = l; - if (errno || *u != l) - return tal_fmt(NULL, "'%s' is out of range", arg); - return NULL; -} - -static char *opt_set_u32(const char *arg, u32 *u) -{ - char *endp; - unsigned long l; - - /* This is how the manpage says to do it. Yech. */ - errno = 0; - l = strtoul(arg, &endp, 0); - if (*endp || !arg[0]) - return tal_fmt(NULL, "'%s' is not a number", arg); - *u = l; - if (errno || *u != l) - return tal_fmt(NULL, "'%s' is out of range", arg); - return NULL; -} - -static char *opt_set_s32(const char *arg, s32 *u) -{ - char *endp; - long l; - - /* This is how the manpage says to do it. Yech. */ - errno = 0; - l = strtol(arg, &endp, 0); - if (*endp || !arg[0]) - return tal_fmt(NULL, "'%s' is not a number", arg); - *u = l; - if (errno || *u != l) - return tal_fmt(NULL, "'%s' is out of range", arg); - return NULL; -} - -static void opt_show_u64(char buf[OPT_SHOW_LEN], const u64 *u) -{ - snprintf(buf, OPT_SHOW_LEN, "%"PRIu64, *u); -} - -static void opt_show_u32(char buf[OPT_SHOW_LEN], const u32 *u) -{ - snprintf(buf, OPT_SHOW_LEN, "%"PRIu32, *u); -} - -static void opt_show_s32(char buf[OPT_SHOW_LEN], const s32 *u) -{ - snprintf(buf, OPT_SHOW_LEN, "%"PRIi32, *u); -} - -static void config_register_opts(struct lightningd_state *dstate) -{ - opt_register_noarg("--bitcoind-regtest", opt_set_bool, - &dstate->config.regtest, - "Bitcoind is in regtest mode"); - opt_register_arg("--locktime-blocks", opt_set_u32, opt_show_u32, - &dstate->config.locktime_blocks, - "Blocks before peer can unilaterally spend funds"); - opt_register_arg("--max-locktime-blocks", opt_set_u32, opt_show_u32, - &dstate->config.locktime_max, - "Maximum seconds peer can lock up our funds"); - opt_register_arg("--anchor-onchain", opt_set_u32, opt_show_u32, - &dstate->config.anchor_onchain_wait, - "Blocks before we give up on pending anchor transaction"); - opt_register_arg("--anchor-confirms", opt_set_u32, opt_show_u32, - &dstate->config.anchor_confirms, - "Confirmations required for anchor transaction"); - opt_register_arg("--max-anchor-confirms", opt_set_u32, opt_show_u32, - &dstate->config.anchor_confirms_max, - "Maximum confirmations other side can wait for anchor transaction"); - opt_register_arg("--forever-confirms", opt_set_u32, opt_show_u32, - &dstate->config.forever_confirms, - "Confirmations after which we consider a reorg impossible"); - opt_register_arg("--commit-fee-min=", opt_set_u32, opt_show_u32, - &dstate->config.commitment_fee_min_percent, - "Minimum percentage of fee to accept for commitment"); - opt_register_arg("--commit-fee-max=", opt_set_u32, opt_show_u32, - &dstate->config.commitment_fee_max_percent, - "Maximum percentage of fee to accept for commitment (0 for unlimited)"); - opt_register_arg("--commit-fee=", opt_set_u32, opt_show_u32, - &dstate->config.commitment_fee_percent, - "Percentage of fee to request for their commitment"); - opt_register_arg("--override-fee-rate", opt_set_u64, opt_show_u64, - &dstate->config.override_fee_rate, - "Force a specific rate in satoshis per kb regardless of estimated fees"); - opt_register_arg("--default-fee-rate", opt_set_u64, opt_show_u64, - &dstate->config.default_fee_rate, - "Satoshis per kb if can't estimate fees"); - opt_register_arg("--min-htlc-expiry", opt_set_u32, opt_show_u32, - &dstate->config.min_htlc_expiry, - "Minimum number of blocks to accept an HTLC before expiry"); - opt_register_arg("--max-htlc-expiry", opt_set_u32, opt_show_u32, - &dstate->config.max_htlc_expiry, - "Maximum number of blocks to accept an HTLC before expiry"); - opt_register_arg("--deadline-blocks", opt_set_u32, opt_show_u32, - &dstate->config.deadline_blocks, - "Number of blocks before HTLC timeout before we drop connection"); - opt_register_arg("--bitcoind-poll", opt_set_time, opt_show_time, - &dstate->config.poll_time, - "Time between polling for new transactions"); - opt_register_arg("--commit-time", opt_set_time, opt_show_time, - &dstate->config.commit_time, - "Time after changes before sending out COMMIT"); - opt_register_arg("--fee-base", opt_set_u32, opt_show_u32, - &dstate->config.fee_base, - "Millisatoshi minimum to charge for HTLC"); - opt_register_arg("--fee-per-satoshi", opt_set_s32, opt_show_s32, - &dstate->config.fee_per_satoshi, - "Microsatoshi fee for every satoshi in HTLC"); - opt_register_arg("--add-route", opt_add_route, NULL, - dstate, - "Add route of form srcid/dstid/base/var/delay/minblocks" - "(base in millisatoshi, var in millionths of satoshi per satoshi)"); - opt_register_noarg("--disable-irc", opt_set_invbool, - &dstate->config.use_irc, - "Disable IRC peer discovery for routing"); - - opt_register_noarg("--ignore-dbversion", opt_set_bool, - &dstate->config.db_version_ignore, - "Continue despite invalid database version (DANGEROUS!)"); -} - -static void dev_register_opts(struct lightningd_state *dstate) -{ - 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 = { - /* 6 blocks to catch cheating attempts. */ - .locktime_blocks = 6, - - /* They can have up to 3 days. */ - .locktime_max = 3 * 6 * 24, - - /* Testnet can have long runs of empty blocks. */ - .anchor_onchain_wait = 100, - - /* We're fairly trusting, under normal circumstances. */ - .anchor_confirms = 1, - - /* More than 10 confirms seems overkill. */ - .anchor_confirms_max = 10, - - /* At some point, you've got to let it go... */ - /* BOLT #onchain: - * - * Outputs... are considered *irrevocably resolved* once they - * are included in a block at least 100 deep on the most-work - * blockchain. 100 blocks is far greater than the longest - * known bitcoin fork, and the same value used to wait for - * confirmations of miner's rewards[1]. - */ - .forever_confirms = 10, - - /* Testnet fees are crazy, allow infinite feerange. */ - .commitment_fee_min_percent = 0, - .commitment_fee_max_percent = 0, - - /* We offer to pay 5 times 2-block fee */ - .commitment_fee_percent = 500, - - /* Use this rate, if specified, regardless of what estimatefee says. */ - .override_fee_rate = 0, - - /* Use this rate by default if estimatefee doesn't estimate. */ - .default_fee_rate = 40000, - - /* Don't bother me unless I have 6 hours to collect. */ - .min_htlc_expiry = 6 * 6, - /* Don't lock up channel for more than 5 days. */ - .max_htlc_expiry = 5 * 6 * 24, - - /* If we're closing on HTLC expiry, and you're unresponsive, we abort. */ - .deadline_blocks = 4, - - /* How often to bother bitcoind. */ - .poll_time = TIME_FROM_SEC(10), - - /* Send commit 10msec after receiving; almost immediately. */ - .commit_time = TIME_FROM_MSEC(10), - - /* Allow dust payments */ - .fee_base = 1, - /* Take 0.001% */ - .fee_per_satoshi = 10, - - /* Discover new peers using IRC */ - .use_irc = true, - - /* Don't ignore database version */ - .db_version_ignore = false, -}; - -/* aka. "Dude, where's my coins?" */ -static const struct config mainnet_config = { - /* ~one day to catch cheating attempts. */ - .locktime_blocks = 6 * 24, - - /* They can have up to 3 days. */ - .locktime_max = 3 * 6 * 24, - - /* You should get in within 10 blocks. */ - .anchor_onchain_wait = 10, - - /* We're fairly trusting, under normal circumstances. */ - .anchor_confirms = 3, - - /* More than 10 confirms seems overkill. */ - .anchor_confirms_max = 10, - - /* At some point, you've got to let it go... */ - /* BOLT #onchain: - * - * Outputs... are considered *irrevocably resolved* once they - * are included in a block at least 100 deep on the most-work - * blockchain. 100 blocks is far greater than the longest - * known bitcoin fork, and the same value used to wait for - * confirmations of miner's rewards[1]. - */ - .forever_confirms = 100, - - /* Insist between 2 and 20 times the 2-block fee. */ - .commitment_fee_min_percent = 200, - .commitment_fee_max_percent = 2000, - - /* We offer to pay 5 times 2-block fee */ - .commitment_fee_percent = 500, - - /* Use this rate, if specified, regardless of what estimatefee says. */ - .override_fee_rate = 0, - - /* Use this rate by default if estimatefee doesn't estimate. */ - .default_fee_rate = 40000, - - /* Don't bother me unless I have 6 hours to collect. */ - .min_htlc_expiry = 6 * 6, - /* Don't lock up channel for more than 5 days. */ - .max_htlc_expiry = 5 * 6 * 24, - - /* If we're closing on HTLC expiry, and you're unresponsive, we abort. */ - .deadline_blocks = 10, - - /* How often to bother bitcoind. */ - .poll_time = TIME_FROM_SEC(30), - - /* Send commit 10msec after receiving; almost immediately. */ - .commit_time = TIME_FROM_MSEC(10), - - /* Discourage dust payments */ - .fee_base = 546000, - /* Take 0.001% */ - .fee_per_satoshi = 10, - - /* Discover new peers using IRC */ - .use_irc = true, - - /* Don't ignore database version */ - .db_version_ignore = false, -}; - -static void check_config(struct lightningd_state *dstate) -{ - /* We do this by ensuring it's less than the minimum we would accept. */ - if (dstate->config.commitment_fee_max_percent != 0 - && dstate->config.commitment_fee_max_percent - < dstate->config.commitment_fee_min_percent) - fatal("Commitment fee invalid min-max %u-%u", - dstate->config.commitment_fee_min_percent, - dstate->config.commitment_fee_max_percent); - - if (dstate->config.forever_confirms < 100 && !dstate->testnet) - log_unusual(dstate->base_log, - "Warning: forever-confirms of %u is less than 100!", - dstate->config.forever_confirms); - - if (dstate->config.anchor_confirms == 0) - fatal("anchor-confirms must be greater than zero"); - - /* BOLT #2: - * - * a node MUST estimate the deadline for successful redemption - * for each HTLC it offers. A node MUST NOT offer a HTLC - * after this deadline */ - if (dstate->config.deadline_blocks >= dstate->config.min_htlc_expiry) - fatal("Deadline %u can't be more than minimum expiry %u", - dstate->config.deadline_blocks, - dstate->config.min_htlc_expiry); -} - static struct lightningd_state *lightningd_state(void) { struct lightningd_state *dstate = tal(NULL, struct lightningd_state); @@ -373,109 +58,11 @@ static struct lightningd_state *lightningd_state(void) return dstate; } -/* Tal wrappers for opt. */ -static void *opt_allocfn(size_t size) -{ - return tal_alloc_(NULL, size, false, false, TAL_LABEL("opt_allocfn", "")); -} - -static void *tal_reallocfn(void *ptr, size_t size) -{ - if (!ptr) - return opt_allocfn(size); - tal_resize_(&ptr, 1, size, false); - return ptr; -} - -static void tal_freefn(void *ptr) -{ - tal_free(ptr); -} - -static void setup_default_config(struct lightningd_state *dstate) -{ - if (dstate->testnet) - dstate->config = testnet_config; - else - dstate->config = mainnet_config; -} - - -/* FIXME: make this nicer! */ -static void config_log_stderr_exit(const char *fmt, ...) -{ - char *msg; - va_list ap; - - va_start(ap, fmt); - - /* This is the format we expect: mangle it to remove '--'. */ - if (streq(fmt, "%s: %.*s: %s")) { - const char *argv0 = va_arg(ap, const char *); - unsigned int len = va_arg(ap, unsigned int); - const char *arg = va_arg(ap, const char *); - const char *problem = va_arg(ap, const char *); - - msg = tal_fmt(NULL, "%s line %s: %.*s: %s", - argv0, arg+strlen(arg)+1, len-2, arg+2, problem); - } else { - msg = tal_vfmt(NULL, fmt, ap); - } - va_end(ap); - - fatal("%s", msg); -} - -/* We turn the config file into cmdline arguments. */ -static void opt_parse_from_config(struct lightningd_state *dstate) -{ - char *contents, **lines; - char **argv; - int i, argc; - - contents = grab_file(dstate, "config"); - /* Doesn't have to exist. */ - if (!contents) { - if (errno != ENOENT) - fatal("Opening and reading config: %s", - strerror(errno)); - /* Now we can set up defaults, since no config file. */ - setup_default_config(dstate); - return; - } - - lines = tal_strsplit(contents, contents, "\r\n", STR_NO_EMPTY); - - /* We have to keep argv around, since opt will point into it */ - argv = tal_arr(dstate, char *, argc = 1); - argv[0] = "lightning config file"; - - for (i = 0; i < tal_count(lines) - 1; i++) { - if (strstarts(lines[i], "#")) - continue; - /* Only valid forms are "foo" and "foo=bar" */ - tal_resize(&argv, argc+1); - /* Stash line number after nul. */ - argv[argc++] = tal_fmt(argv, "--%s%c%u", lines[i], 0, i+1); - } - tal_resize(&argv, argc+1); - argv[argc] = NULL; - - opt_early_parse(argc, argv, config_log_stderr_exit); - /* Now we can set up defaults, depending on whether testnet or not */ - setup_default_config(dstate); - - opt_parse(&argc, argv, config_log_stderr_exit); - tal_free(contents); -} - int main(int argc, char *argv[]) { struct lightningd_state *dstate = lightningd_state(); - unsigned int portnum = 0; err_set_progname(argv[0]); - opt_set_alloc(opt_allocfn, tal_reallocfn, tal_freefn); if (!streq(protobuf_c_version(), PROTOBUF_C_VERSION)) errx(1, "Compiled against protobuf %s, but have %s", @@ -484,50 +71,12 @@ int main(int argc, char *argv[]) secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); - opt_register_noarg("--help|-h", opt_usage_and_exit, - "\n" - "A bitcoin lightning daemon.", - "Print this message."); - opt_register_arg("--port", opt_set_uintval, NULL, &portnum, - "Port to bind to (otherwise, we don't listen)"); - opt_register_arg("--bitcoin-datadir", opt_set_charp, NULL, - &bitcoin_datadir, - "-datadir arg for bitcoin-cli"); - opt_register_logging(dstate->base_log); - opt_register_version(); + /* Handle options and config; move to .lightningd */ + handle_opts(dstate, argc, argv); - configdir_register_opts(dstate, - &dstate->config_dir, &dstate->rpc_filename); - config_register_opts(dstate); - dev_register_opts(dstate); - - /* Get any configdir/testnet options first. */ - opt_early_parse(argc, argv, opt_log_stderr_exit); - - /* Move to config dir, to save ourselves the hassle of path manip. */ - if (chdir(dstate->config_dir) != 0) { - log_unusual(dstate->base_log, "Creating lightningd dir %s" - " (because chdir gave %s)", - dstate->config_dir, strerror(errno)); - if (mkdir(dstate->config_dir, 0700) != 0) - fatal("Could not make directory %s: %s", - dstate->config_dir, strerror(errno)); - if (chdir(dstate->config_dir) != 0) - fatal("Could not change directory %s: %s", - dstate->config_dir, strerror(errno)); - } /* Activate crash log now we're in the right place. */ crashlog_activate(dstate->base_log); - /* Now look for config file */ - opt_parse_from_config(dstate); - - opt_parse(&argc, argv, opt_log_stderr_exit); - if (argc != 1) - errx(1, "no arguments accepted"); - - check_config(dstate); - /* Ignore SIGPIPE: we look at our write return values*/ signal(SIGPIPE, SIG_IGN); @@ -545,8 +94,8 @@ int main(int argc, char *argv[]) setup_jsonrpc(dstate, dstate->rpc_filename); /* Set up connections from peers. */ - if (portnum != 0) - setup_listeners(dstate, portnum); + if (dstate->portnum != 0) + setup_listeners(dstate, dstate->portnum); /* set up IRC peer discovery */ if (dstate->config.use_irc) diff --git a/daemon/options.c b/daemon/options.c new file mode 100644 index 000000000..5984b07fe --- /dev/null +++ b/daemon/options.c @@ -0,0 +1,495 @@ +#include "daemon/bitcoind.h" +#include "daemon/configdir.h" +#include "daemon/lightningd.h" +#include "daemon/log.h" +#include "daemon/opt_time.h" +#include "daemon/options.h" +#include "daemon/routing.h" +#include "version.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Tal wrappers for opt. */ +static void *opt_allocfn(size_t size) +{ + return tal_alloc_(NULL, size, false, false, TAL_LABEL("opt_allocfn", "")); +} + +static void *tal_reallocfn(void *ptr, size_t size) +{ + if (!ptr) + return opt_allocfn(size); + tal_resize_(&ptr, 1, size, false); + return ptr; +} + +static void tal_freefn(void *ptr) +{ + tal_free(ptr); +} + +/* FIXME: Put into ccan/time. */ +#define TIME_FROM_SEC(sec) { { .tv_nsec = 0, .tv_sec = sec } } +#define TIME_FROM_MSEC(msec) \ + { { .tv_nsec = ((msec) % 1000) * 1000000, .tv_sec = (msec) / 1000 } } + +static char *opt_set_u64(const char *arg, u64 *u) +{ + char *endp; + unsigned long long l; + + /* This is how the manpage says to do it. Yech. */ + errno = 0; + l = strtoull(arg, &endp, 0); + if (*endp || !arg[0]) + return tal_fmt(NULL, "'%s' is not a number", arg); + *u = l; + if (errno || *u != l) + return tal_fmt(NULL, "'%s' is out of range", arg); + return NULL; +} + +static char *opt_set_u32(const char *arg, u32 *u) +{ + char *endp; + unsigned long l; + + /* This is how the manpage says to do it. Yech. */ + errno = 0; + l = strtoul(arg, &endp, 0); + if (*endp || !arg[0]) + return tal_fmt(NULL, "'%s' is not a number", arg); + *u = l; + if (errno || *u != l) + return tal_fmt(NULL, "'%s' is out of range", arg); + return NULL; +} + +static char *opt_set_u16(const char *arg, u16 *u) +{ + char *endp; + unsigned long l; + + /* This is how the manpage says to do it. Yech. */ + errno = 0; + l = strtoul(arg, &endp, 0); + if (*endp || !arg[0]) + return tal_fmt(NULL, "'%s' is not a number", arg); + *u = l; + if (errno || *u != l) + return tal_fmt(NULL, "'%s' is out of range", arg); + return NULL; +} + +static char *opt_set_s32(const char *arg, s32 *u) +{ + char *endp; + long l; + + /* This is how the manpage says to do it. Yech. */ + errno = 0; + l = strtol(arg, &endp, 0); + if (*endp || !arg[0]) + return tal_fmt(NULL, "'%s' is not a number", arg); + *u = l; + if (errno || *u != l) + return tal_fmt(NULL, "'%s' is out of range", arg); + return NULL; +} + +static void opt_show_u64(char buf[OPT_SHOW_LEN], const u64 *u) +{ + snprintf(buf, OPT_SHOW_LEN, "%"PRIu64, *u); +} + +static void opt_show_u32(char buf[OPT_SHOW_LEN], const u32 *u) +{ + snprintf(buf, OPT_SHOW_LEN, "%"PRIu32, *u); +} + +static void opt_show_s32(char buf[OPT_SHOW_LEN], const s32 *u) +{ + snprintf(buf, OPT_SHOW_LEN, "%"PRIi32, *u); +} + +static void opt_show_u16(char buf[OPT_SHOW_LEN], const u16 *u) +{ + snprintf(buf, OPT_SHOW_LEN, "%u", *u); +} + +static void config_register_opts(struct lightningd_state *dstate) +{ + opt_register_noarg("--bitcoind-regtest", opt_set_bool, + &dstate->config.regtest, + "Bitcoind is in regtest mode"); + opt_register_arg("--locktime-blocks", opt_set_u32, opt_show_u32, + &dstate->config.locktime_blocks, + "Blocks before peer can unilaterally spend funds"); + opt_register_arg("--max-locktime-blocks", opt_set_u32, opt_show_u32, + &dstate->config.locktime_max, + "Maximum seconds peer can lock up our funds"); + opt_register_arg("--anchor-onchain", opt_set_u32, opt_show_u32, + &dstate->config.anchor_onchain_wait, + "Blocks before we give up on pending anchor transaction"); + opt_register_arg("--anchor-confirms", opt_set_u32, opt_show_u32, + &dstate->config.anchor_confirms, + "Confirmations required for anchor transaction"); + opt_register_arg("--max-anchor-confirms", opt_set_u32, opt_show_u32, + &dstate->config.anchor_confirms_max, + "Maximum confirmations other side can wait for anchor transaction"); + opt_register_arg("--forever-confirms", opt_set_u32, opt_show_u32, + &dstate->config.forever_confirms, + "Confirmations after which we consider a reorg impossible"); + opt_register_arg("--commit-fee-min=", opt_set_u32, opt_show_u32, + &dstate->config.commitment_fee_min_percent, + "Minimum percentage of fee to accept for commitment"); + opt_register_arg("--commit-fee-max=", opt_set_u32, opt_show_u32, + &dstate->config.commitment_fee_max_percent, + "Maximum percentage of fee to accept for commitment (0 for unlimited)"); + opt_register_arg("--commit-fee=", opt_set_u32, opt_show_u32, + &dstate->config.commitment_fee_percent, + "Percentage of fee to request for their commitment"); + opt_register_arg("--override-fee-rate", opt_set_u64, opt_show_u64, + &dstate->config.override_fee_rate, + "Force a specific rate in satoshis per kb regardless of estimated fees"); + opt_register_arg("--default-fee-rate", opt_set_u64, opt_show_u64, + &dstate->config.default_fee_rate, + "Satoshis per kb if can't estimate fees"); + opt_register_arg("--min-htlc-expiry", opt_set_u32, opt_show_u32, + &dstate->config.min_htlc_expiry, + "Minimum number of blocks to accept an HTLC before expiry"); + opt_register_arg("--max-htlc-expiry", opt_set_u32, opt_show_u32, + &dstate->config.max_htlc_expiry, + "Maximum number of blocks to accept an HTLC before expiry"); + opt_register_arg("--deadline-blocks", opt_set_u32, opt_show_u32, + &dstate->config.deadline_blocks, + "Number of blocks before HTLC timeout before we drop connection"); + opt_register_arg("--bitcoind-poll", opt_set_time, opt_show_time, + &dstate->config.poll_time, + "Time between polling for new transactions"); + opt_register_arg("--commit-time", opt_set_time, opt_show_time, + &dstate->config.commit_time, + "Time after changes before sending out COMMIT"); + opt_register_arg("--fee-base", opt_set_u32, opt_show_u32, + &dstate->config.fee_base, + "Millisatoshi minimum to charge for HTLC"); + opt_register_arg("--fee-per-satoshi", opt_set_s32, opt_show_s32, + &dstate->config.fee_per_satoshi, + "Microsatoshi fee for every satoshi in HTLC"); + opt_register_arg("--add-route", opt_add_route, NULL, + dstate, + "Add route of form srcid/dstid/base/var/delay/minblocks" + "(base in millisatoshi, var in millionths of satoshi per satoshi)"); + opt_register_noarg("--disable-irc", opt_set_invbool, + &dstate->config.use_irc, + "Disable IRC peer discovery for routing"); + + opt_register_noarg("--ignore-dbversion", opt_set_bool, + &dstate->config.db_version_ignore, + "Continue despite invalid database version (DANGEROUS!)"); +} + +static void dev_register_opts(struct lightningd_state *dstate) +{ + 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 = { + /* 6 blocks to catch cheating attempts. */ + .locktime_blocks = 6, + + /* They can have up to 3 days. */ + .locktime_max = 3 * 6 * 24, + + /* Testnet can have long runs of empty blocks. */ + .anchor_onchain_wait = 100, + + /* We're fairly trusting, under normal circumstances. */ + .anchor_confirms = 1, + + /* More than 10 confirms seems overkill. */ + .anchor_confirms_max = 10, + + /* At some point, you've got to let it go... */ + /* BOLT #onchain: + * + * Outputs... are considered *irrevocably resolved* once they + * are included in a block at least 100 deep on the most-work + * blockchain. 100 blocks is far greater than the longest + * known bitcoin fork, and the same value used to wait for + * confirmations of miner's rewards[1]. + */ + .forever_confirms = 10, + + /* Testnet fees are crazy, allow infinite feerange. */ + .commitment_fee_min_percent = 0, + .commitment_fee_max_percent = 0, + + /* We offer to pay 5 times 2-block fee */ + .commitment_fee_percent = 500, + + /* Use this rate, if specified, regardless of what estimatefee says. */ + .override_fee_rate = 0, + + /* Use this rate by default if estimatefee doesn't estimate. */ + .default_fee_rate = 40000, + + /* Don't bother me unless I have 6 hours to collect. */ + .min_htlc_expiry = 6 * 6, + /* Don't lock up channel for more than 5 days. */ + .max_htlc_expiry = 5 * 6 * 24, + + /* If we're closing on HTLC expiry, and you're unresponsive, we abort. */ + .deadline_blocks = 4, + + /* How often to bother bitcoind. */ + .poll_time = TIME_FROM_SEC(10), + + /* Send commit 10msec after receiving; almost immediately. */ + .commit_time = TIME_FROM_MSEC(10), + + /* Allow dust payments */ + .fee_base = 1, + /* Take 0.001% */ + .fee_per_satoshi = 10, + + /* Discover new peers using IRC */ + .use_irc = true, + + /* Don't ignore database version */ + .db_version_ignore = false, +}; + +/* aka. "Dude, where's my coins?" */ +static const struct config mainnet_config = { + /* ~one day to catch cheating attempts. */ + .locktime_blocks = 6 * 24, + + /* They can have up to 3 days. */ + .locktime_max = 3 * 6 * 24, + + /* You should get in within 10 blocks. */ + .anchor_onchain_wait = 10, + + /* We're fairly trusting, under normal circumstances. */ + .anchor_confirms = 3, + + /* More than 10 confirms seems overkill. */ + .anchor_confirms_max = 10, + + /* At some point, you've got to let it go... */ + /* BOLT #onchain: + * + * Outputs... are considered *irrevocably resolved* once they + * are included in a block at least 100 deep on the most-work + * blockchain. 100 blocks is far greater than the longest + * known bitcoin fork, and the same value used to wait for + * confirmations of miner's rewards[1]. + */ + .forever_confirms = 100, + + /* Insist between 2 and 20 times the 2-block fee. */ + .commitment_fee_min_percent = 200, + .commitment_fee_max_percent = 2000, + + /* We offer to pay 5 times 2-block fee */ + .commitment_fee_percent = 500, + + /* Use this rate, if specified, regardless of what estimatefee says. */ + .override_fee_rate = 0, + + /* Use this rate by default if estimatefee doesn't estimate. */ + .default_fee_rate = 40000, + + /* Don't bother me unless I have 6 hours to collect. */ + .min_htlc_expiry = 6 * 6, + /* Don't lock up channel for more than 5 days. */ + .max_htlc_expiry = 5 * 6 * 24, + + /* If we're closing on HTLC expiry, and you're unresponsive, we abort. */ + .deadline_blocks = 10, + + /* How often to bother bitcoind. */ + .poll_time = TIME_FROM_SEC(30), + + /* Send commit 10msec after receiving; almost immediately. */ + .commit_time = TIME_FROM_MSEC(10), + + /* Discourage dust payments */ + .fee_base = 546000, + /* Take 0.001% */ + .fee_per_satoshi = 10, + + /* Discover new peers using IRC */ + .use_irc = true, + + /* Don't ignore database version */ + .db_version_ignore = false, +}; + +static void check_config(struct lightningd_state *dstate) +{ + /* We do this by ensuring it's less than the minimum we would accept. */ + if (dstate->config.commitment_fee_max_percent != 0 + && dstate->config.commitment_fee_max_percent + < dstate->config.commitment_fee_min_percent) + fatal("Commitment fee invalid min-max %u-%u", + dstate->config.commitment_fee_min_percent, + dstate->config.commitment_fee_max_percent); + + if (dstate->config.forever_confirms < 100 && !dstate->testnet) + log_unusual(dstate->base_log, + "Warning: forever-confirms of %u is less than 100!", + dstate->config.forever_confirms); + + if (dstate->config.anchor_confirms == 0) + fatal("anchor-confirms must be greater than zero"); + + /* BOLT #2: + * + * a node MUST estimate the deadline for successful redemption + * for each HTLC it offers. A node MUST NOT offer a HTLC + * after this deadline */ + if (dstate->config.deadline_blocks >= dstate->config.min_htlc_expiry) + fatal("Deadline %u can't be more than minimum expiry %u", + dstate->config.deadline_blocks, + dstate->config.min_htlc_expiry); +} + +static void setup_default_config(struct lightningd_state *dstate) +{ + if (dstate->testnet) + dstate->config = testnet_config; + else + dstate->config = mainnet_config; +} + + +/* FIXME: make this nicer! */ +static void config_log_stderr_exit(const char *fmt, ...) +{ + char *msg; + va_list ap; + + va_start(ap, fmt); + + /* This is the format we expect: mangle it to remove '--'. */ + if (streq(fmt, "%s: %.*s: %s")) { + const char *argv0 = va_arg(ap, const char *); + unsigned int len = va_arg(ap, unsigned int); + const char *arg = va_arg(ap, const char *); + const char *problem = va_arg(ap, const char *); + + msg = tal_fmt(NULL, "%s line %s: %.*s: %s", + argv0, arg+strlen(arg)+1, len-2, arg+2, problem); + } else { + msg = tal_vfmt(NULL, fmt, ap); + } + va_end(ap); + + fatal("%s", msg); +} + +/* We turn the config file into cmdline arguments. */ +static void opt_parse_from_config(struct lightningd_state *dstate) +{ + char *contents, **lines; + char **argv; + int i, argc; + + contents = grab_file(dstate, "config"); + /* Doesn't have to exist. */ + if (!contents) { + if (errno != ENOENT) + fatal("Opening and reading config: %s", + strerror(errno)); + /* Now we can set up defaults, since no config file. */ + setup_default_config(dstate); + return; + } + + lines = tal_strsplit(contents, contents, "\r\n", STR_NO_EMPTY); + + /* We have to keep argv around, since opt will point into it */ + argv = tal_arr(dstate, char *, argc = 1); + argv[0] = "lightning config file"; + + for (i = 0; i < tal_count(lines) - 1; i++) { + if (strstarts(lines[i], "#")) + continue; + /* Only valid forms are "foo" and "foo=bar" */ + tal_resize(&argv, argc+1); + /* Stash line number after nul. */ + argv[argc++] = tal_fmt(argv, "--%s%c%u", lines[i], 0, i+1); + } + tal_resize(&argv, argc+1); + argv[argc] = NULL; + + opt_early_parse(argc, argv, config_log_stderr_exit); + /* Now we can set up defaults, depending on whether testnet or not */ + setup_default_config(dstate); + + opt_parse(&argc, argv, config_log_stderr_exit); + tal_free(contents); +} + +void handle_opts(struct lightningd_state *dstate, int argc, char *argv[]) +{ + opt_set_alloc(opt_allocfn, tal_reallocfn, tal_freefn); + + opt_register_noarg("--help|-h", opt_usage_and_exit, + "\n" + "A bitcoin lightning daemon.", + "Print this message."); + opt_register_arg("--port", opt_set_u16, opt_show_u16, &dstate->portnum, + "Port to bind to (0 means don't listen)"); + opt_register_arg("--bitcoin-datadir", opt_set_charp, NULL, + &bitcoin_datadir, + "-datadir arg for bitcoin-cli"); + opt_register_logging(dstate->base_log); + opt_register_version(); + + configdir_register_opts(dstate, + &dstate->config_dir, &dstate->rpc_filename); + config_register_opts(dstate); + dev_register_opts(dstate); + + /* Get any configdir/testnet options first. */ + opt_early_parse(argc, argv, opt_log_stderr_exit); + + /* Move to config dir, to save ourselves the hassle of path manip. */ + if (chdir(dstate->config_dir) != 0) { + log_unusual(dstate->base_log, "Creating lightningd dir %s" + " (because chdir gave %s)", + dstate->config_dir, strerror(errno)); + if (mkdir(dstate->config_dir, 0700) != 0) + fatal("Could not make directory %s: %s", + dstate->config_dir, strerror(errno)); + if (chdir(dstate->config_dir) != 0) + fatal("Could not change directory %s: %s", + dstate->config_dir, strerror(errno)); + } + + /* Now look for config file */ + opt_parse_from_config(dstate); + + opt_parse(&argc, argv, opt_log_stderr_exit); + if (argc != 1) + errx(1, "no arguments accepted"); + + check_config(dstate); +} diff --git a/daemon/options.h b/daemon/options.h new file mode 100644 index 000000000..66b844888 --- /dev/null +++ b/daemon/options.h @@ -0,0 +1,11 @@ +#ifndef LIGHTNING_DAEMON_OPTIONS_H +#define LIGHTNING_DAEMON_OPTIONS_H +#include "config.h" +#include + +struct lightningd_state; + +/* After this, we're in the .lightning dir, config file parsed. */ +void handle_opts(struct lightningd_state *dstate, int argc, char *argv[]); + +#endif /* LIGHTNING_DAEMON_OPTIONS_H */