Remove direct bitcoin calls from qt/bitcoin.cpp

This commit is contained in:
Russell Yanofsky 2017-04-17 13:55:43 -04:00 committed by John Newbery
parent ea73b84d2d
commit 71e0d90876
6 changed files with 215 additions and 47 deletions

View file

@ -104,6 +104,8 @@ BITCOIN_CORE_H = \
httpserver.h \ httpserver.h \
indirectmap.h \ indirectmap.h \
init.h \ init.h \
interface/handler.h \
interface/node.h \
key.h \ key.h \
key_io.h \ key_io.h \
keystore.h \ keystore.h \
@ -357,6 +359,8 @@ libbitcoin_util_a_SOURCES = \
compat/glibcxx_sanity.cpp \ compat/glibcxx_sanity.cpp \
compat/strnlen.cpp \ compat/strnlen.cpp \
fs.cpp \ fs.cpp \
interface/handler.cpp \
interface/node.cpp \
random.cpp \ random.cpp \
rpc/protocol.cpp \ rpc/protocol.cpp \
rpc/util.cpp \ rpc/util.cpp \

33
src/interface/handler.cpp Normal file
View file

@ -0,0 +1,33 @@
// Copyright (c) 2018 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 <interface/handler.h>
#include <util.h>
#include <boost/signals2/connection.hpp>
#include <memory>
#include <utility>
namespace interface {
namespace {
class HandlerImpl : public Handler
{
public:
HandlerImpl(boost::signals2::connection connection) : m_connection(std::move(connection)) {}
void disconnect() override { m_connection.disconnect(); }
boost::signals2::scoped_connection m_connection;
};
} // namespace
std::unique_ptr<Handler> MakeHandler(boost::signals2::connection connection)
{
return MakeUnique<HandlerImpl>(std::move(connection));
}
} // namespace interface

35
src/interface/handler.h Normal file
View file

@ -0,0 +1,35 @@
// Copyright (c) 2018 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_INTERFACE_HANDLER_H
#define BITCOIN_INTERFACE_HANDLER_H
#include <memory>
namespace boost {
namespace signals2 {
class connection;
} // namespace signals2
} // namespace boost
namespace interface {
//! Generic interface for managing an event handler or callback function
//! registered with another interface. Has a single disconnect method to cancel
//! the registration and prevent any future notifications.
class Handler
{
public:
virtual ~Handler() {}
//! Disconnect the handler.
virtual void disconnect() = 0;
};
//! Return handler wrapping a boost signal connection.
std::unique_ptr<Handler> MakeHandler(boost::signals2::connection connection);
} // namespace interface
#endif // BITCOIN_INTERFACE_HANDLER_H

53
src/interface/node.cpp Normal file
View file

@ -0,0 +1,53 @@
// Copyright (c) 2018 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 <interface/node.h>
#include <chainparams.h>
#include <init.h>
#include <interface/handler.h>
#include <scheduler.h>
#include <ui_interface.h>
#include <util.h>
#include <warnings.h>
#include <boost/thread/thread.hpp>
namespace interface {
namespace {
class NodeImpl : public Node
{
void parseParameters(int argc, const char* const argv[]) override
{
gArgs.ParseParameters(argc, argv);
}
void readConfigFile(const std::string& conf_path) override { gArgs.ReadConfigFile(conf_path); }
void selectParams(const std::string& network) override { SelectParams(network); }
void initLogging() override { InitLogging(); }
void initParameterInteraction() override { InitParameterInteraction(); }
std::string getWarnings(const std::string& type) override { return GetWarnings(type); }
bool baseInitialize() override
{
return AppInitBasicSetup() && AppInitParameterInteraction() && AppInitSanityChecks() &&
AppInitLockDataDirectory();
}
bool appInitMain() override { return AppInitMain(); }
void appShutdown() override
{
Interrupt();
Shutdown();
}
void startShutdown() override { StartShutdown(); }
std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) override
{
return MakeHandler(::uiInterface.InitMessage.connect(fn));
}
};
} // namespace
std::unique_ptr<Node> MakeNode() { return MakeUnique<NodeImpl>(); }
} // namespace interface

62
src/interface/node.h Normal file
View file

@ -0,0 +1,62 @@
// Copyright (c) 2018 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_INTERFACE_NODE_H
#define BITCOIN_INTERFACE_NODE_H
#include <functional>
#include <memory>
#include <string>
namespace interface {
class Handler;
//! Top-level interface for a bitcoin node (bitcoind process).
class Node
{
public:
virtual ~Node() {}
//! Set command line arguments.
virtual void parseParameters(int argc, const char* const argv[]) = 0;
//! Load settings from configuration file.
virtual void readConfigFile(const std::string& conf_path) = 0;
//! Choose network parameters.
virtual void selectParams(const std::string& network) = 0;
//! Init logging.
virtual void initLogging() = 0;
//! Init parameter interaction.
virtual void initParameterInteraction() = 0;
//! Get warnings.
virtual std::string getWarnings(const std::string& type) = 0;
//! Initialize app dependencies.
virtual bool baseInitialize() = 0;
//! Start node.
virtual bool appInitMain() = 0;
//! Stop node.
virtual void appShutdown() = 0;
//! Start shutdown.
virtual void startShutdown() = 0;
//! Register handler for init messages.
using InitMessageFn = std::function<void(const std::string& message)>;
virtual std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) = 0;
};
//! Return implementation of Node interface.
std::unique_ptr<Node> MakeNode();
} // namespace interface
#endif // BITCOIN_INTERFACE_NODE_H

View file

@ -27,6 +27,8 @@
#endif #endif
#include <init.h> #include <init.h>
#include <interface/handler.h>
#include <interface/node.h>
#include <rpc/server.h> #include <rpc/server.h>
#include <ui_interface.h> #include <ui_interface.h>
#include <uint256.h> #include <uint256.h>
@ -180,11 +182,7 @@ class BitcoinCore: public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit BitcoinCore(); explicit BitcoinCore(interface::Node& node);
/** Basic initialization, before starting initialization/shutdown thread.
* Return true on success.
*/
static bool baseInitialize();
public Q_SLOTS: public Q_SLOTS:
void initialize(); void initialize();
@ -196,9 +194,10 @@ Q_SIGNALS:
void runawayException(const QString &message); void runawayException(const QString &message);
private: private:
/// Pass fatal exception message to UI thread /// Pass fatal exception message to UI thread
void handleRunawayException(const std::exception *e); void handleRunawayException(const std::exception *e);
interface::Node& m_node;
}; };
/** Main Bitcoin application object */ /** Main Bitcoin application object */
@ -206,7 +205,7 @@ class BitcoinApplication: public QApplication
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit BitcoinApplication(int &argc, char **argv); explicit BitcoinApplication(interface::Node& node, int &argc, char **argv);
~BitcoinApplication(); ~BitcoinApplication();
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
@ -247,6 +246,7 @@ Q_SIGNALS:
private: private:
QThread *coreThread; QThread *coreThread;
interface::Node& m_node;
OptionsModel *optionsModel; OptionsModel *optionsModel;
ClientModel *clientModel; ClientModel *clientModel;
BitcoinGUI *window; BitcoinGUI *window;
@ -264,36 +264,15 @@ private:
#include <qt/bitcoin.moc> #include <qt/bitcoin.moc>
BitcoinCore::BitcoinCore(): BitcoinCore::BitcoinCore(interface::Node& node) :
QObject() QObject(), m_node(node)
{ {
} }
void BitcoinCore::handleRunawayException(const std::exception *e) void BitcoinCore::handleRunawayException(const std::exception *e)
{ {
PrintExceptionContinue(e, "Runaway exception"); PrintExceptionContinue(e, "Runaway exception");
Q_EMIT runawayException(QString::fromStdString(GetWarnings("gui"))); Q_EMIT runawayException(QString::fromStdString(m_node.getWarnings("gui")));
}
bool BitcoinCore::baseInitialize()
{
if (!AppInitBasicSetup())
{
return false;
}
if (!AppInitParameterInteraction())
{
return false;
}
if (!AppInitSanityChecks())
{
return false;
}
if (!AppInitLockDataDirectory())
{
return false;
}
return true;
} }
void BitcoinCore::initialize() void BitcoinCore::initialize()
@ -301,7 +280,7 @@ void BitcoinCore::initialize()
try try
{ {
qDebug() << __func__ << ": Running initialization in thread"; qDebug() << __func__ << ": Running initialization in thread";
bool rv = AppInitMain(); bool rv = m_node.appInitMain();
Q_EMIT initializeResult(rv); Q_EMIT initializeResult(rv);
} catch (const std::exception& e) { } catch (const std::exception& e) {
handleRunawayException(&e); handleRunawayException(&e);
@ -315,8 +294,7 @@ void BitcoinCore::shutdown()
try try
{ {
qDebug() << __func__ << ": Running Shutdown in thread"; qDebug() << __func__ << ": Running Shutdown in thread";
Interrupt(); m_node.appShutdown();
Shutdown();
qDebug() << __func__ << ": Shutdown finished"; qDebug() << __func__ << ": Shutdown finished";
Q_EMIT shutdownResult(); Q_EMIT shutdownResult();
} catch (const std::exception& e) { } catch (const std::exception& e) {
@ -326,9 +304,10 @@ void BitcoinCore::shutdown()
} }
} }
BitcoinApplication::BitcoinApplication(int &argc, char **argv): BitcoinApplication::BitcoinApplication(interface::Node& node, int &argc, char **argv):
QApplication(argc, argv), QApplication(argc, argv),
coreThread(0), coreThread(0),
m_node(node),
optionsModel(0), optionsModel(0),
clientModel(0), clientModel(0),
window(0), window(0),
@ -409,7 +388,7 @@ void BitcoinApplication::startThread()
if(coreThread) if(coreThread)
return; return;
coreThread = new QThread(this); coreThread = new QThread(this);
BitcoinCore *executor = new BitcoinCore(); BitcoinCore *executor = new BitcoinCore(m_node);
executor->moveToThread(coreThread); executor->moveToThread(coreThread);
/* communication to and from thread */ /* communication to and from thread */
@ -427,8 +406,8 @@ void BitcoinApplication::startThread()
void BitcoinApplication::parameterSetup() void BitcoinApplication::parameterSetup()
{ {
InitLogging(); m_node.initLogging();
InitParameterInteraction(); m_node.initParameterInteraction();
} }
void BitcoinApplication::requestInitialize() void BitcoinApplication::requestInitialize()
@ -461,7 +440,7 @@ void BitcoinApplication::requestShutdown()
delete clientModel; delete clientModel;
clientModel = 0; clientModel = 0;
StartShutdown(); m_node.startShutdown();
// Request shutdown from core thread // Request shutdown from core thread
Q_EMIT requestedShutdown(); Q_EMIT requestedShutdown();
@ -555,9 +534,11 @@ int main(int argc, char *argv[])
{ {
SetupEnvironment(); SetupEnvironment();
std::unique_ptr<interface::Node> node = interface::MakeNode();
/// 1. Parse command-line options. These take precedence over anything else. /// 1. Parse command-line options. These take precedence over anything else.
// Command-line options take precedence: // Command-line options take precedence:
gArgs.ParseParameters(argc, argv); node->parseParameters(argc, argv);
// Do not refer to data directory yet, this can be overridden by Intro::pickDataDirectory // Do not refer to data directory yet, this can be overridden by Intro::pickDataDirectory
@ -571,7 +552,7 @@ int main(int argc, char *argv[])
Q_INIT_RESOURCE(bitcoin); Q_INIT_RESOURCE(bitcoin);
Q_INIT_RESOURCE(bitcoin_locale); Q_INIT_RESOURCE(bitcoin_locale);
BitcoinApplication app(argc, argv); BitcoinApplication app(*node, argc, argv);
#if QT_VERSION > 0x050100 #if QT_VERSION > 0x050100
// Generate high-dpi pixmaps // Generate high-dpi pixmaps
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
@ -633,7 +614,7 @@ int main(int argc, char *argv[])
return EXIT_FAILURE; return EXIT_FAILURE;
} }
try { try {
gArgs.ReadConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)); node->readConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME));
} catch (const std::exception& e) { } catch (const std::exception& e) {
QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), QMessageBox::critical(0, QObject::tr(PACKAGE_NAME),
QObject::tr("Error: Cannot parse configuration file: %1. Only use key=value syntax.").arg(e.what())); QObject::tr("Error: Cannot parse configuration file: %1. Only use key=value syntax.").arg(e.what()));
@ -648,7 +629,7 @@ int main(int argc, char *argv[])
// Check for -testnet or -regtest parameter (Params() calls are only valid after this clause) // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
try { try {
SelectParams(ChainNameFromCommandLine()); node->selectParams(ChainNameFromCommandLine());
} catch(std::exception &e) { } catch(std::exception &e) {
QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), QObject::tr("Error: %1").arg(e.what())); QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), QObject::tr("Error: %1").arg(e.what()));
return EXIT_FAILURE; return EXIT_FAILURE;
@ -705,7 +686,7 @@ int main(int argc, char *argv[])
app.createOptionsModel(gArgs.GetBoolArg("-resetguisettings", false)); app.createOptionsModel(gArgs.GetBoolArg("-resetguisettings", false));
// Subscribe to global signals from core // Subscribe to global signals from core
uiInterface.InitMessage.connect(InitMessage); std::unique_ptr<interface::Handler> handler = node->handleInitMessage(InitMessage);
if (gArgs.GetBoolArg("-splash", DEFAULT_SPLASHSCREEN) && !gArgs.GetBoolArg("-min", false)) if (gArgs.GetBoolArg("-splash", DEFAULT_SPLASHSCREEN) && !gArgs.GetBoolArg("-min", false))
app.createSplashScreen(networkStyle.data()); app.createSplashScreen(networkStyle.data());
@ -717,7 +698,7 @@ int main(int argc, char *argv[])
// Perform base initialization before spinning up initialization/shutdown thread // Perform base initialization before spinning up initialization/shutdown thread
// This is acceptable because this function only contains steps that are quick to execute, // This is acceptable because this function only contains steps that are quick to execute,
// so the GUI thread won't be held up. // so the GUI thread won't be held up.
if (BitcoinCore::baseInitialize()) { if (node->baseInitialize()) {
app.requestInitialize(); app.requestInitialize();
#if defined(Q_OS_WIN) && QT_VERSION >= 0x050000 #if defined(Q_OS_WIN) && QT_VERSION >= 0x050000
WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely...").arg(QObject::tr(PACKAGE_NAME)), (HWND)app.getMainWinId()); WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely...").arg(QObject::tr(PACKAGE_NAME)), (HWND)app.getMainWinId());
@ -732,10 +713,10 @@ int main(int argc, char *argv[])
} }
} catch (const std::exception& e) { } catch (const std::exception& e) {
PrintExceptionContinue(&e, "Runaway exception"); PrintExceptionContinue(&e, "Runaway exception");
app.handleRunawayException(QString::fromStdString(GetWarnings("gui"))); app.handleRunawayException(QString::fromStdString(node->getWarnings("gui")));
} catch (...) { } catch (...) {
PrintExceptionContinue(nullptr, "Runaway exception"); PrintExceptionContinue(nullptr, "Runaway exception");
app.handleRunawayException(QString::fromStdString(GetWarnings("gui"))); app.handleRunawayException(QString::fromStdString(node->getWarnings("gui")));
} }
return rv; return rv;
} }