Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/pull/15935/head'
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanofsky committed Jun 4, 2020
2 parents 39afe5b + 6c6846c commit caa1e43
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 5 deletions.
3 changes: 2 additions & 1 deletion doc/files.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,15 @@ Subdirectory | File(s) | Description
`indexes/blockfilter/basic/` | `fltrNNNNN.dat`<sup>[\[2\]](#note2)</sup> | Blockfilter index filters for the basic filtertype; *optional*, used if `-blockfilterindex=basic`
`wallets/` | | [Contains wallets](#multi-wallet-environment); can be specified by `-walletdir` option; if `wallets/` subdirectory does not exist, a wallet resides in the data directory
`./` | `banlist.dat` | Stores the IPs/subnets of banned nodes
`./` | `bitcoin.conf` | Contains [configuration settings](bitcoin-conf.md) for `bitcoind` or `bitcoin-qt`; can be specified by `-conf` option
`./` | `bitcoin.conf` | User-defined [configuration settings](bitcoin-conf.md) for `bitcoind` or `bitcoin-qt`. File is read-only and must be created manually. Path can be specified by `-conf` option
`./` | `bitcoind.pid` | Stores the process ID (PID) of `bitcoind` or `bitcoin-qt` while running; created at start and deleted on shutdown; can be specified by `-pid` option
`./` | `debug.log` | Contains debug information and general logging generated by `bitcoind` or `bitcoin-qt`; can be specified by `-debuglogfile` option
`./` | `fee_estimates.dat` | Stores statistics used to estimate minimum transaction fees and priorities required for confirmation
`./` | `guisettings.ini.bak` | Backup of former [GUI settings](#gui-settings) after `-resetguisettings` option is used
`./` | `mempool.dat` | Dump of the mempool's transactions
`./` | `onion_private_key` | Cached Tor hidden service private key for `-listenonion` option
`./` | `peers.dat` | Peer IP address database (custom format)
`./` | `settings.json` | Read-write settings set though GUI or RPC interfaces, augmenting manual settings from bitcoin.conf. File is created automatically if read-write setting storage is not disabled with `-nosettings` option. Path can be specified with `-settings` option
`./` | `.cookie` | Session RPC authentication cookie; if used, created at start and deleted on shutdown; can be specified by `-rpccookiefile` option
`./` | `.lock` | Data directory lock file

Expand Down
5 changes: 5 additions & 0 deletions src/bitcoind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ static bool AppInit(int argc, char* argv[])
}
}

if (!gArgs.ReadSettingsFile()) {
InitError(strprintf(Untranslated("Error reading settings file\n")));
return false;
}

// -server defaults to true for bitcoind but not for the GUI so do this here
gArgs.SoftSetBoolArg("-server", true);
// Set this early so that parameter interactions go to console
Expand Down
3 changes: 2 additions & 1 deletion src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ void SetupServerArgs(NodeContext& node)
#endif
gArgs.AddArg("-blockreconstructionextratxn=<n>", strprintf("Extra transactions to keep in memory for compact block reconstructions (default: %u)", DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
gArgs.AddArg("-blocksonly", strprintf("Whether to reject transactions from network peers. Automatic broadcast and rebroadcast of any transactions from inbound peers is disabled, unless '-whitelistforcerelay' is '1', in which case whitelisted peers' transactions will be relayed. RPC transactions are not affected. (default: %u)", DEFAULT_BLOCKSONLY), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
gArgs.AddArg("-conf=<file>", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
gArgs.AddArg("-conf=<file>", strprintf("Specify path to read-only configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
gArgs.AddArg("-datadir=<dir>", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
gArgs.AddArg("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS);
gArgs.AddArg("-dbcache=<n>", strprintf("Maximum database cache size <n> MiB (%d to %d, default: %d). In addition, unused mempool memory is shared for this cache (see -maxmempool).", nMinDbCache, nMaxDbCache, nDefaultDbCache), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
Expand All @@ -416,6 +416,7 @@ void SetupServerArgs(NodeContext& node)
"(default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >=%u = automatically prune block files to stay under the specified target size in MiB)", MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
gArgs.AddArg("-reindex", "Rebuild chain state and block index from the blk*.dat files on disk", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
gArgs.AddArg("-reindex-chainstate", "Rebuild chain state from the currently indexed blocks. When in pruning mode or if blocks on disk might be corrupted, use full -reindex instead.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
gArgs.AddArg("-settings=<file>", strprintf("Specify path to read-write settings file for storage of persistent settings. Can be disabled with -nosettings. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_SETTINGS_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
#ifndef WIN32
gArgs.AddArg("-sysperms", "Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
#else
Expand Down
1 change: 1 addition & 0 deletions src/interfaces/node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class NodeImpl : public Node
bool softSetArg(const std::string& arg, const std::string& value) override { return gArgs.SoftSetArg(arg, value); }
bool softSetBoolArg(const std::string& arg, bool value) override { return gArgs.SoftSetBoolArg(arg, value); }
void selectParams(const std::string& network) override { SelectParams(network); }
bool readSettingsFile() override { return gArgs.ReadSettingsFile(); }
uint64_t getAssumedBlockchainSize() override { return Params().AssumedBlockchainSize(); }
uint64_t getAssumedChainStateSize() override { return Params().AssumedChainStateSize(); }
std::string getNetwork() override { return Params().NetworkIDString(); }
Expand Down
5 changes: 5 additions & 0 deletions src/interfaces/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ class Node
//! Choose network parameters.
virtual void selectParams(const std::string& network) = 0;

//! Load <datadir>/settings.json file with saved settings. This needs to be
//! called after selectParams() because the settings file is
//! network-specific.
virtual bool readSettingsFile() = 0;

//! Get the (assumed) blockchain size.
virtual uint64_t getAssumedBlockchainSize() = 0;

Expand Down
5 changes: 5 additions & 0 deletions src/qt/bitcoin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,11 @@ int GuiMain(int argc, char* argv[])
// Parse URIs on command line -- this can affect Params()
PaymentServer::ipcParseCommandLine(*node, argc, argv);
#endif
if (!node->readSettingsFile()) {
QMessageBox::critical(nullptr, QObject::tr(PACKAGE_NAME),
QObject::tr("Error: Cannot read settings file."));
return EXIT_FAILURE;
}

QScopedPointer<const NetworkStyle> networkStyle(NetworkStyle::instantiate(Params().NetworkIDString()));
assert(!networkStyle.isNull());
Expand Down
5 changes: 5 additions & 0 deletions src/util/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace {
enum class Source {
FORCED,
COMMAND_LINE,
RW_SETTINGS,
CONFIG_FILE_NETWORK_SECTION,
CONFIG_FILE_DEFAULT_SECTION
};
Expand All @@ -32,6 +33,10 @@ static void MergeSettings(const Settings& settings, const std::string& section,
if (auto* values = FindKey(settings.command_line_options, name)) {
fn(SettingsSpan(*values), Source::COMMAND_LINE);
}
// Merge in the read-write settings
if (const SettingsValue* value = FindKey(settings.rw_settings, name)) {
fn(SettingsSpan(*value), Source::RW_SETTINGS);
}
// Merge in the network-specific section of the config file
if (!section.empty()) {
if (auto* map = FindKey(settings.ro_config, section)) {
Expand Down
8 changes: 5 additions & 3 deletions src/util/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,21 @@ namespace util {
//! https://github.com/bitcoin/bitcoin/pull/15934/files#r337691812)
using SettingsValue = UniValue;

//! Stored bitcoin settings. This struct combines settings from the command line
//! and a read-only configuration file.
//! Stored bitcoin settings. This struct combines settings from the command line,
//! a read-only configuration file, and a read-write runtime settings file.
struct Settings {
//! Map of setting name to forced setting value.
std::map<std::string, SettingsValue> forced_settings;
//! Map of setting name to list of command line values.
std::map<std::string, std::vector<SettingsValue>> command_line_options;
//! Map of setting name to read-write file setting value.
std::map<std::string, SettingsValue> rw_settings;
//! Map of config section name and setting name to list of config file values.
std::map<std::string, std::map<std::string, std::vector<SettingsValue>>> ro_config;
};

//! Get settings value from combined sources: forced settings, command line
//! arguments and the read-only config file.
//! arguments, runtime read-write settings, and the read-only config file.
//!
//! @param ignore_default_section_config - ignore values in the default section
//! of the config file (part before any
Expand Down
81 changes: 81 additions & 0 deletions src/util/system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
const int64_t nStartupTime = GetTime();

const char * const BITCOIN_CONF_FILENAME = "bitcoin.conf";
const char * const BITCOIN_SETTINGS_FILENAME = "settings.json";

ArgsManager gArgs;

Expand Down Expand Up @@ -372,6 +373,86 @@ bool ArgsManager::IsArgSet(const std::string& strArg) const
return !GetSetting(strArg).isNull();
}

static bool GetSettingsPath(fs::path* filepath = nullptr, bool temp = false)
{
if (gArgs.IsArgNegated("-settings")) return false;
if (filepath) {
std::string settings = gArgs.GetArg("-settings", BITCOIN_SETTINGS_FILENAME);
*filepath = fs::absolute(temp ? settings + ".tmp" : settings, GetDataDir(/* net_specific= */ true));
}
return true;
}

bool ArgsManager::EnableSettingsFile()
{
return GetSettingsPath();
}

bool ArgsManager::ReadSettingsFile()
{
fsbridge::ifstream file;
fs::path filepath;
if (!GetSettingsPath(&filepath, /* temp= */ false)) return true;
file.open(filepath);
if (!file.is_open()) return true; // Ok for file not to exist.

util::SettingsValue in;
if (!in.read(std::string{std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()})) {
LogPrintf("Error: Unable to parse settings file %s\n", filepath.string());
return false;
}
if (file.fail()) {
LogPrintf("Error reading settings file %s\n", filepath.string());
return false;
}
file.close();

if (!in.isObject()) {
LogPrintf("Error: Settings file %s is not in expected key-value format.\n", filepath.string());
return false;
}

LOCK(cs_args);
m_settings.rw_settings.clear();
const std::vector<std::string>& keys = in.getKeys();
const std::vector<UniValue>& values = in.getValues();
for (size_t i = 0; i < keys.size(); ++i) {
m_settings.rw_settings.emplace(keys[i], values[i]);
}
return true;
}

bool ArgsManager::WriteSettingsFile() const
{
fs::path filepath, filepath_tmp;
if (!GetSettingsPath(&filepath, /* temp= */ false) || !GetSettingsPath(&filepath_tmp, /* temp= */ true)) {
throw std::logic_error("Attempt to write settings file when dynamic settings are disabled.");
}

util::SettingsValue out(util::SettingsValue::VOBJ);
{
LOCK(cs_args);
for (const auto& value : m_settings.rw_settings) {
out.__pushKV(value.first, value.second);
}
}

fsbridge::ofstream file;
file.open(filepath_tmp);
if (file.fail()) {
LogPrintf("Error: Unable to open settings file %s for writing\n", filepath_tmp.string());
return false;
}
file << out.write(/* prettyIndent= */ 1, /* indentLevel= */ 4) << std::endl;
file.close();

if (!RenameOver(filepath_tmp, filepath)) {
LogPrintf("Error: Unable to rename settings file %s to %s\n", filepath_tmp.string(), filepath.string());
return false;
}
return true;
}

bool ArgsManager::IsArgNegated(const std::string& strArg) const
{
return GetSetting(strArg).isFalse();
Expand Down
29 changes: 29 additions & 0 deletions src/util/system.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
int64_t GetStartupTime();

extern const char * const BITCOIN_CONF_FILENAME;
extern const char * const BITCOIN_SETTINGS_FILENAME;

void SetupEnvironment();
bool SetupNetworking();
Expand Down Expand Up @@ -333,6 +334,34 @@ class ArgsManager
*/
Optional<unsigned int> GetArgFlags(const std::string& name) const;

/**
* Return whether read-write settings are enabled. This is true unless
* bitcoin was configured with -nosettings to disable storing changed
* dynamic settings from the GUI or RPC methods.
*/
bool EnableSettingsFile();

/**
* Load <datadir>/settings.json file with saved settings. This needs to be
* called after SelectParams() because the settings file is network-specific.
*/
bool ReadSettingsFile();

/**
* Save <datadir>/settings.json file with persistent settings.
*/
bool WriteSettingsFile() const;

/**
* Access settings with lock held.
*/
template <typename Fn>
void LockSettings(Fn&& fn)
{
LOCK(cs_args);
fn(m_settings);
}

/**
* Log the config file options and the command line arguments,
* useful for troubleshooting.
Expand Down

0 comments on commit caa1e43

Please sign in to comment.