conf: Add --example-conf option to print an example config file

This commit is contained in:
Luke Dashjr 2025-03-16 04:29:29 +00:00
parent 2666ff70b8
commit a1a1aaf181
No known key found for this signature in database
GPG Key ID: A291A2C45D0C504A
4 changed files with 95 additions and 7 deletions

View File

@ -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}");
}

View File

@ -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

View File

@ -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");

View File

@ -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;