Hush full node GUI wallet
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

352 lines
10 KiB

// Copyright 2019-2022 The Hush developers
// Released under the GPLv3
#include <singleapplication.h>
#include "precompiled.h"
#include "mainwindow.h"
#include "rpc.h"
#include "settings.h"
#include "version.h"
bool isHSC = 1;
std::string HSC_name = "tumin";
std::string HSC_ticker = "tumin";
std::string HSC_default_theme = "dragonx";
std::string HSC_app_name = "silentdragontumin";
std::string HSC_TG_link = "dragonx.is/tg";
std::string HSC_website = "dragonx.is";
std::string HSC_explorer = "explorer.dragonx.is";
std::string App_title = "SilentDragon - Tumin";
std::string HSC_ac_name = "TUMIN";
// std::string HSC_port = "21769";
std::string HSC_port = "40855";
// std::string HSC_param = " -ac_name=" + HSC_ac_name + " -ac_algo=randomx -ac_halving=3500000 -ac_reward=300000000 -ac_blocktime=36 -ac_private=1 -addnode=176.126.87.241";
std::string HSC_param = " -ac_name=TUMIN -ac_algo=memhash -ac_halving=0 -ac_reward=1000000 -ac_supply=7000000 -ac_blocktime=200 -ac_private=1";
class SignalHandler
{
public:
SignalHandler(int mask = DEFAULT_SIGNALS);
virtual ~SignalHandler();
enum SIGNALS
{
SIG_UNHANDLED = 0, // Physical signal not supported by this class
SIG_NOOP = 1, // The application is requested to do a no-op (only a target that platform-specific signals map to when they can't be raised anyway)
SIG_INT = 2, // Control+C (should terminate but consider that it's a normal way to do so; can delay a bit)
SIG_TERM = 4, // Control+Break (should terminate now without regarding the consquences)
SIG_CLOSE = 8, // Container window closed (should perform normal termination, like Ctrl^C) [Windows only; on Linux it maps to SIG_TERM]
SIG_RELOAD = 16, // Reload the configuration [Linux only, physical signal is SIGHUP; on Windows it maps to SIG_NOOP]
DEFAULT_SIGNALS = SIG_INT | SIG_TERM | SIG_CLOSE,
};
static const int numSignals = 6;
virtual bool handleSignal(int signal) = 0;
private:
int _mask;
};
#include <assert.h>
#ifndef _WIN32
#include <signal.h>
#else
#endif //!_WIN32
// There can be only ONE SignalHandler per process
SignalHandler *g_handler(NULL);
#ifndef _WIN32
void POSIX_handleFunc(int);
int POSIX_physicalToLogical(int);
int POSIX_logicalToPhysical(int);
#endif //_WIN32
SignalHandler::SignalHandler(int mask) : _mask(mask)
{
assert(g_handler == NULL);
g_handler = this;
for (int i = 0; i < numSignals; i++)
{
int logical = 0x1 << i;
if (_mask & logical)
{
#ifndef _WIN32
int sig = POSIX_logicalToPhysical(logical);
bool failed = signal(sig, POSIX_handleFunc) == SIG_ERR;
assert(!failed);
(void)failed; // Silence the warning in non _DEBUG; TODO: something better
#endif //_WIN32
}
}
}
SignalHandler::~SignalHandler()
{
#ifndef _WIN32
for (int i = 0; i < numSignals; i++)
{
int logical = 0x1 << i;
if (_mask & logical)
{
signal(POSIX_logicalToPhysical(logical), SIG_DFL);
}
}
#endif //_WIN32
}
#ifndef _WIN32
int POSIX_logicalToPhysical(int signal)
{
switch (signal)
{
case SignalHandler::SIG_INT:
return SIGINT;
case SignalHandler::SIG_TERM:
return SIGTERM;
// In case the client asks for a SIG_CLOSE handler, accept and
// bind it to a SIGTERM. Anyway the signal will never be raised
case SignalHandler::SIG_CLOSE:
return SIGTERM;
case SignalHandler::SIG_RELOAD:
return SIGHUP;
default:
return -1; // SIG_ERR = -1
}
}
#endif //_WIN32
#ifndef _WIN32
int POSIX_physicalToLogical(int signal)
{
switch (signal)
{
case SIGINT:
return SignalHandler::SIG_INT;
case SIGTERM:
return SignalHandler::SIG_TERM;
case SIGHUP:
return SignalHandler::SIG_RELOAD;
default:
return SignalHandler::SIG_UNHANDLED;
}
}
#endif //_WIN32
#ifndef _WIN32
void POSIX_handleFunc(int signal)
{
if (g_handler)
{
int signo = POSIX_physicalToLogical(signal);
g_handler->handleSignal(signo);
}
}
#endif //_WIN32
class Application : public SignalHandler
{
public:
Application() : SignalHandler(SignalHandler::SIG_INT), w(nullptr) {}
~Application() {}
int main(int argc, char *argv[])
{
fprintf(stderr, "%s: argv0 = %s\n", __func__, argv[0]);
QString binaryName(argv[0]);
binaryName = binaryName.toLower();
QStringList pathParts = binaryName.split(QLatin1Char('/'));
qDebug() << pathParts;
std::string appname_exe = HSC_app_name + ".exe";
std::string appname_app = HSC_app_name + ".app";
isHSC = binaryName.endsWith(HSC_app_name.c_str()) || binaryName.endsWith((appname_exe.c_str())) || binaryName.endsWith((appname_app.c_str()));
qDebug() << "isHSC=" << isHSC;
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
SingleApplication a(argc, argv, true);
// Command line parser
QCommandLineParser parser;
parser.setApplicationDescription("Shielded desktop wallet and embedded full node for Hush");
parser.addHelpOption();
// A boolean option for running it headless
QCommandLineOption headlessOption(QStringList() << "headless", "Running it via GUI.");
parser.addOption(headlessOption);
// No embedded will disable the embedded hushd node
QCommandLineOption noembeddedOption(QStringList() << "no-embedded", "Disable embedded hushd");
parser.addOption(noembeddedOption);
// Positional argument will specify a Hush payment URI
parser.addPositionalArgument("hushURI", "An optional HUSH URI to pay");
parser.process(a);
// Check for a positional argument indicating a Hush payment URI
if (a.isSecondary())
{
if (parser.positionalArguments().length() > 0)
{
a.sendMessage(parser.positionalArguments()[0].toUtf8());
}
a.exit(0);
return 0;
}
QCoreApplication::setOrganizationName("Hush");
QCoreApplication::setApplicationName(isHSC ? App_title.c_str() : "SilentDragon");
QString locale = QLocale::system().name();
locale.truncate(locale.lastIndexOf('_')); // Get the language code
qDebug() << "Loading locale " << locale;
QTranslator translator;
if (isHSC)
{
translator.load(QString(":/translations/silentdragon_") + locale);
}
else
{
translator.load(QString(":/translations/silentdragon_") + locale);
}
a.installTranslator(&translator);
QIcon icon(":/icons/icon.ico");
QApplication::setWindowIcon(icon);
// TODO: update for SD
#ifdef Q_OS_LINUX
QFontDatabase::addApplicationFont(":/fonts/Ubuntu-R.ttf");
qApp->setFont(QFont("Ubuntu", 11, QFont::Normal, false));
#endif
// QRandomGenerator generates a secure random number, which we use to seed.
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
unsigned int seed = QRandomGenerator::securelySeeded().generate();
#else
// This will be used only during debugging for compatibility reasons
unsigned int seed = std::time(0);
#endif
std::srand(seed);
Settings::init();
// Set up libsodium
if (sodium_init() < 0)
{
/* panic! the library couldn't be initialized, it is not safe to use */
qDebug() << "libsodium is not initialized!";
exit(0);
}
// Check for embedded option
if (parser.isSet(noembeddedOption))
{
Settings::getInstance()->setUseEmbedded(false);
}
else
{
Settings::getInstance()->setUseEmbedded(true);
}
w = new MainWindow();
if (isHSC)
{
w->setWindowTitle((QString::fromStdString(App_title) + " v" + QString(APP_VERSION)));
}
else
{
w->setWindowTitle("SilentDragon v" + QString(APP_VERSION));
}
// If there was a payment URI on the command line, pay it
if (parser.positionalArguments().length() > 0)
{
w->payHushURI(parser.positionalArguments()[0]);
}
// Listen for any secondary instances telling us about a Hush payment URI
QObject::connect(&a, &SingleApplication::receivedMessage, [=](quint32, QByteArray msg)
{
QString uri(msg);
// We need to execute this async, otherwise the app seems to crash for some reason.
QTimer::singleShot(1, [=]() { w->payHushURI(uri); }); });
// For MacOS, we have an event filter
a.installEventFilter(w);
// Check if starting headless
if (parser.isSet(headlessOption))
{
Settings::getInstance()->setHeadless(true);
a.setQuitOnLastWindowClosed(false);
}
else
{
Settings::getInstance()->setHeadless(false);
w->show();
}
return QApplication::exec();
}
void DispatchToMainThread(std::function<void()> callback)
{
// any thread
QTimer *timer = new QTimer();
timer->moveToThread(qApp->thread());
timer->setSingleShot(true);
QObject::connect(timer, &QTimer::timeout, [=]()
{
// main thread
callback();
timer->deleteLater(); });
QMetaObject::invokeMethod(timer, "start", Qt::QueuedConnection, Q_ARG(int, 0));
}
bool handleSignal(int signal)
{
std::cout << std::endl
<< "Interrupted with signal " << signal << std::endl;
if (w && w->getRPC())
{
// Blocking call to closeEvent on the UI thread.
DispatchToMainThread([=]
{
w->doClose();
QApplication::quit(); });
}
else
{
QApplication::quit();
}
return true;
}
private:
MainWindow *w;
};
int main(int argc, char *argv[])
{
Application app;
return app.main(argc, argv);
}