fix(daemon): let DRAGONX.conf dbcache override the pinned value

The wallet pins a -dbcache value on the daemon command line. A
command-line flag overrides the same key in DRAGONX.conf, so a user who
set their own dbcache in the conf never got it: the wallet's pin always
won.

- Before spawning, a normal start now reads DRAGONX.conf once and, if it
  sets dbcache, drops the wallet's own -dbcache pin from the arguments
  so the user's value takes effect. An isolated start keeps its own
  datadir and conf and is left alone.
- The conf is now read a single time for both this check and the
  existing rpcthreads check instead of twice.

Tests cover dropping the pin when the conf sets dbcache (in various
forms), and leaving the default arguments untouched when it is
commented out, empty, or sets something else.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-10-14 06:26:13 -05:00
co-authored by Claude Opus 4.8
parent a6b7b966b0
commit 614dfbbc5b
3 changed files with 45 additions and 5 deletions
+12 -5
View File
@@ -591,16 +591,23 @@ bool EmbeddedDaemon::start(const std::string& binary_path)
args.push_back("-maxconnections=" + std::to_string(max_connections_));
}
// The user's own DRAGONX.conf wins over our flags (a command-line flag would override it): read the
// conf once, for a normal start only (an isolated start has its own datadir + conf and keeps the pin).
std::string conf;
if (override_datadir_.empty()) {
std::ifstream in((fs::path(util::Platform::getDragonXDataDir()) / "DRAGONX.conf").string(), std::ios::binary);
if (in) conf.assign(std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>());
if (confSetsKey(conf, "dbcache")) {
DEBUG_LOGF("[INFO] DRAGONX.conf sets dbcache; not pinning -dbcache\n");
}
dropPinnedDbcacheIfConfSets(args, conf);
}
// More RPC workers for a node we launch: dragonxd's default 8 workers + 16-deep queue fill up with
// requests waiting behind a long cs_main holder (a witness rebuild), after which even "stop" is refused.
// The GUI itself no longer floods it; this is headroom for dragonx-cli and other clients — a delay,
// not a fix. Not for an isolated start, and DRAGONX.conf wins (a flag would override the user's own).
if (override_datadir_.empty()) {
std::string conf;
{
std::ifstream in((fs::path(util::Platform::getDragonXDataDir()) / "DRAGONX.conf").string(), std::ios::binary);
if (in) conf.assign(std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>());
}
if (!confSetsKey(conf, "rpcthreads")) args.push_back("-rpcthreads=16");
}
+13
View File
@@ -4,6 +4,7 @@
#pragma once
#include <algorithm>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
@@ -424,6 +425,18 @@ public:
return false;
}
/**
* Drop the wallet's own -dbcache= pin from `args` when the user's DRAGONX.conf sets dbcache (a
* command-line flag overrides the conf, so the user's own value must win). Pure; no logging.
*/
static void dropPinnedDbcacheIfConfSets(std::vector<std::string>& args, const std::string& conf)
{
if (!confSetsKey(conf, "dbcache")) return;
args.erase(std::remove_if(args.begin(), args.end(),
[](const std::string& a) { return a.rfind("-dbcache=", 0) == 0; }),
args.end());
}
/** Decision returned by evaluateDatadirLockGate(): whether start() may spawn now. */
struct StartLockGateDecision {
bool proceed = true; // false => bail before spawning
+20
View File
@@ -6859,6 +6859,25 @@ void testConfSetsKey()
EXPECT_FALSE(EmbeddedDaemon::confSetsKey("rpcworkqueue=64 # rpcthreads=4\n", "rpcthreads"));
}
// C97: a user dbcache= in DRAGONX.conf wins over the wallet's -dbcache pin; default argv is unchanged.
void testDropPinnedDbcache()
{
using dragonx::daemon::EmbeddedDaemon;
const std::vector<std::string> base{"-a", "-dbcache=450", "-b"};
auto run = [&](const std::string& conf) {
std::vector<std::string> v = base;
EmbeddedDaemon::dropPinnedDbcacheIfConfSets(v, conf);
return v;
};
const std::vector<std::string> dropped{"-a", "-b"};
EXPECT_TRUE(run("dbcache=1000") == dropped);
EXPECT_TRUE(run(" dbcache = 8\r\n") == dropped);
EXPECT_TRUE(run("rpcuser=x\ndbcache=2000\n") == dropped);
EXPECT_TRUE(run("#dbcache=1") == base);
EXPECT_TRUE(run("") == base);
EXPECT_TRUE(run("rpcuser=x") == base);
}
// S12: the ownership record names the node we launched, by pid AND start time, so a later session can
// recognise it after "Leave running" — and a reused pid, or a record from before a reboot, never matches.
void testOwnershipRecord()
@@ -18655,6 +18674,7 @@ int main()
testDatadirLockGate();
testDaemonProcessIdentity();
testConfSetsKey();
testDropPinnedDbcache();
testOwnershipRecord();
testDebugLogTailRules();
testNoteConsolidation();