diff options
34 files changed, 582 insertions, 283 deletions
diff --git a/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in b/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in index 0a165d0b75..e66277123a 100644 --- a/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in +++ b/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in @@ -154,12 +154,6 @@ </Link> </ItemDefinitionGroup> <ItemGroup> - <ClCompile Include="..\..\src\rpc\net.cpp"> - <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)\netrpc.obj</ObjectFileName> - <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)\netrpc.obj</ObjectFileName> - <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)\netrpc.obj</ObjectFileName> - <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)\netrpc.obj</ObjectFileName> - </ClCompile> @SOURCE_FILES@ </ItemGroup> <ItemGroup> 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/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/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 65c681c317..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); @@ -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. @@ -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/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/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/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 9cd0fed7db..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. @@ -576,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 844d9afc3b..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(); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 55282f433f..315f69d46b 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -747,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"); } @@ -768,7 +773,7 @@ static UniValue getblockheader(const JSONRPCRequest& request) return strHex; } - return blockheaderToJSON(chainActive.Tip(), pblockindex); + return blockheaderToJSON(tip, pblockindex); } static CBlock GetBlockChecked(const CBlockIndex* pblockindex) @@ -1564,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/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 8010a061c7..0809c96be1 100644 --- a/src/streams.h +++ b/src/streams.h @@ -120,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; @@ -152,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())"); + } } /* @@ -197,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/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/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/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/test/functional/feature_block.py b/test/functional/feature_block.py index 697a0b19ac..5253ff7aaa 100755 --- a/test/functional/feature_block.py +++ b/test/functional/feature_block.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2018 The Bitcoin Core developers +# Copyright (c) 2015-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. """Test block processing.""" @@ -137,12 +137,6 @@ class FullBlockTest(BitcoinTestFramework): for TxTemplate in invalid_txs.iter_all_templates(): template = TxTemplate(spend_tx=attempt_spend_tx) - # Something about the serialization code for missing inputs creates - # a different hash in the test client than on bitcoind, resulting - # in a mismatching merkle root during block validation. - # Skip until we figure out what's going on. - if TxTemplate == invalid_txs.InputMissing: - continue if template.valid_in_block: continue @@ -150,7 +144,22 @@ class FullBlockTest(BitcoinTestFramework): blockname = "for_invalid.%s" % TxTemplate.__name__ badblock = self.next_block(blockname) badtx = template.get_tx() - self.sign_tx(badtx, attempt_spend_tx) + if TxTemplate != invalid_txs.InputMissing: + self.sign_tx(badtx, attempt_spend_tx) + else: + # Segwit is active in regtest at this point, so to deserialize a + # transaction without any inputs correctly, we set the outputs + # to an empty list. This is a hack, as the serialization of an + # empty list of outputs is deserialized as flags==0 and thus + # deserialization of the outputs is skipped. + # A policy check requires "loose" txs to be of a minimum size, + # so vtx is not set to be empty in the TxTemplate class and we + # only apply the workaround where txs are not "loose", i.e. in + # blocks. + # + # The workaround has the purpose that both sides calculate + # the same tx hash in the merkle tree + badtx.vout = [] badtx.rehash() badblock = self.update_block(blockname, [badtx]) self.sync_blocks( @@ -916,7 +925,7 @@ class FullBlockTest(BitcoinTestFramework): # \-> b67 (20) # # - self.log.info("Reject a block with a transaction double spending a transaction creted in the same block") + self.log.info("Reject a block with a transaction double spending a transaction created in the same block") self.move_tip(65) b67 = self.next_block(67) tx1 = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue) @@ -1211,7 +1220,7 @@ class FullBlockTest(BitcoinTestFramework): blocks = [] spend = out[32] for i in range(89, LARGE_REORG_SIZE + 89): - b = self.next_block(i, spend) + b = self.next_block(i, spend, version=4) tx = CTransaction() script_length = MAX_BLOCK_BASE_SIZE - len(b.serialize()) - 69 script_output = CScript([b'\x00' * script_length]) @@ -1230,20 +1239,32 @@ class FullBlockTest(BitcoinTestFramework): self.move_tip(88) blocks2 = [] for i in range(89, LARGE_REORG_SIZE + 89): - blocks2.append(self.next_block("alt" + str(i))) + blocks2.append(self.next_block("alt" + str(i), version=4)) self.sync_blocks(blocks2, False, force_send=True) # extend alt chain to trigger re-org - block = self.next_block("alt" + str(chain1_tip + 1)) + block = self.next_block("alt" + str(chain1_tip + 1), version=4) self.sync_blocks([block], True, timeout=480) # ... and re-org back to the first chain self.move_tip(chain1_tip) - block = self.next_block(chain1_tip + 1) + block = self.next_block(chain1_tip + 1, version=4) self.sync_blocks([block], False, force_send=True) - block = self.next_block(chain1_tip + 2) + block = self.next_block(chain1_tip + 2, version=4) self.sync_blocks([block], True, timeout=480) + self.log.info("Reject a block with an invalid block header version") + b_v1 = self.next_block('b_v1', version=1) + self.sync_blocks([b_v1], success=False, force_send=True, reject_reason='bad-version(0x00000001)') + + self.move_tip(chain1_tip + 2) + b_cb34 = self.next_block('b_cb34', version=4) + b_cb34.vtx[0].vin[0].scriptSig = b_cb34.vtx[0].vin[0].scriptSig[:-1] + b_cb34.vtx[0].rehash() + b_cb34.hashMerkleRoot = b_cb34.calc_merkle_root() + b_cb34.solve() + self.sync_blocks([b_cb34], success=False, reject_reason='bad-cb-height', reconnect=True) + # Helper methods ################ @@ -1271,7 +1292,7 @@ class FullBlockTest(BitcoinTestFramework): tx.rehash() return tx - def next_block(self, number, spend=None, additional_coinbase_value=0, script=CScript([OP_TRUE]), solve=True): + def next_block(self, number, spend=None, additional_coinbase_value=0, script=CScript([OP_TRUE]), solve=True, *, version=1): if self.tip is None: base_block_hash = self.genesis_hash block_time = int(time.time()) + 1 @@ -1284,11 +1305,11 @@ class FullBlockTest(BitcoinTestFramework): coinbase.vout[0].nValue += additional_coinbase_value coinbase.rehash() if spend is None: - block = create_block(base_block_hash, coinbase, block_time) + block = create_block(base_block_hash, coinbase, block_time, version=version) else: coinbase.vout[0].nValue += spend.vout[0].nValue - 1 # all but one satoshi to fees coinbase.rehash() - block = create_block(base_block_hash, coinbase, block_time) + block = create_block(base_block_hash, coinbase, block_time, version=version) tx = self.create_tx(spend, 0, 1, script) # spend 1 satoshi self.sign_tx(tx, spend) self.add_transactions_to_block(block, [tx]) diff --git a/test/functional/rpc_invalidateblock.py b/test/functional/rpc_invalidateblock.py index d8ecdd573a..d8a1deb2a3 100755 --- a/test/functional/rpc_invalidateblock.py +++ b/test/functional/rpc_invalidateblock.py @@ -4,10 +4,15 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test the invalidateblock RPC.""" -import time - from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, connect_nodes_bi, sync_blocks +from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE +from test_framework.util import ( + assert_equal, + connect_nodes_bi, + sync_blocks, + wait_until, +) + class InvalidateTest(BitcoinTestFramework): def set_test_params(self): @@ -21,46 +26,66 @@ class InvalidateTest(BitcoinTestFramework): self.log.info("Make sure we repopulate setBlockIndexCandidates after InvalidateBlock:") self.log.info("Mine 4 blocks on Node 0") self.nodes[0].generatetoaddress(4, self.nodes[0].get_deterministic_priv_key().address) - assert(self.nodes[0].getblockcount() == 4) - besthash = self.nodes[0].getbestblockhash() + assert_equal(self.nodes[0].getblockcount(), 4) + besthash_n0 = self.nodes[0].getbestblockhash() self.log.info("Mine competing 6 blocks on Node 1") self.nodes[1].generatetoaddress(6, self.nodes[1].get_deterministic_priv_key().address) - assert(self.nodes[1].getblockcount() == 6) + assert_equal(self.nodes[1].getblockcount(), 6) self.log.info("Connect nodes to force a reorg") - connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes, 0, 1) sync_blocks(self.nodes[0:2]) - assert(self.nodes[0].getblockcount() == 6) + assert_equal(self.nodes[0].getblockcount(), 6) badhash = self.nodes[1].getblockhash(2) self.log.info("Invalidate block 2 on node 0 and verify we reorg to node 0's original chain") self.nodes[0].invalidateblock(badhash) - newheight = self.nodes[0].getblockcount() - newhash = self.nodes[0].getbestblockhash() - if (newheight != 4 or newhash != besthash): - raise AssertionError("Wrong tip for node0, hash %s, height %d"%(newhash,newheight)) + assert_equal(self.nodes[0].getblockcount(), 4) + assert_equal(self.nodes[0].getbestblockhash(), besthash_n0) self.log.info("Make sure we won't reorg to a lower work chain:") - connect_nodes_bi(self.nodes,1,2) + connect_nodes_bi(self.nodes, 1, 2) self.log.info("Sync node 2 to node 1 so both have 6 blocks") sync_blocks(self.nodes[1:3]) - assert(self.nodes[2].getblockcount() == 6) + assert_equal(self.nodes[2].getblockcount(), 6) self.log.info("Invalidate block 5 on node 1 so its tip is now at 4") self.nodes[1].invalidateblock(self.nodes[1].getblockhash(5)) - assert(self.nodes[1].getblockcount() == 4) + assert_equal(self.nodes[1].getblockcount(), 4) self.log.info("Invalidate block 3 on node 2, so its tip is now 2") self.nodes[2].invalidateblock(self.nodes[2].getblockhash(3)) - assert(self.nodes[2].getblockcount() == 2) + assert_equal(self.nodes[2].getblockcount(), 2) self.log.info("..and then mine a block") self.nodes[2].generatetoaddress(1, self.nodes[2].get_deterministic_priv_key().address) self.log.info("Verify all nodes are at the right height") - time.sleep(5) - assert_equal(self.nodes[2].getblockcount(), 3) - assert_equal(self.nodes[0].getblockcount(), 4) - node1height = self.nodes[1].getblockcount() - if node1height < 4: - raise AssertionError("Node 1 reorged to a lower height: %d"%node1height) + wait_until(lambda: self.nodes[2].getblockcount() == 3, timeout=5) + wait_until(lambda: self.nodes[0].getblockcount() == 4, timeout=5) + wait_until(lambda: self.nodes[1].getblockcount() == 4, timeout=5) + + self.log.info("Verify that we reconsider all ancestors as well") + blocks = self.nodes[1].generatetoaddress(10, ADDRESS_BCRT1_UNSPENDABLE) + assert_equal(self.nodes[1].getbestblockhash(), blocks[-1]) + # Invalidate the two blocks at the tip + self.nodes[1].invalidateblock(blocks[-1]) + self.nodes[1].invalidateblock(blocks[-2]) + assert_equal(self.nodes[1].getbestblockhash(), blocks[-3]) + # Reconsider only the previous tip + self.nodes[1].reconsiderblock(blocks[-1]) + # Should be back at the tip by now + assert_equal(self.nodes[1].getbestblockhash(), blocks[-1]) + + self.log.info("Verify that we reconsider all descendants") + blocks = self.nodes[1].generatetoaddress(10, ADDRESS_BCRT1_UNSPENDABLE) + assert_equal(self.nodes[1].getbestblockhash(), blocks[-1]) + # Invalidate the two blocks at the tip + self.nodes[1].invalidateblock(blocks[-2]) + self.nodes[1].invalidateblock(blocks[-4]) + assert_equal(self.nodes[1].getbestblockhash(), blocks[-5]) + # Reconsider only the previous tip + self.nodes[1].reconsiderblock(blocks[-4]) + # Should be back at the tip by now + assert_equal(self.nodes[1].getbestblockhash(), blocks[-1]) + if __name__ == '__main__': InvalidateTest().main() diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py index 7679ea5398..6b47cae4c3 100644 --- a/test/functional/test_framework/blocktools.py +++ b/test/functional/test_framework/blocktools.py @@ -46,9 +46,10 @@ MAX_BLOCK_SIGOPS = 20000 # From BIP141 WITNESS_COMMITMENT_HEADER = b"\xaa\x21\xa9\xed" -def create_block(hashprev, coinbase, ntime=None): +def create_block(hashprev, coinbase, ntime=None, *, version=1): """Create a block (with regtest difficulty).""" block = CBlock() + block.nVersion = version if ntime is None: import time block.nTime = int(time.time() + 600) diff --git a/test/sanitizer_suppressions/ubsan b/test/sanitizer_suppressions/ubsan index e90d5c2ac0..f0107f1361 100644 --- a/test/sanitizer_suppressions/ubsan +++ b/test/sanitizer_suppressions/ubsan @@ -29,7 +29,6 @@ unsigned-integer-overflow:policy/fees.cpp unsigned-integer-overflow:prevector.h unsigned-integer-overflow:script/interpreter.cpp unsigned-integer-overflow:stl_bvector.h -unsigned-integer-overflow:streams.h unsigned-integer-overflow:txmempool.cpp unsigned-integer-overflow:util/strencodings.cpp unsigned-integer-overflow:validation.cpp |