ObsidianDragon - DragonX ImGui Wallet
Full-node GUI wallet for DragonX cryptocurrency. Built with Dear ImGui, SDL3, and OpenGL3/DX11. Features: - Send/receive shielded and transparent transactions - Autoshield with merged transaction display - Built-in CPU mining (xmrig) - Peer management and network monitoring - Wallet encryption with PIN lock - QR code generation for receive addresses - Transaction history with pagination - Console for direct RPC commands - Cross-platform (Linux, Windows)
This commit is contained in:
224
src/rpc/connection.cpp
Normal file
224
src/rpc/connection.cpp
Normal file
@@ -0,0 +1,224 @@
|
||||
// DragonX Wallet - ImGui Edition
|
||||
// Copyright 2024-2026 The Hush Developers
|
||||
// Released under the GPLv3
|
||||
|
||||
#include "connection.h"
|
||||
#include "../config/version.h"
|
||||
#include "../resources/embedded_resources.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <filesystem>
|
||||
|
||||
#include "../util/logger.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <shlobj.h>
|
||||
#else
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace dragonx {
|
||||
namespace rpc {
|
||||
|
||||
Connection::Connection() = default;
|
||||
Connection::~Connection() = default;
|
||||
|
||||
std::string Connection::getDefaultDataDir()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
char path[MAX_PATH];
|
||||
if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_APPDATA, NULL, 0, path))) {
|
||||
return std::string(path) + "\\Hush\\DRAGONX";
|
||||
}
|
||||
return "";
|
||||
#elif defined(__APPLE__)
|
||||
const char* home = getenv("HOME");
|
||||
if (!home) {
|
||||
struct passwd* pw = getpwuid(getuid());
|
||||
home = pw->pw_dir;
|
||||
}
|
||||
// Match SilentDragonX path: Library/Application Support/Hush/DRAGONX
|
||||
return std::string(home) + "/Library/Application Support/Hush/DRAGONX";
|
||||
#else
|
||||
const char* home = getenv("HOME");
|
||||
if (!home) {
|
||||
struct passwd* pw = getpwuid(getuid());
|
||||
home = pw->pw_dir;
|
||||
}
|
||||
return std::string(home) + "/.hush/DRAGONX";
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string Connection::getDefaultConfPath()
|
||||
{
|
||||
return getDefaultDataDir() + "/" + DRAGONX_CONF_FILENAME;
|
||||
}
|
||||
|
||||
std::string Connection::getSaplingParamsDir()
|
||||
{
|
||||
// Sapling params are now extracted alongside the daemon binaries
|
||||
// in <ObsidianDragonDir>/hush3/ — no longer in the legacy ZcashParams dir.
|
||||
return resources::getDaemonDirectory();
|
||||
}
|
||||
|
||||
bool Connection::verifySaplingParams()
|
||||
{
|
||||
std::string params_dir = getSaplingParamsDir();
|
||||
if (params_dir.empty()) {
|
||||
DEBUG_LOGF("verifySaplingParams: params dir is empty\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string spend_path = params_dir + "\\sapling-spend.params";
|
||||
std::string output_path = params_dir + "\\sapling-output.params";
|
||||
#else
|
||||
std::string spend_path = params_dir + "/sapling-spend.params";
|
||||
std::string output_path = params_dir + "/sapling-output.params";
|
||||
#endif
|
||||
|
||||
bool spend_exists = fs::exists(spend_path);
|
||||
bool output_exists = fs::exists(output_path);
|
||||
|
||||
DEBUG_LOGF("verifySaplingParams: dir=%s\n", params_dir.c_str());
|
||||
DEBUG_LOGF(" spend: %s -> %s\n", spend_path.c_str(), spend_exists ? "found" : "MISSING");
|
||||
DEBUG_LOGF(" output: %s -> %s\n", output_path.c_str(), output_exists ? "found" : "MISSING");
|
||||
|
||||
return spend_exists && output_exists;
|
||||
}
|
||||
|
||||
ConnectionConfig Connection::parseConfFile(const std::string& path)
|
||||
{
|
||||
ConnectionConfig config;
|
||||
|
||||
std::ifstream file(path);
|
||||
if (!file.is_open()) {
|
||||
return config;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
while (std::getline(file, line)) {
|
||||
// Skip empty lines and comments
|
||||
if (line.empty() || line[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Parse key=value
|
||||
size_t eq_pos = line.find('=');
|
||||
if (eq_pos == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string key = line.substr(0, eq_pos);
|
||||
std::string value = line.substr(eq_pos + 1);
|
||||
|
||||
// Trim whitespace
|
||||
while (!key.empty() && (key.back() == ' ' || key.back() == '\t')) {
|
||||
key.pop_back();
|
||||
}
|
||||
while (!value.empty() && (value[0] == ' ' || value[0] == '\t')) {
|
||||
value.erase(0, 1);
|
||||
}
|
||||
|
||||
// Map to config
|
||||
if (key == "rpcuser") {
|
||||
config.rpcuser = value;
|
||||
} else if (key == "rpcpassword") {
|
||||
config.rpcpassword = value;
|
||||
} else if (key == "rpcport") {
|
||||
config.port = value;
|
||||
} else if (key == "rpchost" || key == "rpcconnect") {
|
||||
config.host = value;
|
||||
} else if (key == "proxy") {
|
||||
config.proxy = value;
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
ConnectionConfig Connection::autoDetectConfig()
|
||||
{
|
||||
ConnectionConfig config;
|
||||
|
||||
// Ensure data directory exists
|
||||
std::string data_dir = getDefaultDataDir();
|
||||
if (!fs::exists(data_dir)) {
|
||||
DEBUG_LOGF("Creating data directory: %s\n", data_dir.c_str());
|
||||
fs::create_directories(data_dir);
|
||||
}
|
||||
|
||||
// Try to find DRAGONX.conf
|
||||
std::string conf_path = getDefaultConfPath();
|
||||
|
||||
if (fs::exists(conf_path)) {
|
||||
config = parseConfFile(conf_path);
|
||||
config.hush_dir = data_dir;
|
||||
} else {
|
||||
// Create a default config file
|
||||
if (createDefaultConfig(conf_path)) {
|
||||
config = parseConfFile(conf_path);
|
||||
config.hush_dir = data_dir;
|
||||
}
|
||||
}
|
||||
|
||||
// Set defaults for missing values
|
||||
if (config.host.empty()) {
|
||||
config.host = DRAGONX_DEFAULT_RPC_HOST;
|
||||
}
|
||||
if (config.port.empty()) {
|
||||
config.port = DRAGONX_DEFAULT_RPC_PORT;
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
bool Connection::createDefaultConfig(const std::string& path)
|
||||
{
|
||||
// Generate random rpcuser/rpcpassword
|
||||
auto generateRandomString = [](int length) -> std::string {
|
||||
const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
std::string result;
|
||||
result.reserve(length);
|
||||
|
||||
std::srand(static_cast<unsigned>(std::time(nullptr)));
|
||||
for (int i = 0; i < length; i++) {
|
||||
result += charset[std::rand() % (sizeof(charset) - 1)];
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
std::string rpcuser = generateRandomString(16);
|
||||
std::string rpcpassword = generateRandomString(32);
|
||||
|
||||
std::ofstream file(path);
|
||||
if (!file.is_open()) {
|
||||
DEBUG_LOGF("Failed to create config file: %s\n", path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
file << "# DragonX configuration file\n";
|
||||
file << "# Auto-generated by DragonX Wallet\n";
|
||||
file << "\n";
|
||||
file << "rpcuser=" << rpcuser << "\n";
|
||||
file << "rpcpassword=" << rpcpassword << "\n";
|
||||
file << "rpcport=" << DRAGONX_DEFAULT_RPC_PORT << "\n";
|
||||
file << "server=1\n";
|
||||
file << "txindex=1\n";
|
||||
file << "addnode=195.201.20.230\n";
|
||||
file << "addnode=195.201.137.219\n";
|
||||
|
||||
file.close();
|
||||
|
||||
DEBUG_LOGF("Created default config file: %s\n", path.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace rpc
|
||||
} // namespace dragonx
|
||||
Reference in New Issue
Block a user