diff --git a/src/datum_conf.c b/src/datum_conf.c index 609b9d6..559a2fc 100644 --- a/src/datum_conf.c +++ b/src/datum_conf.c @@ -56,20 +56,25 @@ const T_DATUM_CONFIG_ITEM datum_config_options[] = { { .var_type = DATUM_CONF_STRING, .category = "bitcoind", .name = "rpccookiefile", .description = "Path to file to read RPC cookie from, for communication with local bitcoind.", .required = false, .ptr = datum_config.bitcoind_rpccookiefile, .default_string[0] = "", .max_string_len = sizeof(datum_config.bitcoind_rpccookiefile) }, { .var_type = DATUM_CONF_STRING, .category = "bitcoind", .name = "rpcuser", .description = "RPC username for communication with local bitcoind.", + .example = "\"datum\"", .required = false, .ptr = datum_config.bitcoind_rpcuser, .default_string[0] = "", .max_string_len = sizeof(datum_config.bitcoind_rpcuser) }, { .var_type = DATUM_CONF_STRING, .category = "bitcoind", .name = "rpcpassword", .description = "RPC password for communication with local bitcoind.", + .example = "\"something only you know\"", .required = false, .ptr = datum_config.bitcoind_rpcpassword, .default_string[0] = "", .max_string_len = sizeof(datum_config.bitcoind_rpcpassword) }, { .var_type = DATUM_CONF_STRING, .category = "bitcoind", .name = "rpcurl", .description = "RPC URL for communication with local bitcoind. (GBT Template Source)", + .example = "\"http://localhost:8332\"", .required = true, .ptr = datum_config.bitcoind_rpcurl, .max_string_len = sizeof(datum_config.bitcoind_rpcurl) }, { .var_type = DATUM_CONF_INT, .category = "bitcoind", .name = "work_update_seconds", .description = "How many seconds between normal work updates? (5-120, 40 suggested)", .required = false, .ptr = &datum_config.bitcoind_work_update_seconds, .default_int = 40 }, { .var_type = DATUM_CONF_BOOL, .category = "bitcoind", .name = "notify_fallback", .description = "Fall back to less efficient methods for new block notifications. Can disable if you use blocknotify.", + .example_default = true, .required = false, .ptr = &datum_config.bitcoind_notify_fallback, .default_bool = true }, // stratum v1 server configs { .var_type = DATUM_CONF_STRING, .category = "stratum", .name = "listen_addr", .description = "IP address to listen for Stratum Gateway connections", .required = false, .ptr = datum_config.stratum_v1_listen_addr, .default_string[0] = "", .max_string_len = sizeof(datum_config.stratum_v1_listen_addr) }, { .var_type = DATUM_CONF_INT, .category = "stratum", .name = "listen_port", .description = "Listening port for Stratum Gateway", + .example_default = true, .required = false, .ptr = &datum_config.stratum_v1_listen_port, .default_int = 23334 }, { .var_type = DATUM_CONF_INT, .category = "stratum", .name = "max_clients_per_thread", .description = "Maximum clients per Stratum server thread", .required = false, .ptr = &datum_config.stratum_v1_max_clients_per_thread, .default_int = 128 }, @@ -98,10 +103,13 @@ const T_DATUM_CONFIG_ITEM datum_config_options[] = { // mining settings { .var_type = DATUM_CONF_STRING, .category = "mining", .name = "pool_address", .description = "Bitcoin address used for mining rewards.", + .example = "\"put your own Bitcoin invoice address here\"", .required = true, .ptr = datum_config.mining_pool_address, .max_string_len = sizeof(datum_config.mining_pool_address) }, { .var_type = DATUM_CONF_STRING, .category = "mining", .name = "coinbase_tag_primary", .description = "Text to have in the primary coinbase tag when not using pool (overridden by DATUM Pool)", + .example_default = true, .required = false, .ptr = datum_config.mining_coinbase_tag_primary, .default_string[0] = "DATUM Gateway", .max_string_len = sizeof(datum_config.mining_coinbase_tag_primary) }, { .var_type = DATUM_CONF_STRING, .category = "mining", .name = "coinbase_tag_secondary", .description = "Text to have in the secondary coinbase tag (Short name/identifier)", + .example_default = true, .required = false, .ptr = datum_config.mining_coinbase_tag_secondary, .default_string[0] = "DATUM User", .max_string_len = sizeof(datum_config.mining_coinbase_tag_secondary) }, { .var_type = DATUM_CONF_INT, .category = "mining", .name = "coinbase_unique_id", .description = "A unique ID between 1 and 65535. This is appended to the coinbase. Make unique per instance of datum with the same coinbase tags.", .required = false, .ptr = &datum_config.coinbase_unique_id, .default_int = 4242 }, @@ -110,13 +118,16 @@ const T_DATUM_CONFIG_ITEM datum_config_options[] = { // API/dashboard { .var_type = DATUM_CONF_STRING, .category = "api", .name = "admin_password", .description = "API password for actions/changes (username 'admin'; disabled if blank)", + .example = "\"\"", .required = false, .ptr = datum_config.api_admin_password, .default_string[0] = "", .max_string_len = sizeof(datum_config.api_admin_password) }, { .var_type = DATUM_CONF_STRING, .category = "api", .name = "listen_addr", .description = "IP address to listen for API/dashboard requests", .required = false, .ptr = datum_config.api_listen_addr, .default_string[0] = "", .max_string_len = sizeof(datum_config.api_listen_addr) }, { .var_type = DATUM_CONF_INT, .category = "api", .name = "listen_port", .description = "Port to listen for API/dashboard requests (0=disabled)", + .example = "7152", .required = false, .ptr = &datum_config.api_listen_port, .default_int = 0 }, { .var_type = DATUM_CONF_BOOL, .category = "api", .name = "modify_conf", .description = "Enable modifying the config file from API/dashboard", - .required = false, .ptr = &datum_config.api_modify_conf, .default_int = 0 }, + .example_default = true, + .required = false, .ptr = &datum_config.api_modify_conf, .default_bool = false }, // extra block submissions list { .var_type = DATUM_CONF_STRING_ARRAY, .category = "extra_block_submissions", .name = "urls", .description = "Array of bitcoind RPC URLs to submit our blocks to directly. Include auth info: http://user:pass@IP", @@ -124,20 +135,26 @@ const T_DATUM_CONFIG_ITEM datum_config_options[] = { // logger { .var_type = DATUM_CONF_BOOL, .category = "logger", .name = "log_to_console", .description = "Enable logging of messages to the console", + .example_default = true, .required = false, .ptr = &datum_config.clog_to_console, .default_bool = true }, { .var_type = DATUM_CONF_BOOL, .category = "logger", .name = "log_to_stderr", .description = "Log console messages to stderr *instead* of stdout", .required = false, .ptr = &datum_config.clog_to_stderr, .default_bool = false }, { .var_type = DATUM_CONF_BOOL, .category = "logger", .name = "log_to_file", .description = "Enable logging of messages to a file", + .example_default = true, .required = false, .ptr = &datum_config.clog_to_file, .default_bool = false }, { .var_type = DATUM_CONF_STRING, .category = "logger", .name = "log_file", .description = "Path to file to write log messages, when enabled", + .example = "\"/var/log/datum.log\"", .required = false, .ptr = datum_config.clog_file, .default_string[0] = "", .max_string_len = sizeof(datum_config.clog_file) }, { .var_type = DATUM_CONF_BOOL, .category = "logger", .name = "log_rotate_daily", .description = "Rotate the message log file at midnight", + .example_default = true, .required = false, .ptr = &datum_config.clog_rotate_daily, .default_bool = true }, { .var_type = DATUM_CONF_BOOL, .category = "logger", .name = "log_calling_function", .description = "Log the name of the calling function when logging", .required = false, .ptr = &datum_config.clog_calling_function, .default_bool = true }, { .var_type = DATUM_CONF_INT, .category = "logger", .name = "log_level_console", .description = "Minimum log level for console messages (0=All, 1=Debug, 2=Info, 3=Warn, 4=Error, 5=Fatal)", + .example_default = true, .required = false, .ptr = &datum_config.clog_level_console, .default_int = 2 }, { .var_type = DATUM_CONF_INT, .category = "logger", .name = "log_level_file", .description = "Minimum log level for log file messages (0=All, 1=Debug, 2=Info, 3=Warn, 4=Error, 5=Fatal)", + .example_default = true, .required = false, .ptr = &datum_config.clog_level_file, .default_int = 1 }, // datum options @@ -148,12 +165,15 @@ const T_DATUM_CONFIG_ITEM datum_config_options[] = { { .var_type = DATUM_CONF_STRING, .category = "datum", .name = "pool_pubkey", .description = "Public key of the DATUM server for initiating encrypted connection. Get from secure location, or set to empty to auto-fetch.", .required = false, .ptr = datum_config.datum_pool_pubkey, .default_string[0] = "f21f2f0ef0aa1970468f22bad9bb7f4535146f8e4a8f646bebc93da3d89b1406f40d032f09a417d94dc068055df654937922d2c89522e3e8f6f0e649de473003", .max_string_len = sizeof(datum_config.datum_pool_pubkey) }, { .var_type = DATUM_CONF_BOOL, .category = "datum", .name = "pool_pass_workers", .description = "Pass stratum miner usernames as sub-worker names to the pool (pool_username.miner's username)", + .example_default = true, .required = false, .ptr = &datum_config.datum_pool_pass_workers, .default_bool = true }, { .var_type = DATUM_CONF_BOOL, .category = "datum", .name = "pool_pass_full_users", .description = "Pass stratum miner usernames as raw usernames to the pool (use if putting multiple payout addresses on miners behind this gateway)", + .example_default = true, .required = false, .ptr = &datum_config.datum_pool_pass_full_users, .default_bool = true }, { .var_type = DATUM_CONF_BOOL, .category = "datum", .name = "always_pay_self", .description = "Always include my datum.pool_username payout in my blocks if possible", .required = false, .ptr = &datum_config.datum_always_pay_self, .default_bool = true }, { .var_type = DATUM_CONF_BOOL, .category = "datum", .name = "pooled_mining_only", .description = "If the DATUM pool server becomes unavailable, terminate miner connections (otherwise, 100% of any blocks you find pay mining.pool_address)", + .example_default = true, .required = false, .ptr = &datum_config.datum_pooled_mining_only, .default_bool = true }, { .var_type = DATUM_CONF_INT, .category = "datum", .name = "protocol_global_timeout", .description = "If no valid messages are received from the DATUM server in this many seconds, give up and try to reconnect", .required = false, .ptr = &datum_config.datum_protocol_global_timeout, .default_int = 60 }, @@ -471,6 +491,7 @@ void datum_gateway_help(const char * const argv0) { puts("Command line options:\n"); puts(" -c, --config=FILE ..................... Path to configuration JSON file (default: ./datum_gateway_config.json)"); puts(" -?, --help ............................ Print this help"); + puts(" --example-conf ........................ Print an example configuration JSON file"); puts(" --version ............................. Print this software's name and version"); puts(""); puts("Configuration file options:\n\n{"); @@ -512,3 +533,54 @@ void datum_gateway_help(const char * const argv0) { } puts(" }\n}\n"); } + +void datum_gateway_example_conf(void) { + const char *lastcat = ""; + bool first = true; + + puts("{"); + for (unsigned int i = 0; i < NUM_CONFIG_ITEMS; ++i) { + const T_DATUM_CONFIG_ITEM * const opt = &datum_config_options[i]; + if (!(opt->example || opt->example_default)) { + continue; + } + if (strcmp(opt->category, lastcat)) { + if (*lastcat) { puts("\n\t},"); } + printf("\t\"%s\": {\n", opt->category); + lastcat = opt->category; + first = true; + } + if (first) { + first = false; + } else { + puts(","); + } + printf("\t\t\"%s\": ", opt->name); + if (opt->example) { + printf("%s", opt->example); + } else if (opt->example_default) { + switch (opt->var_type) { + case DATUM_CONF_INT: { + printf("%d", opt->default_int); + break; + } + + case DATUM_CONF_BOOL: { + printf("%s", opt->default_bool ? "true" : "false"); + break; + } + + case DATUM_CONF_STRING: { + printf("\"%s\"", opt->default_string[0]); + break; + } + + case DATUM_CONF_STRING_ARRAY: { + puts("[]"); + break; + } + } + } + } + puts("\n\t}\n}"); +} diff --git a/src/datum_conf.h b/src/datum_conf.h index 227e83e..901e032 100644 --- a/src/datum_conf.h +++ b/src/datum_conf.h @@ -56,6 +56,8 @@ typedef struct { char category[32]; char name[64]; char description[512]; + const char *example; + bool example_default; enum datum_conf_vartype var_type; union { int default_int; @@ -147,5 +149,6 @@ extern global_config_t datum_config; int datum_read_config(const char *conffile); void datum_gateway_help(const char *argv0); +void datum_gateway_example_conf(void); #endif diff --git a/src/datum_gateway.c b/src/datum_gateway.c index c0e25b1..027de77 100644 --- a/src/datum_gateway.c +++ b/src/datum_gateway.c @@ -70,6 +70,7 @@ static char doc[] = "Decentralized Alternative Templates for Universal Mining - static char args_doc[] = ""; static struct argp_option options[] = { {"help", '?', 0, 0, "Show custom help", 0}, + {"example-conf", 0x100, NULL, 0, "Print an example configuration JSON file", 0}, {"usage", '?', 0, 0, "Show custom help", 0}, {"config", 'c', "FILE", 0, "Configuration JSON file"}, {0} @@ -83,6 +84,7 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) { struct arguments *arguments = state->input; switch (key) { case '?': { + datum_print_banner(); datum_gateway_help(state->argv[0]); exit(0); break; @@ -91,6 +93,10 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) { arguments->config_file = arg; break; } + case 0x100: // example-conf + datum_gateway_example_conf(); + exit(0); + break; default: return ARGP_ERR_UNKNOWN; } @@ -100,6 +106,14 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) { static struct argp argp = {options, parse_opt, args_doc, doc}; // END ARGP Stuff +void datum_print_banner(void) { + printf("\n **************************************************************************\n"); + printf(" * DATUM Gateway --- Copyright (c) 2024 Bitcoin Ocean, LLC & Jason Hughes *\n"); + printf(" * git commit: %-58s *\n", GIT_COMMIT_HASH); + printf(" **************************************************************************\n\n"); + fflush(stdout); +} + void handle_sigusr1(int sig) { datum_blocktemplates_notifynew(NULL, 0); } @@ -119,12 +133,6 @@ int main(const int argc, const char * const * const argv) { bool rejecting_stratum = false; uint32_t next_reconnect_attempt_ms = 5000; - printf("\n **************************************************************************\n"); - printf(" * DATUM Gateway --- Copyright (c) 2024 Bitcoin Ocean, LLC & Jason Hughes *\n"); - printf(" * git commit: %-58s *\n", GIT_COMMIT_HASH); - printf(" **************************************************************************\n\n"); - fflush(stdout); - // listen for block notifications // set this up early so a notification doesn't break our init sa.sa_handler = handle_sigusr1; @@ -132,6 +140,7 @@ int main(const int argc, const char * const * const argv) { sigemptyset(&sa.sa_mask); if (sigaction(SIGUSR1, &sa, NULL) == -1) { + datum_print_banner(); DLOG_FATAL("Could not setup signal handler!"); perror("sigaction"); usleep(100000); @@ -148,9 +157,11 @@ int main(const int argc, const char * const * const argv) { arguments.config_file = "datum_gateway_config.json"; // Default config file if (argp_parse(&argp, argc, datum_deepcopy_charpp(argv), 0, 0, &arguments) != 0) { + datum_print_banner(); DLOG_FATAL("Error parsing arguments. Check --help"); exit(1); } + datum_print_banner(); if (datum_read_config(arguments.config_file) != 1) { DLOG_FATAL("Error reading config file. Check --help"); diff --git a/src/datum_gateway.h b/src/datum_gateway.h index 64e0a14..0ab52e9 100644 --- a/src/datum_gateway.h +++ b/src/datum_gateway.h @@ -55,6 +55,8 @@ #define STRATUM_JOB_INDEX_XOR ((uint16_t)0xC0DE) +void datum_print_banner(void); + extern const char *datum_gateway_config_filename; extern const char * const *datum_argv;