diff --git a/src/init.cpp b/src/init.cpp index a61b40c..0469de5 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -418,7 +418,7 @@ std::string HelpMessage() //" -proxy= " + _("Connect through socks proxy") + "\n" + //" -socks= " + _("Select the version of socks proxy to use (4-5, default: 5)") + "\n" + " -tor= " + _("Use proxy to reach tor hidden services (default: same as -proxy)") + "\n" - " -notor " + _("Disable Tor (WARNING: wallet will not start - Tor is required)") + "\n" + + " -notor " + _("Disable Tor - run in clearnet-only mode (no .onion connectivity)") + "\n" + " -torsocks= " + _("Set embedded or managed Tor SOCKS proxy port (default: 19099)") + "\n" + " -torhiddenservice " + _("Enable the managed Tor hidden service (default: 1)") + "\n" + " -torhsport= " + _("Set embedded or managed Tor hidden service port (default: wallet listen port)") + "\n" + @@ -1334,6 +1334,15 @@ bool AppInit2() #ifdef USE_UPNP fUseUPnP = false; #endif + } else if (GetBoolArg("-notor", false)) { + // -notor: user explicitly disabled Tor. Allow the daemon to start + // in clearnet-only mode (useful for diagnostics, benchmarking, and + // recovery). .onion connectivity will not be available. + printf("NOTICE: Tor disabled via -notor. Running in clearnet-only mode.\n"); + printf(" .onion connections will NOT be available.\n"); + SetReachable(NET_IPV4, true); + SetReachable(NET_IPV6, true); + SetReachable(NET_TOR, false); } else { std::string torError = CTorEmbedded::GetInstance()->GetStartupError(); if (torError.empty()) diff --git a/src/tor/tor_process.cpp b/src/tor/tor_process.cpp index 79960a4..ed6f0ff 100644 --- a/src/tor/tor_process.cpp +++ b/src/tor/tor_process.cpp @@ -259,10 +259,34 @@ bool CTorProcess::WriteTorrc() // SOCKS proxy for wallet connections torrc << "SocksPort " << socksPort << "\n"; - // Data directory for Tor state - fs::path torStateDir = dataPath / "state"; - fs::create_directories(torStateDir); - torrc << "DataDirectory " << torStateDir.string() << "\n"; + // Data directory for Tor state. + // Use the tor_data directory itself as DataDirectory so that Tor creates + // its internal 'state' FILE at /state. Older wallet builds + // erroneously created a subdirectory called 'state' and pointed + // DataDirectory at it; newer Tor versions (0.4.9+) reject that because + // they expect to write a plain file called 'state' inside DataDirectory. + // + // Recovery: if 'state' exists as a directory, move its contents up and + // remove it so that Tor can create its state file in the normal location. + { + fs::path badStateDir = dataPath / "state"; + if (fs::exists(badStateDir) && fs::is_directory(badStateDir)) { + // Migrate any files inside the bad 'state/' directory up to dataPath + try { + for (auto& entry : fs::directory_iterator(badStateDir)) { + fs::path dest = dataPath / entry.path().filename(); + if (!fs::exists(dest)) { + fs::rename(entry.path(), dest); + } + } + fs::remove(badStateDir); + printf("Auto-recovered: removed legacy 'state' directory from %s\n", dataPath.string().c_str()); + } catch (const fs::filesystem_error& e) { + printf("WARNING: Could not auto-recover tor_data/state directory: %s\n", e.what()); + } + } + } + torrc << "DataDirectory " << dataPath.string() << "\n"; // Persistent Tor log for post-mortem debugging on user machines. fs::path torLogPath = dataPath / "tor.log";