diff options
Diffstat (limited to 'src')
50 files changed, 593 insertions, 393 deletions
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 445849e3d8..f4f84e2a99 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -120,6 +120,7 @@ QT_MOC_CPP = \ qt/moc_bantablemodel.cpp \ qt/moc_bitcoinaddressvalidator.cpp \ qt/moc_bitcoinamountfield.cpp \ + qt/moc_bitcoin.cpp \ qt/moc_bitcoingui.cpp \ qt/moc_bitcoinunits.cpp \ qt/moc_clientmodel.cpp \ @@ -166,7 +167,6 @@ BITCOIN_MM = \ qt/macos_appnap.mm QT_MOC = \ - qt/bitcoin.moc \ qt/bitcoinamountfield.moc \ qt/intro.moc \ qt/overviewpage.moc \ @@ -194,6 +194,7 @@ BITCOIN_QT_H = \ qt/bantablemodel.h \ qt/bitcoinaddressvalidator.h \ qt/bitcoinamountfield.h \ + qt/bitcoin.h \ qt/bitcoingui.h \ qt/bitcoinunits.h \ qt/clientmodel.h \ @@ -302,6 +303,7 @@ RES_ICONS = \ BITCOIN_QT_BASE_CPP = \ qt/bantablemodel.cpp \ + qt/bitcoin.cpp \ qt/bitcoinaddressvalidator.cpp \ qt/bitcoinamountfield.cpp \ qt/bitcoingui.cpp \ @@ -382,6 +384,9 @@ qt_libbitcoinqt_a_OBJCXXFLAGS = $(AM_OBJCXXFLAGS) $(QT_PIE_FLAGS) qt_libbitcoinqt_a_SOURCES = $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(QT_FORMS_UI) \ $(QT_QRC) $(QT_QRC_LOCALE) $(QT_TS) $(PROTOBUF_PROTO) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES) +if TARGET_DARWIN + qt_libbitcoinqt_a_SOURCES += $(BITCOIN_MM) +endif nodist_qt_libbitcoinqt_a_SOURCES = $(QT_MOC_CPP) $(QT_MOC) $(PROTOBUF_CC) \ $(PROTOBUF_H) $(QT_QRC_CPP) $(QT_QRC_LOCALE_CPP) @@ -404,10 +409,7 @@ qt_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDE $(QT_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS) qt_bitcoin_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS) -qt_bitcoin_qt_SOURCES = qt/bitcoin.cpp -if TARGET_DARWIN - qt_bitcoin_qt_SOURCES += $(BITCOIN_MM) -endif +qt_bitcoin_qt_SOURCES = qt/main.cpp if TARGET_WINDOWS qt_bitcoin_qt_SOURCES += $(BITCOIN_RC) endif diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index db7873e8b7..61977b50cd 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -6,6 +6,7 @@ bin_PROGRAMS += qt/test/test_bitcoin-qt TESTS += qt/test/test_bitcoin-qt TEST_QT_MOC_CPP = \ + qt/test/moc_apptests.cpp \ qt/test/moc_compattests.cpp \ qt/test/moc_rpcnestedtests.cpp \ qt/test/moc_uritests.cpp @@ -22,6 +23,7 @@ endif # ENABLE_WALLET TEST_QT_H = \ qt/test/addressbooktests.h \ + qt/test/apptests.h \ qt/test/compattests.h \ qt/test/rpcnestedtests.h \ qt/test/uritests.h \ @@ -40,6 +42,7 @@ qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_ $(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS) qt_test_test_bitcoin_qt_SOURCES = \ + qt/test/apptests.cpp \ qt/test/compattests.cpp \ qt/test/rpcnestedtests.cpp \ qt/test/test_main.cpp \ diff --git a/src/addrman.h b/src/addrman.h index af5a1d3b23..003bd059f8 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -23,33 +23,31 @@ */ class CAddrInfo : public CAddress { - - public: //! last try whatsoever by us (memory only) - int64_t nLastTry; + int64_t nLastTry{0}; //! last counted attempt (memory only) - int64_t nLastCountAttempt; + int64_t nLastCountAttempt{0}; private: //! where knowledge about this address first came from CNetAddr source; //! last successful connection by us - int64_t nLastSuccess; + int64_t nLastSuccess{0}; //! connection attempts since last successful attempt - int nAttempts; + int nAttempts{0}; //! reference count in new sets (memory only) - int nRefCount; + int nRefCount{0}; //! in tried set? (memory only) - bool fInTried; + bool fInTried{false}; //! position in vRandom - int nRandomPos; + int nRandomPos{-1}; friend class CAddrMan; @@ -65,25 +63,12 @@ public: READWRITE(nAttempts); } - void Init() - { - nLastSuccess = 0; - nLastTry = 0; - nLastCountAttempt = 0; - nAttempts = 0; - nRefCount = 0; - fInTried = false; - nRandomPos = -1; - } - CAddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource) { - Init(); } CAddrInfo() : CAddress(), source() { - Init(); } //! Calculate in which "tried" bucket this entry belongs @@ -106,7 +91,6 @@ public: //! Calculate the relative chance this entry should be given when selecting nodes to connect to double GetChance(int64_t nNow = GetAdjustedTime()) const; - }; /** Stochastic address manager diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 4ce1b53880..d334233224 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -272,10 +272,10 @@ public: strNetworkID = "regtest"; consensus.nSubsidyHalvingInterval = 150; consensus.BIP16Exception = uint256(); - consensus.BIP34Height = 100000000; // BIP34 has not activated on regtest (far in the future so block v1 are not rejected in tests) + consensus.BIP34Height = 500; // BIP34 activated on regtest (Used in functional tests) consensus.BIP34Hash = uint256(); - consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in rpc activation tests) - consensus.BIP66Height = 1251; // BIP66 activated on regtest (Used in rpc activation tests) + consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in functional tests) + consensus.BIP66Height = 1251; // BIP66 activated on regtest (Used in functional tests) consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks consensus.nPowTargetSpacing = 10 * 60; diff --git a/src/httpserver.cpp b/src/httpserver.cpp index cb8578927a..ca60ea43a7 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -124,7 +124,6 @@ public: struct HTTPPathHandler { - HTTPPathHandler() {} HTTPPathHandler(std::string _prefix, bool _exactMatch, HTTPRequestHandler _handler): prefix(_prefix), exactMatch(_exactMatch), handler(_handler) { diff --git a/src/index/base.cpp b/src/index/base.cpp index 4d4a7e1502..f6f59572ce 100644 --- a/src/index/base.cpp +++ b/src/index/base.cpp @@ -60,7 +60,11 @@ bool BaseIndex::Init() } LOCK(cs_main); - m_best_block_index = FindForkInGlobalIndex(chainActive, locator); + if (locator.IsNull()) { + m_best_block_index = nullptr; + } else { + m_best_block_index = FindForkInGlobalIndex(chainActive, locator); + } m_synced = m_best_block_index.load() == chainActive.Tip(); return true; } diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp index ba1c44765f..10bc8419dd 100644 --- a/src/index/txindex.cpp +++ b/src/index/txindex.cpp @@ -245,6 +245,9 @@ bool TxIndex::Init() bool TxIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex) { + // Exclude genesis block transaction because outputs are not spendable. + if (pindex->nHeight == 0) return true; + CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size())); std::vector<std::pair<uint256, CDiskTxPos>> vPos; vPos.reserve(block.vtx.size()); diff --git a/src/net.cpp b/src/net.cpp index a288c6e81e..03ee7af5e4 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -80,7 +80,7 @@ enum BindFlags { // The sleep time needs to be small to avoid new sockets stalling static const uint64_t SELECT_TIMEOUT_MILLISECONDS = 50; -const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*"; +const std::string NET_MESSAGE_COMMAND_OTHER = "*other*"; static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8] static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // SHA256("localhostnonce")[0:8] @@ -787,7 +787,6 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete nBytes -= handled; if (msg.complete()) { - //store received bytes per message command //to prevent a memory DOS, only allow valid commands mapMsgCmdSize::iterator i = mapRecvBytesPerMsgCmd.find(msg.hdr.pchCommand); @@ -2317,14 +2316,6 @@ void CConnman::SetNetworkActive(bool active) CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSeed1(nSeed1In) { - fNetworkActive = true; - setBannedIsDirty = false; - fAddressesInitialized = false; - nLastNodeId = 0; - nPrevNodeCount = 0; - nSendBufferMaxSize = 0; - nReceiveFloodSize = 0; - flagInterruptMsgProc = false; SetTryNewOutboundPeer(false); Options connOptions; @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -404,15 +404,15 @@ private: // whitelisted (as well as those connecting to whitelisted binds). std::vector<CSubNet> vWhitelistedRange; - unsigned int nSendBufferMaxSize; - unsigned int nReceiveFloodSize; + unsigned int nSendBufferMaxSize{0}; + unsigned int nReceiveFloodSize{0}; std::vector<ListenSocket> vhListenSocket; - std::atomic<bool> fNetworkActive; + std::atomic<bool> fNetworkActive{true}; banmap_t setBanned GUARDED_BY(cs_setBanned); CCriticalSection cs_setBanned; - bool setBannedIsDirty GUARDED_BY(cs_setBanned); - bool fAddressesInitialized; + bool setBannedIsDirty GUARDED_BY(cs_setBanned){false}; + bool fAddressesInitialized{false}; CAddrMan addrman; std::deque<std::string> vOneShots GUARDED_BY(cs_vOneShots); CCriticalSection cs_vOneShots; @@ -421,8 +421,8 @@ private: std::vector<CNode*> vNodes; std::list<CNode*> vNodesDisconnected; mutable CCriticalSection cs_vNodes; - std::atomic<NodeId> nLastNodeId; - unsigned int nPrevNodeCount; + std::atomic<NodeId> nLastNodeId{0}; + unsigned int nPrevNodeCount{0}; /** Services this instance offers */ ServiceFlags nLocalServices; @@ -446,7 +446,7 @@ private: std::condition_variable condMsgProc; Mutex mutexMsgProc; - std::atomic<bool> flagInterruptMsgProc; + std::atomic<bool> flagInterruptMsgProc{false}; CThreadInterrupt interruptNet; @@ -550,6 +550,8 @@ struct LocalServiceInfo { extern CCriticalSection cs_mapLocalHost; extern std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(cs_mapLocalHost); + +extern const std::string NET_MESSAGE_COMMAND_OTHER; typedef std::map<std::string, uint64_t> mapMsgCmdSize; //command, total bytes class CNodeStats @@ -696,8 +698,8 @@ public: const uint64_t nKeyedNetGroup; std::atomic_bool fPauseRecv; std::atomic_bool fPauseSend; -protected: +protected: mapMsgCmdSize mapSendBytesPerMsgCmd; mapMsgCmdSize mapRecvBytesPerMsgCmd GUARDED_BY(cs_vRecv); diff --git a/src/protocol.h b/src/protocol.h index 50d197415b..a790a06906 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -402,7 +402,6 @@ public: std::string GetCommand() const; std::string ToString() const; - // TODO: make private (improves encapsulation) public: int type; uint256 hash; diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp index dcfe3dcc57..713db595d5 100644 --- a/src/qt/bantablemodel.cpp +++ b/src/qt/bantablemodel.cpp @@ -40,8 +40,8 @@ class BanTablePriv public: /** Local cache of peer information */ QList<CCombinedBan> cachedBanlist; - /** Column to sort nodes by */ - int sortColumn; + /** Column to sort nodes by (default to unsorted) */ + int sortColumn{-1}; /** Order (ascending or descending) to sort nodes by */ Qt::SortOrder sortOrder; @@ -87,8 +87,6 @@ BanTableModel::BanTableModel(interfaces::Node& node, ClientModel *parent) : { columns << tr("IP/Netmask") << tr("Banned Until"); priv.reset(new BanTablePriv()); - // default to unsorted - priv->sortColumn = -1; // load initial data refresh(); diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index eaeb93a652..cf1bc6450e 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -6,6 +6,7 @@ #include <config/bitcoin-config.h> #endif +#include <qt/bitcoin.h> #include <qt/bitcoingui.h> #include <chainparams.h> @@ -71,11 +72,6 @@ Q_DECLARE_METATYPE(bool*) Q_DECLARE_METATYPE(CAmount) Q_DECLARE_METATYPE(uint256) -/** Translate string to current locale using Qt. */ -const std::function<std::string(const char*)> G_TRANSLATION_FUN = [](const char* psz) { - return QCoreApplication::translate("bitcoin-core", psz).toStdString(); -}; - static QString GetLangTerritory() { QSettings settings; @@ -140,101 +136,6 @@ void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, cons } } -/** 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); - 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 -{ - Q_OBJECT -public: - explicit BitcoinApplication(interfaces::Node& node, int &argc, char **argv); - ~BitcoinApplication(); - -#ifdef ENABLE_WALLET - /// Create payment server - void createPaymentServer(); -#endif - /// parameter interaction/setup based on rules - void parameterSetup(); - /// Create options model - void createOptionsModel(bool resetSettings); - /// Create main window - void createWindow(const NetworkStyle *networkStyle); - /// Create splash screen - void createSplashScreen(const NetworkStyle *networkStyle); - - /// Request core initialization - void requestInitialize(); - /// Request core shutdown - void requestShutdown(); - - /// Get process return value - int getReturnValue() const { return returnValue; } - - /// Get window identifier of QMainWindow (BitcoinGUI) - WId getMainWinId() const; - - /// Setup platform style - void setupPlatformStyle(); - -public Q_SLOTS: - void initializeResult(bool success); - void shutdownResult(); - /// Handle runaway exceptions. Shows a message box with the problem and quits the program. - void handleRunawayException(const QString &message); - void addWallet(WalletModel* walletModel); - void removeWallet(); - -Q_SIGNALS: - void requestedInitialize(); - void requestedShutdown(); - void stopThread(); - void splashFinished(); - -private: - QThread *coreThread; - interfaces::Node& m_node; - OptionsModel *optionsModel; - ClientModel *clientModel; - BitcoinGUI *window; - QTimer *pollShutdownTimer; -#ifdef ENABLE_WALLET - PaymentServer* paymentServer; - std::vector<WalletModel*> m_wallet_models; - std::unique_ptr<interfaces::Handler> m_handler_load_wallet; -#endif - int returnValue; - const PlatformStyle *platformStyle; - std::unique_ptr<QWidget> shutdownWindow; - - void startThread(); -}; - -#include <qt/bitcoin.moc> - BitcoinCore::BitcoinCore(interfaces::Node& node) : QObject(), m_node(node) { @@ -358,6 +259,11 @@ void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle) connect(this, &BitcoinApplication::requestedShutdown, splash, &QWidget::close); } +bool BitcoinApplication::baseInitialize() +{ + return m_node.baseInitialize(); +} + void BitcoinApplication::startThread() { if(coreThread) @@ -431,7 +337,7 @@ void BitcoinApplication::addWallet(WalletModel* walletModel) window->addWallet(walletModel); if (m_wallet_models.empty()) { - window->setCurrentWallet(walletModel->getWalletName()); + window->setCurrentWallet(walletModel); } #ifdef ENABLE_BIP70 @@ -467,7 +373,7 @@ void BitcoinApplication::initializeResult(bool success) #ifdef ENABLE_BIP70 PaymentServer::LoadRootCAs(); #endif - paymentServer->setOptionsModel(optionsModel); + if (paymentServer) paymentServer->setOptionsModel(optionsModel); #endif clientModel = new ClientModel(m_node, optionsModel); @@ -496,16 +402,19 @@ void BitcoinApplication::initializeResult(bool success) window->show(); } Q_EMIT splashFinished(); + Q_EMIT windowShown(window); #ifdef ENABLE_WALLET // Now that initialization/startup is done, process any command-line // bitcoin: URIs or payment requests: - connect(paymentServer, &PaymentServer::receivedPaymentRequest, window, &BitcoinGUI::handlePaymentRequest); - connect(window, &BitcoinGUI::receivedURI, paymentServer, &PaymentServer::handleURIOrFile); - connect(paymentServer, &PaymentServer::message, [this](const QString& title, const QString& message, unsigned int style) { - window->message(title, message, style); - }); - QTimer::singleShot(100, paymentServer, &PaymentServer::uiReady); + if (paymentServer) { + connect(paymentServer, &PaymentServer::receivedPaymentRequest, window, &BitcoinGUI::handlePaymentRequest); + connect(window, &BitcoinGUI::receivedURI, paymentServer, &PaymentServer::handleURIOrFile); + connect(paymentServer, &PaymentServer::message, [this](const QString& title, const QString& message, unsigned int style) { + window->message(title, message, style); + }); + QTimer::singleShot(100, paymentServer, &PaymentServer::uiReady); + } #endif pollShutdownTimer->start(200); } else { @@ -548,7 +457,7 @@ static void SetupUIArgs() } #ifndef BITCOIN_QT_TEST -int main(int argc, char *argv[]) +int GuiMain(int argc, char* argv[]) { #ifdef WIN32 util::WinCmdLineArgs winArgs; @@ -706,7 +615,7 @@ int main(int argc, char *argv[]) // Perform base initialization before spinning up initialization/shutdown thread // This is acceptable because this function only contains steps that are quick to execute, // so the GUI thread won't be held up. - if (node->baseInitialize()) { + if (app.baseInitialize()) { app.requestInitialize(); #if defined(Q_OS_WIN) WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely...").arg(QObject::tr(PACKAGE_NAME)), (HWND)app.getMainWinId()); diff --git a/src/qt/bitcoin.h b/src/qt/bitcoin.h new file mode 100644 index 0000000000..48b5907570 --- /dev/null +++ b/src/qt/bitcoin.h @@ -0,0 +1,127 @@ +// Copyright (c) 2011-2016 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_BITCOIN_H +#define BITCOIN_QT_BITCOIN_H + +#if defined(HAVE_CONFIG_H) +#include <config/bitcoin-config.h> +#endif + +#include <QApplication> +#include <memory> +#include <vector> + +class BitcoinGUI; +class ClientModel; +class NetworkStyle; +class OptionsModel; +class PaymentServer; +class PlatformStyle; +class WalletModel; + +namespace interfaces { +class Handler; +class Node; +} // namespace interfaces + +/** 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); + 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 +{ + Q_OBJECT +public: + explicit BitcoinApplication(interfaces::Node& node, int &argc, char **argv); + ~BitcoinApplication(); + +#ifdef ENABLE_WALLET + /// Create payment server + void createPaymentServer(); +#endif + /// parameter interaction/setup based on rules + void parameterSetup(); + /// Create options model + void createOptionsModel(bool resetSettings); + /// Create main window + void createWindow(const NetworkStyle *networkStyle); + /// Create splash screen + void createSplashScreen(const NetworkStyle *networkStyle); + /// Basic initialization, before starting initialization/shutdown thread. Return true on success. + bool baseInitialize(); + + /// Request core initialization + void requestInitialize(); + /// Request core shutdown + void requestShutdown(); + + /// Get process return value + int getReturnValue() const { return returnValue; } + + /// Get window identifier of QMainWindow (BitcoinGUI) + WId getMainWinId() const; + + /// Setup platform style + void setupPlatformStyle(); + +public Q_SLOTS: + void initializeResult(bool success); + void shutdownResult(); + /// Handle runaway exceptions. Shows a message box with the problem and quits the program. + void handleRunawayException(const QString &message); + void addWallet(WalletModel* walletModel); + void removeWallet(); + +Q_SIGNALS: + void requestedInitialize(); + void requestedShutdown(); + void stopThread(); + void splashFinished(); + void windowShown(BitcoinGUI* window); + +private: + QThread *coreThread; + interfaces::Node& m_node; + OptionsModel *optionsModel; + ClientModel *clientModel; + BitcoinGUI *window; + QTimer *pollShutdownTimer; +#ifdef ENABLE_WALLET + PaymentServer* paymentServer; + std::vector<WalletModel*> m_wallet_models; + std::unique_ptr<interfaces::Handler> m_handler_load_wallet; +#endif + int returnValue; + const PlatformStyle *platformStyle; + std::unique_ptr<QWidget> shutdownWindow; + + void startThread(); +}; + +int GuiMain(int argc, char* argv[]); + +#endif // BITCOIN_QT_BITCOIN_H diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 70255e058a..155f8efe7f 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -110,6 +110,7 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty * the central widget is the rpc console. */ setCentralWidget(rpcConsole); + Q_EMIT consoleShown(rpcConsole); } // Accept D&D of URIs @@ -324,6 +325,7 @@ void BitcoinGUI::createActions() openRPCConsoleAction->setStatusTip(tr("Open debugging and diagnostic console")); // initially disable the debug window menu item openRPCConsoleAction->setEnabled(false); + openRPCConsoleAction->setObjectName("openRPCConsoleAction"); usedSendingAddressesAction = new QAction(platformStyle->TextColorIcon(":/icons/address-book"), tr("&Sending addresses"), this); usedSendingAddressesAction->setStatusTip(tr("Show the list of used sending addresses and labels")); @@ -569,10 +571,9 @@ bool BitcoinGUI::addWallet(WalletModel *walletModel) { if(!walletFrame) return false; - const QString name = walletModel->getWalletName(); - QString display_name = name.isEmpty() ? "["+tr("default wallet")+"]" : name; + const QString display_name = walletModel->getDisplayName(); setWalletActionsEnabled(true); - m_wallet_selector->addItem(display_name, name); + m_wallet_selector->addItem(display_name, QVariant::fromValue(walletModel)); if (m_wallet_selector->count() == 2) { m_wallet_selector_label_action->setVisible(true); m_wallet_selector_action->setVisible(true); @@ -584,8 +585,7 @@ bool BitcoinGUI::addWallet(WalletModel *walletModel) bool BitcoinGUI::removeWallet(WalletModel* walletModel) { if (!walletFrame) return false; - QString name = walletModel->getWalletName(); - int index = m_wallet_selector->findData(name); + int index = m_wallet_selector->findData(QVariant::fromValue(walletModel)); m_wallet_selector->removeItem(index); if (m_wallet_selector->count() == 0) { setWalletActionsEnabled(false); @@ -594,20 +594,20 @@ bool BitcoinGUI::removeWallet(WalletModel* walletModel) m_wallet_selector_action->setVisible(false); } rpcConsole->removeWallet(walletModel); - return walletFrame->removeWallet(name); + return walletFrame->removeWallet(walletModel); } -bool BitcoinGUI::setCurrentWallet(const QString& name) +bool BitcoinGUI::setCurrentWallet(WalletModel* wallet_model) { if(!walletFrame) return false; - return walletFrame->setCurrentWallet(name); + return walletFrame->setCurrentWallet(wallet_model); } bool BitcoinGUI::setCurrentWalletBySelectorIndex(int index) { - QString internal_name = m_wallet_selector->itemData(index).toString(); - return setCurrentWallet(internal_name); + WalletModel* wallet_model = m_wallet_selector->itemData(index).value<WalletModel*>(); + return setCurrentWallet(wallet_model); } void BitcoinGUI::removeAllWallets() @@ -642,9 +642,11 @@ void BitcoinGUI::createTrayIcon(const NetworkStyle *networkStyle) assert(QSystemTrayIcon::isSystemTrayAvailable()); #ifndef Q_OS_MAC - trayIcon = new QSystemTrayIcon(networkStyle->getTrayAndWindowIcon(), this); - QString toolTip = tr("%1 client").arg(tr(PACKAGE_NAME)) + " " + networkStyle->getTitleAddText(); - trayIcon->setToolTip(toolTip); + if (QSystemTrayIcon::isSystemTrayAvailable()) { + trayIcon = new QSystemTrayIcon(networkStyle->getTrayAndWindowIcon(), this); + QString toolTip = tr("%1 client").arg(tr(PACKAGE_NAME)) + " " + networkStyle->getTitleAddText(); + trayIcon->setToolTip(toolTip); + } #endif } @@ -724,6 +726,7 @@ void BitcoinGUI::aboutClicked() void BitcoinGUI::showDebugWindow() { GUIUtil::bringToFront(rpcConsole); + Q_EMIT consoleShown(rpcConsole); } void BitcoinGUI::showDebugWindowActivateConsole() diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index aeff5dae30..e6c62d43bd 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -187,6 +187,8 @@ private: Q_SIGNALS: /** Signal raised when a URI was entered or dragged to the GUI */ void receivedURI(const QString &uri); + /** Signal raised when RPC console shown */ + void consoleShown(RPCConsole* console); public Q_SLOTS: /** Set number of connections shown in the UI */ @@ -206,7 +208,7 @@ public Q_SLOTS: void message(const QString &title, const QString &message, unsigned int style, bool *ret = nullptr); #ifdef ENABLE_WALLET - bool setCurrentWallet(const QString& name); + bool setCurrentWallet(WalletModel* wallet_model); bool setCurrentWalletBySelectorIndex(int index); /** Set the UI status indicators based on the currently selected wallet. */ diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui index 8f34e6bc82..507d195b72 100644 --- a/src/qt/forms/optionsdialog.ui +++ b/src/qt/forms/optionsdialog.ui @@ -714,7 +714,7 @@ <item> <widget class="QLabel" name="overriddenByCommandLineInfoLabel"> <property name="text"> - <string>Active command-line options that override above options:</string> + <string>Options set in this dialog are overridden by the command line or in the configuration file:</string> </property> <property name="textFormat"> <enum>Qt::PlainText</enum> diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h index 04b03a5435..4d6006c582 100644 --- a/src/qt/guiconstants.h +++ b/src/qt/guiconstants.h @@ -50,5 +50,6 @@ static const int MAX_URI_LENGTH = 255; #define QAPP_ORG_DOMAIN "bitcoin.org" #define QAPP_APP_NAME_DEFAULT "Bitcoin-Qt" #define QAPP_APP_NAME_TESTNET "Bitcoin-Qt-testnet" +#define QAPP_APP_NAME_REGTEST "Bitcoin-Qt-regtest" #endif // BITCOIN_QT_GUICONSTANTS_H diff --git a/src/qt/main.cpp b/src/qt/main.cpp new file mode 100644 index 0000000000..6a3c2249d1 --- /dev/null +++ b/src/qt/main.cpp @@ -0,0 +1,17 @@ +// 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 <qt/bitcoin.h> + +#include <QCoreApplication> + +#include <functional> +#include <string> + +/** Translate string to current locale using Qt. */ +extern const std::function<std::string(const char*)> G_TRANSLATION_FUN = [](const char* psz) { + return QCoreApplication::translate("bitcoin-core", psz).toStdString(); +}; + +int main(int argc, char* argv[]) { return GuiMain(argc, argv); } diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp index b134a139b0..da048d3211 100644 --- a/src/qt/networkstyle.cpp +++ b/src/qt/networkstyle.cpp @@ -17,7 +17,7 @@ static const struct { } network_styles[] = { {"main", QAPP_APP_NAME_DEFAULT, 0, 0, ""}, {"test", QAPP_APP_NAME_TESTNET, 70, 30, QT_TRANSLATE_NOOP("SplashScreen", "[testnet]")}, - {"regtest", QAPP_APP_NAME_TESTNET, 160, 30, "[regtest]"} + {"regtest", QAPP_APP_NAME_REGTEST, 160, 30, "[regtest]"} }; static const unsigned network_styles_count = sizeof(network_styles)/sizeof(*network_styles); diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp index 94505043dc..4b91c19761 100644 --- a/src/qt/notificator.cpp +++ b/src/qt/notificator.cpp @@ -39,7 +39,7 @@ Notificator::Notificator(const QString &_programName, QSystemTrayIcon *_trayIcon mode(None), trayIcon(_trayIcon) #ifdef USE_DBUS - ,interface(0) + ,interface(nullptr) #endif { if(_trayIcon && _trayIcon->supportsMessages()) @@ -154,14 +154,14 @@ QVariant FreedesktopImage::toVariant(const QImage &img) void Notificator::notifyDBus(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout) { - Q_UNUSED(cls); - // Arguments for DBus call: + // https://developer.gnome.org/notification-spec/ + // Arguments for DBus "Notify" call: QList<QVariant> args; // Program Name: args.append(programName); - // Unique ID of this notification type: + // Replaces ID; A value of 0 means that this notification won't replace any existing notifications: args.append(0U); // Application Icon, empty string @@ -209,9 +209,8 @@ void Notificator::notifyDBus(Class cls, const QString &title, const QString &tex } #endif -void Notificator::notifySystray(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout) +void Notificator::notifySystray(Class cls, const QString &title, const QString &text, int millisTimeout) { - Q_UNUSED(icon); QSystemTrayIcon::MessageIcon sicon = QSystemTrayIcon::NoIcon; switch(cls) // Set icon based on class { @@ -222,13 +221,12 @@ void Notificator::notifySystray(Class cls, const QString &title, const QString & trayIcon->showMessage(title, text, sicon, millisTimeout); } -// Based on Qt's tray icon implementation #ifdef Q_OS_MAC -void Notificator::notifyMacUserNotificationCenter(Class cls, const QString &title, const QString &text, const QIcon &icon) { +void Notificator::notifyMacUserNotificationCenter(const QString &title, const QString &text) +{ // icon is not supported by the user notification center yet. OSX will use the app icon. MacNotificationHandler::instance()->showNotification(title, text); } - #endif void Notificator::notify(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout) @@ -241,11 +239,11 @@ void Notificator::notify(Class cls, const QString &title, const QString &text, c break; #endif case QSystemTray: - notifySystray(cls, title, text, icon, millisTimeout); + notifySystray(cls, title, text, millisTimeout); break; #ifdef Q_OS_MAC case UserNotificationCenter: - notifyMacUserNotificationCenter(cls, title, text, icon); + notifyMacUserNotificationCenter(title, text); break; #endif default: diff --git a/src/qt/notificator.h b/src/qt/notificator.h index 10b7b6c50a..7d80b43e43 100644 --- a/src/qt/notificator.h +++ b/src/qt/notificator.h @@ -57,7 +57,7 @@ private: enum Mode { None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */ Freedesktop, /**< Use DBus org.freedesktop.Notifications */ - QSystemTray, /**< Use QSystemTray::showMessage */ + QSystemTray, /**< Use QSystemTrayIcon::showMessage() */ UserNotificationCenter /**< Use the 10.8+ User Notification Center (Mac only) */ }; QString programName; @@ -68,9 +68,9 @@ private: void notifyDBus(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout); #endif - void notifySystray(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout); + void notifySystray(Class cls, const QString &title, const QString &text, int millisTimeout); #ifdef Q_OS_MAC - void notifyMacUserNotificationCenter(Class cls, const QString &title, const QString &text, const QIcon &icon); + void notifyMacUserNotificationCenter(const QString &title, const QString &text); #endif }; diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index 8cfedca57f..e2e78fe81b 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -49,8 +49,8 @@ class PeerTablePriv public: /** Local cache of peer information */ QList<CNodeCombinedStats> cachedNodeStats; - /** Column to sort nodes by */ - int sortColumn; + /** Column to sort nodes by (default to unsorted) */ + int sortColumn{-1}; /** Order (ascending or descending) to sort nodes by */ Qt::SortOrder sortOrder; /** Index of rows by node ID */ @@ -108,8 +108,6 @@ PeerTableModel::PeerTableModel(interfaces::Node& node, ClientModel *parent) : { columns << tr("NodeId") << tr("Node/Service") << tr("Ping") << tr("Sent") << tr("Received") << tr("User Agent"); priv.reset(new PeerTablePriv()); - // default to unsorted - priv->sortColumn = -1; // set up timer for auto refresh timer = new QTimer(this); diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index 82ab48ac20..aa746017f3 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -15,8 +15,6 @@ RecentRequestsTableModel::RecentRequestsTableModel(WalletModel *parent) : QAbstractTableModel(parent), walletModel(parent) { - nReceiveRequestsMaxId = 0; - // Load entries from wallet std::vector<std::string> vReceiveRequests; parent->loadReceiveRequests(vReceiveRequests); diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h index ff2c0c8098..8a1140e952 100644 --- a/src/qt/recentrequeststablemodel.h +++ b/src/qt/recentrequeststablemodel.h @@ -94,7 +94,7 @@ private: WalletModel *walletModel; QStringList columns; QList<RecentRequestEntry> list; - int64_t nReceiveRequestsMaxId; + int64_t nReceiveRequestsMaxId{0}; /** Updates the column title to "Amount (DisplayUnit)" and emits headerDataChanged() signal for table headers to react. */ void updateAmountColumnTitle(); diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 774a0d78e7..a6187685a9 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -85,7 +85,7 @@ public: explicit RPCExecutor(interfaces::Node& node) : m_node(node) {} public Q_SLOTS: - void request(const QString &command, const QString &walletID); + void request(const QString &command, const WalletModel* wallet_model); Q_SIGNALS: void reply(int category, const QString &command); @@ -148,7 +148,7 @@ public: * @param[out] pstrFilteredOut Command line, filtered to remove any sensitive data */ -bool RPCConsole::RPCParseCommandLine(interfaces::Node* node, std::string &strResult, const std::string &strCommand, const bool fExecute, std::string * const pstrFilteredOut, const std::string *walletID) +bool RPCConsole::RPCParseCommandLine(interfaces::Node* node, std::string &strResult, const std::string &strCommand, const bool fExecute, std::string * const pstrFilteredOut, const WalletModel* wallet_model) { std::vector< std::vector<std::string> > stack; stack.push_back(std::vector<std::string>()); @@ -306,8 +306,8 @@ bool RPCConsole::RPCParseCommandLine(interfaces::Node* node, std::string &strRes std::string method = stack.back()[0]; std::string uri; #ifdef ENABLE_WALLET - if (walletID) { - QByteArray encodedName = QUrl::toPercentEncoding(QString::fromStdString(*walletID)); + if (wallet_model) { + QByteArray encodedName = QUrl::toPercentEncoding(wallet_model->getWalletName()); uri = "/wallet/"+std::string(encodedName.constData(), encodedName.length()); } #endif @@ -387,7 +387,7 @@ bool RPCConsole::RPCParseCommandLine(interfaces::Node* node, std::string &strRes } } -void RPCExecutor::request(const QString &command, const QString &walletID) +void RPCExecutor::request(const QString &command, const WalletModel* wallet_model) { try { @@ -418,9 +418,7 @@ void RPCExecutor::request(const QString &command, const QString &walletID) " example: getblock(getblockhash(0),true)[tx][0]\n\n"))); return; } - std::string wallet_id = walletID.toStdString(); - if (!RPCConsole::RPCExecuteCommandLine(m_node, result, executableCommand, nullptr, walletID.isNull() ? nullptr : &wallet_id)) - { + if (!RPCConsole::RPCExecuteCommandLine(m_node, result, executableCommand, nullptr, wallet_model)) { Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \"")); return; } @@ -698,10 +696,8 @@ void RPCConsole::setClientModel(ClientModel *model) #ifdef ENABLE_WALLET void RPCConsole::addWallet(WalletModel * const walletModel) { - const QString name = walletModel->getWalletName(); - // use name for text and internal data object (to allow to move to a wallet id later) - QString display_name = name.isEmpty() ? "["+tr("default wallet")+"]" : name; - ui->WalletSelector->addItem(display_name, name); + // use name for text and wallet model for internal data object (to allow to move to a wallet id later) + ui->WalletSelector->addItem(walletModel->getDisplayName(), QVariant::fromValue(walletModel)); if (ui->WalletSelector->count() == 2 && !isVisible()) { // First wallet added, set to default so long as the window isn't presently visible (and potentially in use) ui->WalletSelector->setCurrentIndex(1); @@ -714,8 +710,7 @@ void RPCConsole::addWallet(WalletModel * const walletModel) void RPCConsole::removeWallet(WalletModel * const walletModel) { - const QString name = walletModel->getWalletName(); - ui->WalletSelector->removeItem(ui->WalletSelector->findData(name)); + ui->WalletSelector->removeItem(ui->WalletSelector->findData(QVariant::fromValue(walletModel))); if (ui->WalletSelector->count() == 2) { ui->WalletSelector->setVisible(false); ui->WalletSelectorLabel->setVisible(false); @@ -910,25 +905,25 @@ void RPCConsole::on_lineEdit_returnPressed() cmdBeforeBrowsing = QString(); - QString walletID; + WalletModel* wallet_model{nullptr}; #ifdef ENABLE_WALLET const int wallet_index = ui->WalletSelector->currentIndex(); if (wallet_index > 0) { - walletID = (QString)ui->WalletSelector->itemData(wallet_index).value<QString>(); + wallet_model = ui->WalletSelector->itemData(wallet_index).value<WalletModel*>(); } - if (m_last_wallet_id != walletID) { - if (walletID.isNull()) { - message(CMD_REQUEST, tr("Executing command without any wallet")); + if (m_last_wallet_model != wallet_model) { + if (wallet_model) { + message(CMD_REQUEST, tr("Executing command using \"%1\" wallet").arg(wallet_model->getWalletName())); } else { - message(CMD_REQUEST, tr("Executing command using \"%1\" wallet").arg(walletID)); + message(CMD_REQUEST, tr("Executing command without any wallet")); } - m_last_wallet_id = walletID; + m_last_wallet_model = wallet_model; } #endif message(CMD_REQUEST, QString::fromStdString(strFilteredCmd)); - Q_EMIT cmdRequest(cmd, walletID); + Q_EMIT cmdRequest(cmd, m_last_wallet_model); cmd = QString::fromStdString(strFilteredCmd); diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 20dbf5ec95..6c000ba096 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -41,9 +41,9 @@ public: explicit RPCConsole(interfaces::Node& node, const PlatformStyle *platformStyle, QWidget *parent); ~RPCConsole(); - static bool RPCParseCommandLine(interfaces::Node* node, std::string &strResult, const std::string &strCommand, bool fExecute, std::string * const pstrFilteredOut = nullptr, const std::string *walletID = nullptr); - static bool RPCExecuteCommandLine(interfaces::Node& node, std::string &strResult, const std::string &strCommand, std::string * const pstrFilteredOut = nullptr, const std::string *walletID = nullptr) { - return RPCParseCommandLine(&node, strResult, strCommand, true, pstrFilteredOut, walletID); + static bool RPCParseCommandLine(interfaces::Node* node, std::string &strResult, const std::string &strCommand, bool fExecute, std::string * const pstrFilteredOut = nullptr, const WalletModel* wallet_model = nullptr); + static bool RPCExecuteCommandLine(interfaces::Node& node, std::string &strResult, const std::string &strCommand, std::string * const pstrFilteredOut = nullptr, const WalletModel* wallet_model = nullptr) { + return RPCParseCommandLine(&node, strResult, strCommand, true, pstrFilteredOut, wallet_model); } void setClientModel(ClientModel *model); @@ -133,7 +133,7 @@ public Q_SLOTS: Q_SIGNALS: // For RPC command executor void stopExecutor(); - void cmdRequest(const QString &command, const QString &walletID); + void cmdRequest(const QString &command, const WalletModel* wallet_model); private: void startExecutor(); @@ -165,7 +165,7 @@ private: int consoleFontSize = 0; QCompleter *autoCompleter = nullptr; QThread thread; - QString m_last_wallet_id; + WalletModel* m_last_wallet_model{nullptr}; /** Update UI with latest network info from model. */ void updateNetworkState(); diff --git a/src/qt/test/apptests.cpp b/src/qt/test/apptests.cpp new file mode 100644 index 0000000000..2c477a2e98 --- /dev/null +++ b/src/qt/test/apptests.cpp @@ -0,0 +1,117 @@ +// 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 <qt/test/apptests.h> + +#include <chainparams.h> +#include <init.h> +#include <qt/bitcoin.h> +#include <qt/bitcoingui.h> +#include <qt/networkstyle.h> +#include <qt/rpcconsole.h> +#include <shutdown.h> +#include <validation.h> + +#if defined(HAVE_CONFIG_H) +#include <config/bitcoin-config.h> +#endif +#ifdef ENABLE_WALLET +#include <wallet/db.h> +#endif + +#include <QAction> +#include <QEventLoop> +#include <QLineEdit> +#include <QScopedPointer> +#include <QTest> +#include <QTextEdit> +#include <QtGlobal> +#if QT_VERSION >= 0x050000 +#include <QtTest/QtTestWidgets> +#endif +#include <QtTest/QtTestGui> +#include <new> +#include <string> +#include <univalue.h> + +namespace { +//! Call getblockchaininfo RPC and check first field of JSON output. +void TestRpcCommand(RPCConsole* console) +{ + QEventLoop loop; + QTextEdit* messagesWidget = console->findChild<QTextEdit*>("messagesWidget"); + QObject::connect(messagesWidget, &QTextEdit::textChanged, &loop, &QEventLoop::quit); + QLineEdit* lineEdit = console->findChild<QLineEdit*>("lineEdit"); + QTest::keyClicks(lineEdit, "getblockchaininfo"); + QTest::keyClick(lineEdit, Qt::Key_Return); + loop.exec(); + QString output = messagesWidget->toPlainText(); + UniValue value; + value.read(output.right(output.size() - output.lastIndexOf(QChar::ObjectReplacementCharacter) - 1).toStdString()); + QCOMPARE(value["chain"].get_str(), std::string("regtest")); +} +} // namespace + +//! Entry point for BitcoinApplication tests. +void AppTests::appTests() +{ +#ifdef Q_OS_MAC + if (QApplication::platformName() == "minimal") { + // Disable for mac on "minimal" platform to avoid crashes inside the Qt + // framework when it tries to look up unimplemented cocoa functions, + // and fails to handle returned nulls + // (https://bugreports.qt.io/browse/QTBUG-49686). + QWARN("Skipping AppTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke " + "with 'test_bitcoin-qt -platform cocoa' on mac, or else use a linux or windows build."); + return; + } +#endif + + m_app.parameterSetup(); + m_app.createOptionsModel(true /* reset settings */); + QScopedPointer<const NetworkStyle> style( + NetworkStyle::instantiate(QString::fromStdString(Params().NetworkIDString()))); + m_app.setupPlatformStyle(); + m_app.createWindow(style.data()); + connect(&m_app, &BitcoinApplication::windowShown, this, &AppTests::guiTests); + expectCallback("guiTests"); + m_app.baseInitialize(); + m_app.requestInitialize(); + m_app.exec(); + m_app.requestShutdown(); + m_app.exec(); + + // Reset global state to avoid interfering with later tests. + AbortShutdown(); + UnloadBlockIndex(); +} + +//! Entry point for BitcoinGUI tests. +void AppTests::guiTests(BitcoinGUI* window) +{ + HandleCallback callback{"guiTests", *this}; + connect(window, &BitcoinGUI::consoleShown, this, &AppTests::consoleTests); + expectCallback("consoleTests"); + QAction* action = window->findChild<QAction*>("openRPCConsoleAction"); + action->activate(QAction::Trigger); +} + +//! Entry point for RPCConsole tests. +void AppTests::consoleTests(RPCConsole* console) +{ + HandleCallback callback{"consoleTests", *this}; + TestRpcCommand(console); +} + +//! Destructor to shut down after the last expected callback completes. +AppTests::HandleCallback::~HandleCallback() +{ + auto& callbacks = m_app_tests.m_callbacks; + auto it = callbacks.find(m_callback); + assert(it != callbacks.end()); + callbacks.erase(it); + if (callbacks.empty()) { + m_app_tests.m_app.quit(); + } +} diff --git a/src/qt/test/apptests.h b/src/qt/test/apptests.h new file mode 100644 index 0000000000..83bf56f1e4 --- /dev/null +++ b/src/qt/test/apptests.h @@ -0,0 +1,50 @@ +// 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_QT_TEST_APPTESTS_H +#define BITCOIN_QT_TEST_APPTESTS_H + +#include <QObject> +#include <set> +#include <string> +#include <utility> + +class BitcoinApplication; +class BitcoinGUI; +class RPCConsole; + +class AppTests : public QObject +{ + Q_OBJECT +public: + explicit AppTests(BitcoinApplication& app) : m_app(app) {} + +private Q_SLOTS: + void appTests(); + void guiTests(BitcoinGUI* window); + void consoleTests(RPCConsole* console); + +private: + //! Add expected callback name to list of pending callbacks. + void expectCallback(std::string callback) { m_callbacks.emplace(std::move(callback)); } + + //! RAII helper to remove no-longer-pending callback. + struct HandleCallback + { + std::string m_callback; + AppTests& m_app_tests; + ~HandleCallback(); + }; + + //! Bitcoin application. + BitcoinApplication& m_app; + + //! Set of pending callback names. Used to track expected callbacks and shut + //! down the app after the last callback has been handled and all tests have + //! either run or thrown exceptions. This could be a simple int counter + //! instead of a set of names, but the names might be useful for debugging. + std::multiset<std::string> m_callbacks; +}; + +#endif // BITCOIN_QT_TEST_APPTESTS_H diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp index ed453336da..173c814f1e 100644 --- a/src/qt/test/rpcnestedtests.cpp +++ b/src/qt/test/rpcnestedtests.cpp @@ -41,7 +41,7 @@ void RPCNestedTests::rpcNestedTests() TestingSetup test; - SetRPCWarmupFinished(); + if (RPCIsInWarmup(nullptr)) SetRPCWarmupFinished(); std::string result; std::string result2; diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index b6523604fd..a2bf53973b 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -7,6 +7,9 @@ #endif #include <chainparams.h> +#include <interfaces/node.h> +#include <qt/bitcoin.h> +#include <qt/test/apptests.h> #include <qt/test/rpcnestedtests.h> #include <util/system.h> #include <qt/test/uritests.h> @@ -47,12 +50,13 @@ int main(int argc, char *argv[]) { SetupEnvironment(); SetupNetworking(); - SelectParams(CBaseChainParams::MAIN); + SelectParams(CBaseChainParams::REGTEST); noui_connect(); ClearDatadirCache(); fs::path pathTemp = fs::temp_directory_path() / strprintf("test_bitcoin-qt_%lu_%i", (unsigned long)GetTime(), (int)GetRand(100000)); fs::create_directories(pathTemp); gArgs.ForceSetArg("-datadir", pathTemp.string()); + auto node = interfaces::MakeNode(); bool fInvalid = false; @@ -67,11 +71,15 @@ int main(int argc, char *argv[]) // Don't remove this, it's needed to access // QApplication:: and QCoreApplication:: in the tests - QApplication app(argc, argv); + BitcoinApplication app(*node, argc, argv); app.setApplicationName("Bitcoin-Qt-test"); SSL_library_init(); + AppTests app_tests(app); + if (QTest::qExec(&app_tests) != 0) { + fInvalid = true; + } URITests test1; if (QTest::qExec(&test1) != 0) { fInvalid = true; diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index d15bd95b8e..4f8b6d363e 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -46,8 +46,7 @@ bool WalletFrame::addWallet(WalletModel *walletModel) return false; } - const QString name = walletModel->getWalletName(); - if (mapWalletViews.count(name) > 0) { + if (mapWalletViews.count(walletModel) > 0) { return false; } @@ -65,7 +64,7 @@ bool WalletFrame::addWallet(WalletModel *walletModel) } walletStack->addWidget(walletView); - mapWalletViews[name] = walletView; + mapWalletViews[walletModel] = walletView; // Ensure a walletView is able to show the main window connect(walletView, &WalletView::showNormalIfMinimized, [this]{ @@ -77,24 +76,24 @@ bool WalletFrame::addWallet(WalletModel *walletModel) return true; } -bool WalletFrame::setCurrentWallet(const QString& name) +bool WalletFrame::setCurrentWallet(WalletModel* wallet_model) { - if (mapWalletViews.count(name) == 0) + if (mapWalletViews.count(wallet_model) == 0) return false; - WalletView *walletView = mapWalletViews.value(name); + WalletView *walletView = mapWalletViews.value(wallet_model); walletStack->setCurrentWidget(walletView); assert(walletView); walletView->updateEncryptionStatus(); return true; } -bool WalletFrame::removeWallet(const QString &name) +bool WalletFrame::removeWallet(WalletModel* wallet_model) { - if (mapWalletViews.count(name) == 0) + if (mapWalletViews.count(wallet_model) == 0) return false; - WalletView *walletView = mapWalletViews.take(name); + WalletView *walletView = mapWalletViews.take(wallet_model); walletStack->removeWidget(walletView); delete walletView; return true; @@ -102,7 +101,7 @@ bool WalletFrame::removeWallet(const QString &name) void WalletFrame::removeAllWallets() { - QMap<QString, WalletView*>::const_iterator i; + QMap<WalletModel*, WalletView*>::const_iterator i; for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) walletStack->removeWidget(i.value()); mapWalletViews.clear(); @@ -120,35 +119,35 @@ bool WalletFrame::handlePaymentRequest(const SendCoinsRecipient &recipient) void WalletFrame::showOutOfSyncWarning(bool fShow) { bOutOfSync = fShow; - QMap<QString, WalletView*>::const_iterator i; + QMap<WalletModel*, WalletView*>::const_iterator i; for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) i.value()->showOutOfSyncWarning(fShow); } void WalletFrame::gotoOverviewPage() { - QMap<QString, WalletView*>::const_iterator i; + QMap<WalletModel*, WalletView*>::const_iterator i; for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) i.value()->gotoOverviewPage(); } void WalletFrame::gotoHistoryPage() { - QMap<QString, WalletView*>::const_iterator i; + QMap<WalletModel*, WalletView*>::const_iterator i; for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) i.value()->gotoHistoryPage(); } void WalletFrame::gotoReceiveCoinsPage() { - QMap<QString, WalletView*>::const_iterator i; + QMap<WalletModel*, WalletView*>::const_iterator i; for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) i.value()->gotoReceiveCoinsPage(); } void WalletFrame::gotoSendCoinsPage(QString addr) { - QMap<QString, WalletView*>::const_iterator i; + QMap<WalletModel*, WalletView*>::const_iterator i; for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) i.value()->gotoSendCoinsPage(addr); } diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index 1963e89b24..9fbc8b4d52 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -37,8 +37,8 @@ public: void setClientModel(ClientModel *clientModel); bool addWallet(WalletModel *walletModel); - bool setCurrentWallet(const QString& name); - bool removeWallet(const QString &name); + bool setCurrentWallet(WalletModel* wallet_model); + bool removeWallet(WalletModel* wallet_model); void removeAllWallets(); bool handlePaymentRequest(const SendCoinsRecipient& recipient); @@ -53,7 +53,7 @@ private: QStackedWidget *walletStack; BitcoinGUI *gui; ClientModel *clientModel; - QMap<QString, WalletView*> mapWalletViews; + QMap<WalletModel*, WalletView*> mapWalletViews; bool bOutOfSync; diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index ba16fdd5e1..0a5b21f997 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -40,8 +40,6 @@ WalletModel::WalletModel(std::unique_ptr<interfaces::Wallet> wallet, interfaces: cachedNumBlocks(0) { fHaveWatchOnly = m_wallet->haveWatchOnly(); - fForceCheckBalanceChanged = false; - addressTableModel = new AddressTableModel(this); transactionTableModel = new TransactionTableModel(platformStyle, this); recentRequestsTableModel = new RecentRequestsTableModel(this); @@ -578,6 +576,12 @@ QString WalletModel::getWalletName() const return QString::fromStdString(m_wallet->getWalletName()); } +QString WalletModel::getDisplayName() const +{ + const QString name = getWalletName(); + return name.isEmpty() ? "["+tr("default wallet")+"]" : name; +} + bool WalletModel::isMultiwallet() { return m_node.getWallets().size() > 1; diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index ec4c5a2a6c..6a6c538157 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -219,6 +219,7 @@ public: interfaces::Wallet& wallet() const { return *m_wallet; } QString getWalletName() const; + QString getDisplayName() const; bool isMultiwallet(); @@ -234,7 +235,7 @@ private: interfaces::Node& m_node; bool fHaveWatchOnly; - bool fForceCheckBalanceChanged; + bool fForceCheckBalanceChanged{false}; // Wallet has an options model for wallet-specific options // (transaction fee, for example) diff --git a/src/rest.cpp b/src/rest.cpp index 4988e6ed26..4f26e3afb5 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -136,10 +136,12 @@ static bool rest_headers(HTTPRequest* req, if (!ParseHashStr(hashStr, hash)) return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr); + const CBlockIndex* tip = nullptr; std::vector<const CBlockIndex *> headers; headers.reserve(count); { LOCK(cs_main); + tip = chainActive.Tip(); const CBlockIndex* pindex = LookupBlockIndex(hash); while (pindex != nullptr && chainActive.Contains(pindex)) { headers.push_back(pindex); @@ -175,11 +177,8 @@ static bool rest_headers(HTTPRequest* req, } case RetFormat::JSON: { UniValue jsonHeaders(UniValue::VARR); - { - LOCK(cs_main); - for (const CBlockIndex *pindex : headers) { - jsonHeaders.push_back(blockheaderToJSON(pindex)); - } + for (const CBlockIndex *pindex : headers) { + jsonHeaders.push_back(blockheaderToJSON(tip, pindex)); } std::string strJSON = jsonHeaders.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); @@ -207,8 +206,10 @@ static bool rest_block(HTTPRequest* req, CBlock block; CBlockIndex* pblockindex = nullptr; + CBlockIndex* tip = nullptr; { LOCK(cs_main); + tip = chainActive.Tip(); pblockindex = LookupBlockIndex(hash); if (!pblockindex) { return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); @@ -241,11 +242,7 @@ static bool rest_block(HTTPRequest* req, } case RetFormat::JSON: { - UniValue objBlock; - { - LOCK(cs_main); - objBlock = blockToJSON(block, pblockindex, showTxDetails); - } + UniValue objBlock = blockToJSON(block, tip, pblockindex, showTxDetails); std::string strJSON = objBlock.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); req->WriteReply(HTTP_OK, strJSON); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index ec87f42c93..315f69d46b 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -59,10 +59,7 @@ static CUpdatedBlock latestblock; */ double GetDifficulty(const CBlockIndex* blockindex) { - if (blockindex == nullptr) - { - return 1.0; - } + assert(blockindex); int nShift = (blockindex->nBits >> 24) & 0xff; double dDiff = @@ -82,15 +79,22 @@ double GetDifficulty(const CBlockIndex* blockindex) return dDiff; } -UniValue blockheaderToJSON(const CBlockIndex* blockindex) +static int ComputeNextBlockAndDepth(const CBlockIndex* tip, const CBlockIndex* blockindex, const CBlockIndex*& next) +{ + next = tip->GetAncestor(blockindex->nHeight + 1); + if (next && next->pprev == blockindex) { + return tip->nHeight - blockindex->nHeight + 1; + } + next = nullptr; + return blockindex == tip ? 1 : -1; +} + +UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex) { - AssertLockHeld(cs_main); UniValue result(UniValue::VOBJ); result.pushKV("hash", blockindex->GetBlockHash().GetHex()); - int confirmations = -1; - // Only report confirmations if the block is on the main chain - if (chainActive.Contains(blockindex)) - confirmations = chainActive.Height() - blockindex->nHeight + 1; + const CBlockIndex* pnext; + int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext); result.pushKV("confirmations", confirmations); result.pushKV("height", blockindex->nHeight); result.pushKV("version", blockindex->nVersion); @@ -106,21 +110,17 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) if (blockindex->pprev) result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()); - CBlockIndex *pnext = chainActive.Next(blockindex); if (pnext) result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex()); return result; } -UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails) +UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails) { - AssertLockHeld(cs_main); UniValue result(UniValue::VOBJ); result.pushKV("hash", blockindex->GetBlockHash().GetHex()); - int confirmations = -1; - // Only report confirmations if the block is on the main chain - if (chainActive.Contains(blockindex)) - confirmations = chainActive.Height() - blockindex->nHeight + 1; + const CBlockIndex* pnext; + int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext); result.pushKV("confirmations", confirmations); result.pushKV("strippedsize", (int)::GetSerializeSize(block, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS)); result.pushKV("size", (int)::GetSerializeSize(block, PROTOCOL_VERSION)); @@ -152,7 +152,6 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx if (blockindex->pprev) result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()); - CBlockIndex *pnext = chainActive.Next(blockindex); if (pnext) result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex()); return result; @@ -748,15 +747,20 @@ static UniValue getblockheader(const JSONRPCRequest& request) + HelpExampleRpc("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") ); - LOCK(cs_main); - uint256 hash(ParseHashV(request.params[0], "hash")); bool fVerbose = true; if (!request.params[1].isNull()) fVerbose = request.params[1].get_bool(); - const CBlockIndex* pblockindex = LookupBlockIndex(hash); + const CBlockIndex* pblockindex; + const CBlockIndex* tip; + { + LOCK(cs_main); + pblockindex = LookupBlockIndex(hash); + tip = chainActive.Tip(); + } + if (!pblockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } @@ -769,7 +773,7 @@ static UniValue getblockheader(const JSONRPCRequest& request) return strHex; } - return blockheaderToJSON(pblockindex); + return blockheaderToJSON(tip, pblockindex); } static CBlock GetBlockChecked(const CBlockIndex* pblockindex) @@ -871,7 +875,7 @@ static UniValue getblock(const JSONRPCRequest& request) return strHex; } - return blockToJSON(block, pblockindex, verbosity >= 2); + return blockToJSON(block, chainActive.Tip(), pblockindex, verbosity >= 2); } struct CCoinsStats @@ -1150,7 +1154,7 @@ static UniValue verifychain(const JSONRPCRequest& request) } /** Implementation of IsSuperMajority with better feedback */ -static UniValue SoftForkMajorityDesc(int version, CBlockIndex* pindex, const Consensus::Params& consensusParams) +static UniValue SoftForkMajorityDesc(int version, const CBlockIndex* pindex, const Consensus::Params& consensusParams) { UniValue rv(UniValue::VOBJ); bool activated = false; @@ -1170,7 +1174,7 @@ static UniValue SoftForkMajorityDesc(int version, CBlockIndex* pindex, const Con return rv; } -static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex* pindex, const Consensus::Params& consensusParams) +static UniValue SoftForkDesc(const std::string &name, int version, const CBlockIndex* pindex, const Consensus::Params& consensusParams) { UniValue rv(UniValue::VOBJ); rv.pushKV("id", name); @@ -1277,20 +1281,21 @@ UniValue getblockchaininfo(const JSONRPCRequest& request) LOCK(cs_main); + const CBlockIndex* tip = chainActive.Tip(); UniValue obj(UniValue::VOBJ); obj.pushKV("chain", Params().NetworkIDString()); obj.pushKV("blocks", (int)chainActive.Height()); obj.pushKV("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1); - obj.pushKV("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex()); - obj.pushKV("difficulty", (double)GetDifficulty(chainActive.Tip())); - obj.pushKV("mediantime", (int64_t)chainActive.Tip()->GetMedianTimePast()); - obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), chainActive.Tip())); + obj.pushKV("bestblockhash", tip->GetBlockHash().GetHex()); + obj.pushKV("difficulty", (double)GetDifficulty(tip)); + obj.pushKV("mediantime", (int64_t)tip->GetMedianTimePast()); + obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip)); obj.pushKV("initialblockdownload", IsInitialBlockDownload()); - obj.pushKV("chainwork", chainActive.Tip()->nChainWork.GetHex()); + obj.pushKV("chainwork", tip->nChainWork.GetHex()); obj.pushKV("size_on_disk", CalculateCurrentUsage()); obj.pushKV("pruned", fPruneMode); if (fPruneMode) { - CBlockIndex* block = chainActive.Tip(); + const CBlockIndex* block = tip; assert(block); while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) { block = block->pprev; @@ -1307,7 +1312,6 @@ UniValue getblockchaininfo(const JSONRPCRequest& request) } const Consensus::Params& consensusParams = Params().GetConsensus(); - CBlockIndex* tip = chainActive.Tip(); UniValue softforks(UniValue::VARR); UniValue bip9_softforks(UniValue::VOBJ); softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams)); @@ -1565,7 +1569,7 @@ static UniValue reconsiderblock(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 1) throw std::runtime_error( RPCHelpMan{"reconsiderblock", - "\nRemoves invalidity status of a block and its descendants, reconsider them for activation.\n" + "\nRemoves invalidity status of a block, its ancestors and its descendants, reconsider them for activation.\n" "This can be used to undo the effects of invalidateblock.\n", { {"blockhash", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "the hash of the block to reconsider"}, diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h index add335eb8a..529132d033 100644 --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -27,7 +27,7 @@ double GetDifficulty(const CBlockIndex* blockindex); void RPCNotifyBlockChange(bool ibd, const CBlockIndex *); /** Block description to JSON */ -UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false); +UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails = false); /** Mempool information to JSON */ UniValue mempoolInfoToJSON(); @@ -36,7 +36,7 @@ UniValue mempoolInfoToJSON(); UniValue mempoolToJSON(bool fVerbose = false); /** Block header to JSON */ -UniValue blockheaderToJSON(const CBlockIndex* blockindex); +UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex); /** Used by getblockstats to get feerates at different percentiles by weight */ void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector<std::pair<CAmount, int64_t>>& scores, int64_t total_weight); diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 4d6b260cc7..cc229367ba 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -109,11 +109,15 @@ static UniValue getpeerinfo(const JSONRPCRequest& request) " \"whitelisted\": true|false, (boolean) Whether the peer is whitelisted\n" " \"minfeefilter\": n, (numeric) The minimum fee rate for transactions this peer accepts\n" " \"bytessent_per_msg\": {\n" - " \"addr\": n, (numeric) The total bytes sent aggregated by message type\n" + " \"msg\": n, (numeric) The total bytes sent aggregated by message type\n" + " When a message type is not listed in this json object, the bytes sent are 0.\n" + " Only known message types can appear as keys in the object.\n" " ...\n" " },\n" " \"bytesrecv_per_msg\": {\n" - " \"addr\": n, (numeric) The total bytes received aggregated by message type\n" + " \"msg\": n, (numeric) The total bytes received aggregated by message type\n" + " When a message type is not listed in this json object, the bytes received are 0.\n" + " Only known message types can appear as keys in the object and all bytes received of unknown message types are listed under '"+NET_MESSAGE_COMMAND_OTHER+"'.\n" " ...\n" " }\n" " }\n" @@ -178,14 +182,14 @@ static UniValue getpeerinfo(const JSONRPCRequest& request) obj.pushKV("minfeefilter", ValueFromAmount(stats.minFeeFilter)); UniValue sendPerMsgCmd(UniValue::VOBJ); - for (const mapMsgCmdSize::value_type &i : stats.mapSendBytesPerMsgCmd) { + for (const auto& i : stats.mapSendBytesPerMsgCmd) { if (i.second > 0) sendPerMsgCmd.pushKV(i.first, i.second); } obj.pushKV("bytessent_per_msg", sendPerMsgCmd); UniValue recvPerMsgCmd(UniValue::VOBJ); - for (const mapMsgCmdSize::value_type &i : stats.mapRecvBytesPerMsgCmd) { + for (const auto& i : stats.mapRecvBytesPerMsgCmd) { if (i.second > 0) recvPerMsgCmd.pushKV(i.first, i.second); } diff --git a/src/streams.h b/src/streams.h index d5565fe61f..0809c96be1 100644 --- a/src/streams.h +++ b/src/streams.h @@ -64,12 +64,6 @@ public: size_t size() const { return stream->size(); } }; -template<typename S> -OverrideStream<S> WithOrVersion(S* s, int nVersionFlag) -{ - return OverrideStream<S>(s, s->GetType(), s->GetVersion() | nVersionFlag); -} - /* Minimal stream for overwriting and/or appending to an existing byte vector * * The referenced vector will grow as necessary @@ -126,12 +120,6 @@ class CVectorWriter { return nType; } - void seek(size_t nSize) - { - nPos += nSize; - if(nPos > vchData.size()) - vchData.resize(nPos); - } private: const int nType; const int nVersion; @@ -158,9 +146,11 @@ public: * @param[in] pos Starting position. Vector index where reads should start. */ VectorReader(int type, int version, const std::vector<unsigned char>& data, size_t pos) - : m_type(type), m_version(version), m_data(data) + : m_type(type), m_version(version), m_data(data), m_pos(pos) { - seek(pos); + if (m_pos > m_data.size()) { + throw std::ios_base::failure("VectorReader(...): end of data (m_pos > m_data.size())"); + } } /* @@ -203,14 +193,6 @@ public: memcpy(dst, m_data.data() + m_pos, n); m_pos = pos_next; } - - void seek(size_t n) - { - m_pos += n; - if (m_pos > m_data.size()) { - throw std::ios_base::failure("VectorReader::seek(): end of data"); - } - } }; /** Double ended buffer combining vector and stream-like interfaces. diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp index 234da5ae4d..22347fbc57 100644 --- a/src/test/addrman_tests.cpp +++ b/src/test/addrman_tests.cpp @@ -12,13 +12,9 @@ class CAddrManTest : public CAddrMan { - uint64_t state; - public: explicit CAddrManTest(bool makeDeterministic = true) { - state = 1; - if (makeDeterministic) { // Set addrman addr placement to be deterministic. MakeDeterministic(); diff --git a/src/test/blockchain_tests.cpp b/src/test/blockchain_tests.cpp index 7d8ae46fb8..b61152985f 100644 --- a/src/test/blockchain_tests.cpp +++ b/src/test/blockchain_tests.cpp @@ -68,11 +68,4 @@ BOOST_AUTO_TEST_CASE(get_difficulty_for_very_high_target) TestDifficulty(0x12345678, 5913134931067755359633408.0); } -// Verify that difficulty is 1.0 for an empty chain. -BOOST_AUTO_TEST_CASE(get_difficulty_for_null_tip) -{ - double difficulty = GetDifficulty(nullptr); - RejectDifficultyMismatch(difficulty, 1.0); -} - BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/script_p2sh_tests.cpp b/src/test/script_p2sh_tests.cpp index 1556b2f667..3a2a11ef98 100644 --- a/src/test/script_p2sh_tests.cpp +++ b/src/test/script_p2sh_tests.cpp @@ -213,14 +213,22 @@ BOOST_AUTO_TEST_CASE(is) BOOST_CHECK(p2sh.IsPayToScriptHash()); // Not considered pay-to-script-hash if using one of the OP_PUSHDATA opcodes: - static const unsigned char direct[] = { OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL }; - BOOST_CHECK(CScript(direct, direct+sizeof(direct)).IsPayToScriptHash()); - static const unsigned char pushdata1[] = { OP_HASH160, OP_PUSHDATA1, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL }; - BOOST_CHECK(!CScript(pushdata1, pushdata1+sizeof(pushdata1)).IsPayToScriptHash()); - static const unsigned char pushdata2[] = { OP_HASH160, OP_PUSHDATA2, 20,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL }; - BOOST_CHECK(!CScript(pushdata2, pushdata2+sizeof(pushdata2)).IsPayToScriptHash()); - static const unsigned char pushdata4[] = { OP_HASH160, OP_PUSHDATA4, 20,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL }; - BOOST_CHECK(!CScript(pushdata4, pushdata4+sizeof(pushdata4)).IsPayToScriptHash()); + std::vector<unsigned char> direct = {OP_HASH160, 20}; + direct.insert(direct.end(), 20, 0); + direct.push_back(OP_EQUAL); + BOOST_CHECK(CScript(direct.begin(), direct.end()).IsPayToScriptHash()); + std::vector<unsigned char> pushdata1 = {OP_HASH160, OP_PUSHDATA1, 20}; + pushdata1.insert(pushdata1.end(), 20, 0); + pushdata1.push_back(OP_EQUAL); + BOOST_CHECK(!CScript(pushdata1.begin(), pushdata1.end()).IsPayToScriptHash()); + std::vector<unsigned char> pushdata2 = {OP_HASH160, 20, 0}; + pushdata2.insert(pushdata2.end(), 20, 0); + pushdata2.push_back(OP_EQUAL); + BOOST_CHECK(!CScript(pushdata2.begin(), pushdata2.end()).IsPayToScriptHash()); + std::vector<unsigned char> pushdata4 = {OP_HASH160, 20, 0, 0, 0}; + pushdata4.insert(pushdata4.end(), 20, 0); + pushdata4.push_back(OP_EQUAL); + BOOST_CHECK(!CScript(pushdata4.begin(), pushdata4.end()).IsPayToScriptHash()); CScript not_p2sh; BOOST_CHECK(!not_p2sh.IsPayToScriptHash()); diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp index 26cf74830d..a1940eb80e 100644 --- a/src/test/streams_tests.cpp +++ b/src/test/streams_tests.cpp @@ -102,15 +102,15 @@ BOOST_AUTO_TEST_CASE(streams_vector_reader) BOOST_CHECK_THROW(reader >> d, std::ios_base::failure); // Read a 4 bytes as a signed int from the beginning of the buffer. - reader.seek(-6); - reader >> d; + VectorReader new_reader(SER_NETWORK, INIT_PROTO_VERSION, vch, 0); + new_reader >> d; BOOST_CHECK_EQUAL(d, 67370753); // 1,255,3,4 in little-endian base-256 - BOOST_CHECK_EQUAL(reader.size(), 2); - BOOST_CHECK(!reader.empty()); + BOOST_CHECK_EQUAL(new_reader.size(), 2); + BOOST_CHECK(!new_reader.empty()); // Reading after end of byte vector throws an error even if the reader is // not totally empty. - BOOST_CHECK_THROW(reader >> d, std::ios_base::failure); + BOOST_CHECK_THROW(new_reader >> d, std::ios_base::failure); } BOOST_AUTO_TEST_CASE(bitstream_reader_writer) diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index d952054483..39cff3f463 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -414,7 +414,8 @@ static void ReplaceRedeemScript(CScript& script, const CScript& redeemScript) script = PushAll(stack); } -BOOST_AUTO_TEST_CASE(test_big_witness_transaction) { +BOOST_AUTO_TEST_CASE(test_big_witness_transaction) +{ CMutableTransaction mtx; mtx.nVersion = 1; @@ -456,9 +457,8 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction) { } CDataStream ssout(SER_NETWORK, PROTOCOL_VERSION); - auto vstream = WithOrVersion(&ssout, 0); - vstream << mtx; - CTransaction tx(deserialize, vstream); + ssout << mtx; + CTransaction tx(deserialize, ssout); // check all inputs concurrently, with the cache PrecomputedTransactionData txdata(tx); diff --git a/src/test/txindex_tests.cpp b/src/test/txindex_tests.cpp index 43e025c58f..0301901bf0 100644 --- a/src/test/txindex_tests.cpp +++ b/src/test/txindex_tests.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <chainparams.h> #include <index/txindex.h> #include <script/standard.h> #include <test/test_bitcoin.h> @@ -38,6 +39,12 @@ BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup) MilliSleep(100); } + // Check that txindex excludes genesis block transactions. + const CBlock& genesis_block = Params().GenesisBlock(); + for (const auto& txn : genesis_block.vtx) { + BOOST_CHECK(!txindex.FindTx(txn->GetHash(), block_hash, tx_disk)); + } + // Check that txindex has all txs that were in the chain before it started. for (const auto& txn : m_coinbase_txns) { if (!txindex.FindTx(txn->GetHash(), block_hash, tx_disk)) { diff --git a/src/validation.cpp b/src/validation.cpp index 00d7a60cb7..a18e449af6 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3998,7 +3998,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, LogPrintf("[0%%]..."); /* Continued */ for (pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) { boost::this_thread::interruption_point(); - int percentageDone = std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100)))); + const int percentageDone = std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100)))); if (reportDone < percentageDone/10) { // report every 10% step LogPrintf("[%d%%]...", percentageDone); /* Continued */ @@ -4056,7 +4056,13 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, if (nCheckLevel >= 4) { while (pindex != chainActive.Tip()) { boost::this_thread::interruption_point(); - uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, 100 - (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50))), false); + const int percentageDone = std::max(1, std::min(99, 100 - (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50))); + if (reportDone < percentageDone/10) { + // report every 10% step + LogPrintf("[%d%%]...", percentageDone); /* Continued */ + reportDone = percentageDone/10; + } + uiInterface.ShowProgress(_("Verifying blocks..."), percentageDone, false); pindex = chainActive.Next(pindex); CBlock block; if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index c1cdd0b2ee..38397a3940 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -1020,15 +1020,12 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request) struct tallyitem { - CAmount nAmount; - int nConf; + CAmount nAmount{0}; + int nConf{std::numeric_limits<int>::max()}; std::vector<uint256> txids; - bool fIsWatchonly; + bool fIsWatchonly{false}; tallyitem() { - nAmount = 0; - nConf = std::numeric_limits<int>::max(); - fIsWatchonly = false; } }; diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 1ed1926af2..0db22cf6fe 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2018 The Bitcoin Core developers +// Copyright (c) 2012-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -47,7 +47,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) auto locked_chain = chain->lock(); - // Verify ScanForWalletTransactions accomodates a null start block. + // Verify ScanForWalletTransactions accommodates a null start block. { CWallet wallet(*chain, WalletLocation(), WalletDatabase::CreateDummy()); AddKey(wallet, coinbaseKey); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 95a2c833f8..3a3ec43c9b 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1178,18 +1178,16 @@ class CReserveKey final : public CReserveScript { protected: CWallet* pwallet; - int64_t nIndex; + int64_t nIndex{-1}; CPubKey vchPubKey; - bool fInternal; + bool fInternal{false}; + public: explicit CReserveKey(CWallet* pwalletIn) { - nIndex = -1; pwallet = pwalletIn; - fInternal = false; } - CReserveKey() = default; CReserveKey(const CReserveKey&) = delete; CReserveKey& operator=(const CReserveKey&) = delete; diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 09a33f252c..6e037808e3 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -153,21 +153,17 @@ bool WalletBatch::WriteMinVersion(int nVersion) class CWalletScanState { public: - unsigned int nKeys; - unsigned int nCKeys; - unsigned int nWatchKeys; - unsigned int nKeyMeta; - unsigned int m_unknown_records; - bool fIsEncrypted; - bool fAnyUnordered; - int nFileVersion; + unsigned int nKeys{0}; + unsigned int nCKeys{0}; + unsigned int nWatchKeys{0}; + unsigned int nKeyMeta{0}; + unsigned int m_unknown_records{0}; + bool fIsEncrypted{false}; + bool fAnyUnordered{false}; + int nFileVersion{0}; std::vector<uint256> vWalletUpgrade; CWalletScanState() { - nKeys = nCKeys = nWatchKeys = nKeyMeta = m_unknown_records = 0; - fIsEncrypted = false; - fAnyUnordered = false; - nFileVersion = 0; } }; |