Compare commits

...

1 Commits

Author SHA1 Message Date
sami7777 ae5e97ad6e Integrate Tor V3 onion identity into wallet startup, fix freeze
The wallet was freezing on "Verifying database integrity" because the
old Tor v2 startup code blocked on a mutex (wait_initialized) and
required an onion/hostname file that no longer existed after v2 removal.

Replace the blocking v2 startup with internal V3 onion identity:
- Every wallet now auto-generates Ed25519 keys and a V3 .onion address
- Keys are stored in wallet.dat (encrypted if wallet is encrypted)
- Onion identity is created after wallet loads (Step 8.5) so keys
  persist across restarts
- No external Tor process required for identity generation
- Writes onion/hostname and tor_data/ config for optional external Tor

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 12:35:51 -07:00
3 changed files with 73 additions and 53 deletions
+41 -26
View File
@@ -11,6 +11,7 @@
#include "ui_interface.h"
#include "checkpoints.h"
#include "smessage.h"
#include "tor/onion_v3.h"
#ifdef ENABLE_ZMQ
#include "zmqpublishnotifier.h"
#endif
@@ -152,6 +153,7 @@ void Shutdown(void* parg)
}
SecureMsgShutdown();
ShutdownTorV3();
#ifdef ENABLE_ZMQ
if (pzmqNotifier)
@@ -748,14 +750,8 @@ bool AppInit2()
}
// start up tor
if (!(mapArgs.count("-tor") && mapArgs["-tor"] != "0")) {
if (!NewThread(StartTor, NULL))
InitError(_("Error: could not start tor"));
}
wait_initialized();
// Release the old Tor initialization mutex (no longer blocking on embedded Tor)
set_initialized();
if (mapArgs.count("-externalip"))
{
@@ -765,25 +761,8 @@ bool AppInit2()
return InitError(strprintf(_("Cannot resolve -externalip address: '%s'"), strAddr.c_str()));
AddLocal(CService(strAddr, GetListenPort(), fNameLookup), LOCAL_MANUAL);
}
} else {
string automatic_onion;
fs::path const hostname_path = GetDataDir(
) / "onion" / "hostname";
if (
!fs::exists(
hostname_path
)
) {
return InitError(strprintf(_("No external address found. %s"), hostname_path.string().c_str()));
}
ifstream file(
hostname_path.string(
).c_str(
)
);
file >> automatic_onion;
AddLocal(CService(automatic_onion, GetListenPort(), fNameLookup), LOCAL_MANUAL);
}
// Tor V3 onion address is registered after wallet loads (Step 8.5)
if (mapArgs.count("-reservebalance")) // triangles: reserve balance amount
{
@@ -977,6 +956,42 @@ bool AppInit2()
printf(" rescan %15"PRId64"ms\n", GetTimeMillis() - nStart);
}
// ********************************************************* Step 8.5: initialize Tor V3 identity
{
uiInterface.InitMessage(_("Initializing Tor V3 identity..."));
printf("Initializing Tor V3 onion identity...\n");
// Tor V3 identity is innate to Triangles — always enabled
LoadTorV3Config();
TorV3Config& torConfig = GetTorV3Config();
torConfig.enableTor = true;
torConfig.enableHiddenService = true;
torConfig.hiddenServicePort = GetListenPort();
torConfig.torDataDirectory = (GetDataDir() / "tor_data").string();
if (InitTorV3()) {
string onionAddr = CTorV3Manager::GetInstance()->GetWalletOnionAddress();
if (!onionAddr.empty()) {
// Write onion/hostname for compatibility with existing code paths
fs::path onionDir = GetDataDir() / "onion";
fs::create_directories(onionDir);
ofstream hostnameFile((onionDir / "hostname").string().c_str());
if (hostnameFile.is_open()) {
hostnameFile << onionAddr << endl;
hostnameFile.close();
}
// Register onion address as local address for peer discovery
AddLocal(CService(onionAddr, GetListenPort(), fNameLookup), LOCAL_MANUAL);
printf("Tor V3 identity: %s\n", onionAddr.c_str());
} else {
printf("WARNING: Tor V3 initialized but no onion address available\n");
}
} else {
printf("WARNING: Failed to initialize Tor V3 identity\n");
}
}
// ********************************************************* Step 9: import blocks
if (mapArgs.count("-loadblock"))
+28 -23
View File
@@ -507,32 +507,34 @@ bool CTorV3Service::StartOnionService()
printf("ERROR: No onion address generated\n");
return false;
}
// Use data directory for Tor service files
boost::filesystem::path serviceDir = GetDataDir() / "tor_data" / "triangles_v3";
boost::filesystem::create_directories(serviceDir);
// Create Tor configuration for hidden service
std::string torrcContent = strprintf(
"HiddenServiceDir tor_data/triangles_v3/\n"
"HiddenServiceDir %s\n"
"HiddenServiceVersion 3\n"
"HiddenServicePort %d 127.0.0.1:%d\n",
port, port
serviceDir.string().c_str(), port, port
);
// Write torrc file
boost::filesystem::create_directories("tor_data/triangles_v3");
std::ofstream torrcFile("tor_data/triangles_v3/torrc");
std::ofstream torrcFile((serviceDir / "torrc").string().c_str());
if (torrcFile.is_open()) {
torrcFile << torrcContent;
torrcFile.close();
}
// Write private key
std::ofstream keyFile("tor_data/triangles_v3/hs_ed25519_secret_key");
std::ofstream keyFile((serviceDir / "hs_ed25519_secret_key").string().c_str());
if (keyFile.is_open()) {
keyFile << "== ed25519v1-secret: type0 ==\n";
keyFile << privateKey << "\n";
keyFile.close();
}
isActive = true;
printf("Started V3 onion service on %s:%d\n", onionAddress.c_str(), port);
return true;
@@ -1097,7 +1099,7 @@ CTorV3Manager* CTorV3Manager::GetInstance()
CTorV3Manager::CTorV3Manager() : torEnabled(false), torDataDir("tor_data")
{
LoadTorV3Config();
// Config is loaded via LoadTorV3Config() before InitTorV3() is called
}
CTorV3Manager::~CTorV3Manager()
@@ -1108,16 +1110,19 @@ CTorV3Manager::~CTorV3Manager()
bool CTorV3Manager::InitializeTor()
{
printf("Initializing Tor V3 support...\n");
// Use configured data directory (set by init.cpp to GetDataDir()/tor_data)
torDataDir = torV3Config.torDataDirectory;
// Create tor data directory
boost::filesystem::create_directories(torDataDir);
torEnabled = true;
if (torV3Config.enableHiddenService) {
return CreateWalletHiddenService(torV3Config.hiddenServicePort);
}
return true;
}
@@ -1962,21 +1967,21 @@ void CTorV3Manager::UpdateDiscoveryStats(int connected, int attempted)
// Load Tor V3 configuration
bool LoadTorV3Config()
{
// Set default values
torV3Config.enableTor = GetBoolArg("-tor", false);
torV3Config.enableHiddenService = GetBoolArg("-torhiddenservice", false);
// Tor V3 identity is innate to Triangles — enabled by default
torV3Config.enableTor = GetBoolArg("-tor", true);
torV3Config.enableHiddenService = GetBoolArg("-torhiddenservice", true);
torV3Config.enableSeederMode = GetBoolArg("-torseeder", false);
torV3Config.hiddenServicePort = GetArg("-torhiddenserviceport", 19112);
torV3Config.torDataDirectory = GetArg("-tordatadir", "tor_data");
torV3Config.hiddenServicePort = GetArg("-torhiddenserviceport", GetDefaultPort());
torV3Config.torDataDirectory = GetArg("-tordatadir", (GetDataDir() / "tor_data").string());
torV3Config.socksProxy = GetArg("-torproxy", "127.0.0.1:9050");
torV3Config.maxConnections = GetArg("-tormaxconnections", 8);
printf("Loaded Tor V3 configuration: enabled=%s, hidden_service=%s, seeder=%s, proxy=%s\n",
torV3Config.enableTor ? "true" : "false",
torV3Config.enableHiddenService ? "true" : "false",
torV3Config.enableHiddenService ? "true" : "false",
torV3Config.enableSeederMode ? "true" : "false",
torV3Config.socksProxy.c_str());
return true;
}
+4 -4
View File
@@ -149,11 +149,11 @@ struct TorV3Config
int maxConnections;
std::vector<std::string> trustedOnionPeers;
TorV3Config() :
enableTor(false),
enableHiddenService(false),
TorV3Config() :
enableTor(true),
enableHiddenService(true),
enableSeederMode(false),
hiddenServicePort(19112),
hiddenServicePort(24112),
torDataDirectory("tor_data"),
socksProxy("127.0.0.1:9050"),
maxConnections(8) {}