Skip to content

refactor: Make BitcoinCore class reusable #10

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/Makefile.qt.include
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ QT_MOC_CPP = \
qt/moc_askpassphrasedialog.cpp \
qt/moc_createwalletdialog.cpp \
qt/moc_bantablemodel.cpp \
qt/moc_bitcoin.cpp \
qt/moc_bitcoinaddressvalidator.cpp \
qt/moc_bitcoinamountfield.cpp \
qt/moc_bitcoin.cpp \
qt/moc_bitcoincore.cpp \
qt/moc_bitcoingui.cpp \
qt/moc_bitcoinunits.cpp \
qt/moc_clientmodel.cpp \
Expand Down Expand Up @@ -110,9 +111,10 @@ BITCOIN_QT_H = \
qt/addresstablemodel.h \
qt/askpassphrasedialog.h \
qt/bantablemodel.h \
qt/bitcoin.h \
qt/bitcoinaddressvalidator.h \
qt/bitcoinamountfield.h \
qt/bitcoin.h \
qt/bitcoincore.h \
qt/bitcoingui.h \
qt/bitcoinunits.h \
qt/clientmodel.h \
Expand Down Expand Up @@ -223,6 +225,7 @@ BITCOIN_QT_BASE_CPP = \
qt/bitcoin.cpp \
qt/bitcoinaddressvalidator.cpp \
qt/bitcoinamountfield.cpp \
qt/bitcoincore.cpp \
qt/bitcoingui.cpp \
qt/bitcoinunits.cpp \
qt/clientmodel.cpp \
Expand Down
98 changes: 19 additions & 79 deletions src/qt/bitcoin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,16 @@
#endif

#include <qt/bitcoin.h>
#include <qt/bitcoingui.h>

#include <chainparams.h>
#include <init.h>
#include <interfaces/handler.h>
#include <interfaces/node.h>
#include <node/context.h>
#include <node/ui_interface.h>
#include <noui.h>
#include <qt/bitcoincore.h>
#include <qt/bitcoingui.h>
#include <qt/clientmodel.h>
#include <qt/guiconstants.h>
#include <qt/guiutil.h>
Expand All @@ -20,25 +27,18 @@
#include <qt/splashscreen.h>
#include <qt/utilitydialog.h>
#include <qt/winshutdownmonitor.h>
#include <uint256.h>
#include <util/system.h>
#include <util/threadnames.h>
#include <util/translation.h>
#include <validation.h>

#ifdef ENABLE_WALLET
#include <qt/paymentserver.h>
#include <qt/walletcontroller.h>
#include <qt/walletmodel.h>
#endif // ENABLE_WALLET

#include <init.h>
#include <interfaces/handler.h>
#include <interfaces/node.h>
#include <node/context.h>
#include <node/ui_interface.h>
#include <noui.h>
#include <uint256.h>
#include <util/system.h>
#include <util/threadnames.h>
#include <util/translation.h>
#include <validation.h>

#include <boost/signals2/connection.hpp>
#include <memory>

Expand Down Expand Up @@ -155,54 +155,11 @@ void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, cons
}
}

BitcoinCore::BitcoinCore(interfaces::Node& node) :
QObject(), m_node(node)
{
}

void BitcoinCore::handleRunawayException(const std::exception *e)
{
PrintExceptionContinue(e, "Runaway exception");
Q_EMIT runawayException(QString::fromStdString(m_node.getWarnings().translated));
}

void BitcoinCore::initialize()
{
try
{
util::ThreadRename("qt-init");
qDebug() << __func__ << ": Running initialization in thread";
interfaces::BlockAndHeaderTipInfo tip_info;
bool rv = m_node.appInitMain(&tip_info);
Q_EMIT initializeResult(rv, tip_info);
} catch (const std::exception& e) {
handleRunawayException(&e);
} catch (...) {
handleRunawayException(nullptr);
}
}

void BitcoinCore::shutdown()
{
try
{
qDebug() << __func__ << ": Running Shutdown in thread";
m_node.appShutdown();
qDebug() << __func__ << ": Shutdown finished";
Q_EMIT shutdownResult();
} catch (const std::exception& e) {
handleRunawayException(&e);
} catch (...) {
handleRunawayException(nullptr);
}
}

static int qt_argc = 1;
static const char* qt_argv = "bitcoin-qt";

BitcoinApplication::BitcoinApplication():
QApplication(qt_argc, const_cast<char **>(&qt_argv)),
coreThread(nullptr),
optionsModel(nullptr),
clientModel(nullptr),
window(nullptr),
Expand Down Expand Up @@ -230,14 +187,6 @@ void BitcoinApplication::setupPlatformStyle()

BitcoinApplication::~BitcoinApplication()
{
if(coreThread)
{
qDebug() << __func__ << ": Stopping thread";
coreThread->quit();
coreThread->wait();
qDebug() << __func__ << ": Stopped thread";
}

delete window;
window = nullptr;
delete platformStyle;
Expand Down Expand Up @@ -291,22 +240,14 @@ bool BitcoinApplication::baseInitialize()

void BitcoinApplication::startThread()
{
if(coreThread)
return;
coreThread = new QThread(this);
BitcoinCore *executor = new BitcoinCore(node());
executor->moveToThread(coreThread);
m_core = std::make_unique<BitcoinCore>(node());

/* communication to and from thread */
connect(executor, &BitcoinCore::initializeResult, this, &BitcoinApplication::initializeResult);
connect(executor, &BitcoinCore::shutdownResult, this, &BitcoinApplication::shutdownResult);
connect(executor, &BitcoinCore::runawayException, this, &BitcoinApplication::handleRunawayException);
connect(this, &BitcoinApplication::requestedInitialize, executor, &BitcoinCore::initialize);
connect(this, &BitcoinApplication::requestedShutdown, executor, &BitcoinCore::shutdown);
/* make sure executor object is deleted in its own thread */
connect(coreThread, &QThread::finished, executor, &QObject::deleteLater);

coreThread->start();
connect(m_core.get(), &BitcoinCore::initializeResult, this, &BitcoinApplication::initializeResult);
connect(m_core.get(), &BitcoinCore::shutdownResult, this, &BitcoinApplication::shutdownResult);
connect(m_core.get(), &BitcoinCore::runawayException, this, &BitcoinApplication::handleRunawayException);
connect(this, &BitcoinApplication::requestedInitialize, m_core.get(), &BitcoinCore::initialize);
connect(this, &BitcoinApplication::requestedShutdown, m_core.get(), &BitcoinCore::shutdown);
}

void BitcoinApplication::parameterSetup()
Expand Down Expand Up @@ -339,7 +280,6 @@ void BitcoinApplication::requestShutdown()
shutdownWindow.reset(ShutdownWindow::showShutdownWindow(window));

qDebug() << __func__ << ": Requesting shutdown";
startThread();
window->hide();
// Must disconnect node signals otherwise current thread can deadlock since
// no event loop is running.
Expand Down
33 changes: 5 additions & 28 deletions src/qt/bitcoin.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
#include <config/bitcoin-config.h>
#endif

#include <QApplication>
#include <interfaces/node.h>
#include <qt/bitcoincore.h>

#include <assert.h>
#include <memory>

#include <interfaces/node.h>
#include <QApplication>

class BitcoinGUI;
class ClientModel;
Expand All @@ -26,31 +28,6 @@ class WalletController;
class WalletModel;


/** Class encapsulating Bitcoin Core startup and shutdown.
* Allows running startup and shutdown in a different thread from the UI thread.
*/
class BitcoinCore: public QObject
{
Q_OBJECT
public:
explicit BitcoinCore(interfaces::Node& node);

public Q_SLOTS:
void initialize();
void shutdown();

Q_SIGNALS:
void initializeResult(bool success, interfaces::BlockAndHeaderTipInfo tip_info);
void shutdownResult();
void runawayException(const QString &message);

private:
/// Pass fatal exception message to UI thread
void handleRunawayException(const std::exception *e);

interfaces::Node& m_node;
};

/** Main Bitcoin application object */
class BitcoinApplication: public QApplication
{
Expand Down Expand Up @@ -112,7 +89,7 @@ public Q_SLOTS:
void windowShown(BitcoinGUI* window);

private:
QThread *coreThread;
std::unique_ptr<BitcoinCore> m_core;
OptionsModel *optionsModel;
ClientModel *clientModel;
BitcoinGUI *window;
Expand Down
66 changes: 66 additions & 0 deletions src/qt/bitcoincore.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (c) 2014-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <qt/bitcoincore.h>

#include <interfaces/node.h>
#include <util/system.h>
#include <util/threadnames.h>

#include <exception>

#include <QDebug>
#include <QObject>
#include <QString>
#include <QThread>

BitcoinCore::BitcoinCore(interfaces::Node& node)
: QObject(), m_node(node)
{
this->moveToThread(&m_thread);
m_thread.start();
}

BitcoinCore::~BitcoinCore()
{
qDebug() << __func__ << ": Stopping thread";
m_thread.quit();
m_thread.wait();
qDebug() << __func__ << ": Stopped thread";
}

void BitcoinCore::handleRunawayException(const std::exception* e)
{
PrintExceptionContinue(e, "Runaway exception");
Q_EMIT runawayException(QString::fromStdString(m_node.getWarnings().translated));
}

void BitcoinCore::initialize()
{
try {
util::ThreadRename("qt-init");
qDebug() << __func__ << ": Running initialization in thread";
interfaces::BlockAndHeaderTipInfo tip_info;
bool rv = m_node.appInitMain(&tip_info);
Q_EMIT initializeResult(rv, tip_info);
} catch (const std::exception& e) {
handleRunawayException(&e);
} catch (...) {
handleRunawayException(nullptr);
}
}

void BitcoinCore::shutdown()
{
try {
qDebug() << __func__ << ": Running Shutdown in thread";
m_node.appShutdown();
qDebug() << __func__ << ": Shutdown finished";
Q_EMIT shutdownResult();
} catch (const std::exception& e) {
handleRunawayException(&e);
} catch (...) {
handleRunawayException(nullptr);
}
}
46 changes: 46 additions & 0 deletions src/qt/bitcoincore.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) 2014-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef BITCOIN_QT_BITCOINCORE_H
#define BITCOIN_QT_BITCOINCORE_H

#include <interfaces/node.h>

#include <exception>

#include <QObject>
#include <QThread>

QT_BEGIN_NAMESPACE
class QString;
QT_END_NAMESPACE

/** Class encapsulating Bitcoin Core startup and shutdown.
* Allows running startup and shutdown in a different thread from the UI thread.
*/
class BitcoinCore : public QObject
{
Q_OBJECT
public:
explicit BitcoinCore(interfaces::Node& node);
~BitcoinCore();

public Q_SLOTS:
void initialize();
void shutdown();

Q_SIGNALS:
void initializeResult(bool success, interfaces::BlockAndHeaderTipInfo tip_info);
void shutdownResult();
void runawayException(const QString& message);

private:
/// Pass fatal exception message to UI thread
void handleRunawayException(const std::exception* e);

interfaces::Node& m_node;
QThread m_thread;
};

#endif // BITCOIN_QT_BITCOINCORE_H
1 change: 1 addition & 0 deletions src/qt/test/test_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <interfaces/node.h>
#include <qt/bitcoin.h>
#include <qt/bitcoincore.h>
#include <qt/test/apptests.h>
#include <qt/test/rpcnestedtests.h>
#include <qt/test/uritests.h>
Expand Down