From 54d0aefda22c579023599242d6e26c22ce6254d1 Mon Sep 17 00:00:00 2001 From: pasta Date: Tue, 3 Nov 2026 14:50:20 +0000 Subject: [PATCH] fix: stop creating an empty dash.conf while reading the configuration ReadConfigFiles() created an empty dash.conf when none existed. Since the bitcoin#20744 backport (v22) a failed creation returned false with no error, and creation always fails while the default data directory does not exist yet, because common::InitConfig() creates it only after reading the config. On a machine without one, a first dashd start and dash-cli calls have failed with "Error reading configuration file: " since v23 (bitcoin#27073), and dashd -version and -help since the bitcoin#27150 backport (a v24 regression). Drop the Dash-only branch so a missing default config is handled as in Bitcoin Core. dash-qt's "Open Configuration File" only opened an existing file, so make it create the file first, as upstream's openBitcoinConf() does. Co-authored-by: Konstantin Akimov Co-Authored-By: Claude Opus 5.5 --- doc/release-notes-8029.md | 4 ++++ src/qt/guiutil.cpp | 4 ++++ src/util/system.cpp | 7 ------- test/functional/feature_config_args.py | 22 ++++++++++++++++++++++ 4 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 doc/release-notes-8029.md diff --git a/doc/release-notes-8029.md b/doc/release-notes-8029.md new file mode 100644 index 000000000000..7a617b8d9a91 --- /dev/null +++ b/doc/release-notes-8029.md @@ -0,0 +1,4 @@ +Configuration +------------- + +- `dashd` no longer creates an empty `dash.conf` when none exists, matching Bitcoin Core. `dash-qt`'s "Open Configuration File" still creates it on demand. (#8029) diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index e97f7a3bc537..edfa4f5eeb40 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -599,6 +599,10 @@ void openConfigfile() { fs::path pathConfig = gArgs.GetConfigFilePath(); + /* Create the file */ + std::ofstream configFile{pathConfig, std::ios_base::app}; + configFile.close(); + /* Open dash.conf with the associated application */ if (fs::exists(pathConfig)) { // Workaround for macOS-specific behavior; see #15409. diff --git a/src/util/system.cpp b/src/util/system.cpp index 4ff205593ca5..9b246b63de3e 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -990,13 +990,6 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys) tfm::format(std::cerr, "warning: -includeconf cannot be used from included files; ignoring -includeconf=%s\n", conf_file_name); } } - } else { - // Create an empty dash.conf if it does not exist - std::ofstream configFile{conf_path, std::ios_base::app}; - if (!configFile.good()) - return false; - configFile.close(); - return true; // Nothing to read, so just return } // If datadir is changed in .conf file: diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py index c172e737b127..8cdb34d9596b 100755 --- a/test/functional/feature_config_args.py +++ b/test/functional/feature_config_args.py @@ -336,6 +336,27 @@ def test_ignored_conf(self): self.start_node(0, [f'-conf={node.datadir}/dash.conf']) self.stop_node(0) + def test_missing_default_datadir(self): + # Overriding the default datadir through the environment does not work on Windows + if sys.platform == "win32": + return + + self.log.info('Test -version, -help and a first start without a default data directory') + node = self.nodes[0] + node_args = node.args + node.args = [arg for arg in node.args if not arg.startswith("-datadir=")] + for name, extra_args in [("version", ["-version"]), ("help", ["-help"]), ("start", ["-regtest", "-listen=0", "-server=0"])]: + env, default_datadir = util.get_temp_default_datadir(pathlib.Path(self.options.tmpdir, "no_datadir", name)) + default_datadir.parent.mkdir(parents=True) + node.start(extra_args, env=env) + if name == "start": + debug_log = default_datadir / "regtest" / "debug.log" + self.wait_until(lambda: node.process.poll() is not None or (debug_log.exists() and "Done loading" in debug_log.read_text(encoding="utf-8"))) + assert node.process.poll() is None + node.process.terminate() + node.wait_until_stopped() + node.args = node_args + def test_ignored_default_conf(self): # Disable this test for windows currently because trying to override # the default datadir through the environment does not seem to work. @@ -394,6 +415,7 @@ def run_test(self): self.test_config_file_log() self.test_invalid_command_line_options() self.test_ignored_conf() + self.test_missing_default_datadir() self.test_ignored_default_conf() self.test_acceptstalefeeestimates_arg_support()