diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp index 04a9fda00..d3b728831 100644 --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -1,365 +1,368 @@ // 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(HAVE_CONFIG_H) #include #endif #include #include class HTTPRPCRequestProcessor; class CWallet; fs::path GetWalletDir(); std::vector ListWalletDir(); std::vector> GetWallets(); std::shared_ptr LoadWallet(const CChainParams &chainParams, interfaces::Chain &chain, const std::string &name, bilingual_str &error, std::vector &warnings); WalletCreationStatus CreateWallet(const CChainParams ¶ms, interfaces::Chain &chain, const SecureString &passphrase, uint64_t wallet_creation_flags, const std::string &name, bilingual_str &error, std::vector &warnings, std::shared_ptr &result); std::unique_ptr HandleLoadWallet(interfaces::Node::LoadWalletFn load_wallet); namespace interfaces { namespace { class NodeImpl : public Node { public: NodeImpl(NodeContext *context) { setContext(context); } void initLogging() override { InitLogging(*Assert(m_context->args)); } void initParameterInteraction() override { InitParameterInteraction(*Assert(m_context->args)); } std::string getWarnings() override { return GetWarnings(true); } bool baseInitialize(Config &config) override { return AppInitBasicSetup(gArgs) && AppInitParameterInteraction(config, gArgs) && AppInitSanityChecks() && AppInitLockDataDirectory(); } bool appInitMain(Config &config, RPCServer &rpcServer, HTTPRPCRequestProcessor &httpRPCRequestProcessor) override { m_context->chain = MakeChain(*m_context, config.GetChainParams()); return AppInitMain(config, rpcServer, httpRPCRequestProcessor, *m_context); } void appShutdown() override { Interrupt(*m_context); Shutdown(*m_context); } void startShutdown() override { StartShutdown(); } bool shutdownRequested() override { return ShutdownRequested(); } void mapPort(bool use_upnp) override { if (use_upnp) { StartMapPort(); } else { InterruptMapPort(); StopMapPort(); } } bool getProxy(Network net, proxyType &proxy_info) override { return GetProxy(net, proxy_info); } size_t getNodeCount(CConnman::NumConnections flags) override { return m_context->connman ? m_context->connman->GetNodeCount(flags) : 0; } bool getNodesStats(NodesStats &stats) override { stats.clear(); if (m_context->connman) { std::vector stats_temp; m_context->connman->GetNodeStats(stats_temp); stats.reserve(stats_temp.size()); for (auto &node_stats_temp : stats_temp) { stats.emplace_back(std::move(node_stats_temp), false, CNodeStateStats()); } // Try to retrieve the CNodeStateStats for each node. TRY_LOCK(::cs_main, lockMain); if (lockMain) { for (auto &node_stats : stats) { std::get<1>(node_stats) = GetNodeStateStats(std::get<0>(node_stats).nodeid, std::get<2>(node_stats)); } } return true; } return false; } bool getBanned(banmap_t &banmap) override { if (m_context->banman) { m_context->banman->GetBanned(banmap); return true; } return false; } bool ban(const CNetAddr &net_addr, int64_t ban_time_offset) override { if (m_context->banman) { m_context->banman->Ban(net_addr, ban_time_offset); return true; } return false; } bool unban(const CSubNet &ip) override { if (m_context->banman) { m_context->banman->Unban(ip); return true; } return false; } bool disconnectByAddress(const CNetAddr &net_addr) override { if (m_context->connman) { return m_context->connman->DisconnectNode(net_addr); } return false; } bool disconnectById(NodeId id) override { if (m_context->connman) { return m_context->connman->DisconnectNode(id); } return false; } int64_t getTotalBytesRecv() override { return m_context->connman ? m_context->connman->GetTotalBytesRecv() : 0; } int64_t getTotalBytesSent() override { return m_context->connman ? m_context->connman->GetTotalBytesSent() : 0; } size_t getMempoolSize() override { return m_context->mempool ? m_context->mempool->size() : 0; } size_t getMempoolDynamicUsage() override { return m_context->mempool ? m_context->mempool->DynamicMemoryUsage() : 0; } bool getHeaderTip(int &height, int64_t &block_time) override { LOCK(::cs_main); if (::pindexBestHeader) { height = ::pindexBestHeader->nHeight; block_time = ::pindexBestHeader->GetBlockTime(); return true; } return false; } int getNumBlocks() override { LOCK(::cs_main); return ::ChainActive().Height(); } BlockHash getBestBlockHash() override { const CBlockIndex *tip = WITH_LOCK(::cs_main, return ::ChainActive().Tip()); return tip ? tip->GetBlockHash() : Params().GenesisBlock().GetHash(); } int64_t getLastBlockTime() override { LOCK(::cs_main); if (::ChainActive().Tip()) { return ::ChainActive().Tip()->GetBlockTime(); } // Genesis block's time of current network return Params().GenesisBlock().GetBlockTime(); } double getVerificationProgress() override { const CBlockIndex *tip; { LOCK(::cs_main); tip = ::ChainActive().Tip(); } return GuessVerificationProgress(Params().TxData(), tip); } bool isInitialBlockDownload() override { return ::ChainstateActive().IsInitialBlockDownload(); } bool getReindex() override { return ::fReindex; } bool getImporting() override { return ::fImporting; } void setNetworkActive(bool active) override { if (m_context->connman) { m_context->connman->SetNetworkActive(active); } } bool getNetworkActive() override { return m_context->connman && m_context->connman->GetNetworkActive(); } CFeeRate estimateSmartFee() override { return m_context->mempool ? m_context->mempool->estimateFee() : CFeeRate(); } CFeeRate getDustRelayFee() override { return ::dustRelayFee; } UniValue executeRpc(Config &config, const std::string &command, const UniValue ¶ms, const std::string &uri) override { JSONRPCRequest req(m_context_ref); req.params = params; req.strMethod = command; req.URI = uri; return ::tableRPC.execute(config, req); } std::vector listRpcCommands() override { return ::tableRPC.listCommands(); } void rpcSetTimerInterfaceIfUnset(RPCTimerInterface *iface) override { RPCSetTimerInterfaceIfUnset(iface); } void rpcUnsetTimerInterface(RPCTimerInterface *iface) override { RPCUnsetTimerInterface(iface); } bool getUnspentOutput(const COutPoint &output, Coin &coin) override { LOCK(::cs_main); return ::ChainstateActive().CoinsTip().GetCoin(output, coin); } std::string getWalletDir() override { return GetWalletDir().string(); } std::vector listWalletDir() override { std::vector paths; for (auto &path : ListWalletDir()) { paths.push_back(path.string()); } return paths; } std::vector> getWallets() override { std::vector> wallets; for (auto &client : m_context->chain_clients) { auto client_wallets = client->getWallets(); std::move(client_wallets.begin(), client_wallets.end(), std::back_inserter(wallets)); } return wallets; } std::unique_ptr loadWallet(const CChainParams ¶ms, const std::string &name, bilingual_str &error, std::vector &warnings) const override { return MakeWallet( LoadWallet(params, *m_context->chain, name, error, warnings)); } std::unique_ptr createWallet(const CChainParams ¶ms, const SecureString &passphrase, uint64_t wallet_creation_flags, const std::string &name, bilingual_str &error, std::vector &warnings, WalletCreationStatus &status) override { std::shared_ptr wallet; status = CreateWallet(params, *m_context->chain, passphrase, wallet_creation_flags, name, error, warnings, wallet); return MakeWallet(wallet); } std::unique_ptr handleInitMessage(InitMessageFn fn) override { return MakeHandler(::uiInterface.InitMessage_connect(fn)); } std::unique_ptr handleMessageBox(MessageBoxFn fn) override { return MakeHandler(::uiInterface.ThreadSafeMessageBox_connect(fn)); } std::unique_ptr handleQuestion(QuestionFn fn) override { return MakeHandler(::uiInterface.ThreadSafeQuestion_connect(fn)); } std::unique_ptr handleShowProgress(ShowProgressFn fn) override { return MakeHandler(::uiInterface.ShowProgress_connect(fn)); } std::unique_ptr handleLoadWallet(LoadWalletFn fn) override { return HandleLoadWallet(std::move(fn)); } std::unique_ptr handleNotifyNumConnectionsChanged( NotifyNumConnectionsChangedFn fn) override { return MakeHandler( ::uiInterface.NotifyNumConnectionsChanged_connect(fn)); } std::unique_ptr handleNotifyNetworkActiveChanged( NotifyNetworkActiveChangedFn fn) override { return MakeHandler( ::uiInterface.NotifyNetworkActiveChanged_connect(fn)); } std::unique_ptr handleNotifyAlertChanged(NotifyAlertChangedFn fn) override { return MakeHandler(::uiInterface.NotifyAlertChanged_connect(fn)); } std::unique_ptr handleBannedListChanged(BannedListChangedFn fn) override { return MakeHandler(::uiInterface.BannedListChanged_connect(fn)); } std::unique_ptr handleNotifyBlockTip(NotifyBlockTipFn fn) override { return MakeHandler(::uiInterface.NotifyBlockTip_connect( [fn](SynchronizationState sync_state, const CBlockIndex *block) { - fn(sync_state, block->GetBlockHash(), block->nHeight, - block->GetBlockTime(), + fn(sync_state, + BlockTip{block->nHeight, block->GetBlockTime(), + block->GetBlockHash()}, GuessVerificationProgress(Params().TxData(), block)); })); } std::unique_ptr handleNotifyHeaderTip(NotifyHeaderTipFn fn) override { /* verification progress is unused when a header was received */ return MakeHandler(::uiInterface.NotifyHeaderTip_connect( [fn](SynchronizationState sync_state, const CBlockIndex *block) { - fn(sync_state, block->GetBlockHash(), block->nHeight, - block->GetBlockTime(), 0); + fn(sync_state, + BlockTip{block->nHeight, block->GetBlockTime(), + block->GetBlockHash()}, + 0); })); } NodeContext *context() override { return m_context; } void setContext(NodeContext *context) override { m_context = context; if (context) { m_context_ref.Set(*context); } else { m_context_ref.Clear(); } } NodeContext *m_context{nullptr}; util::Ref m_context_ref{m_context}; }; } // namespace std::unique_ptr MakeNode(NodeContext *context) { return std::make_unique(context); } } // namespace interfaces diff --git a/src/interfaces/node.h b/src/interfaces/node.h index ed4160a78..3bf7668e8 100644 --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -1,266 +1,274 @@ // 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_INTERFACES_NODE_H #define BITCOIN_INTERFACES_NODE_H #include // For Amount #include // For CConnman::NumConnections #include // For banmap_t #include // For Network #include // For SecureString #include #include #include #include #include #include #include class BanMan; class CCoinControl; class CFeeRate; struct CNodeStateStats; struct CNodeStats; class Coin; class Config; class HTTPRPCRequestProcessor; struct NodeContext; class proxyType; class RPCServer; class RPCTimerInterface; enum class SynchronizationState; class UniValue; enum class WalletCreationStatus; struct bilingual_str; namespace interfaces { class Handler; class Wallet; +struct BlockTip; //! Top-level interface for a bitcoin node (bitcoind process). class Node { public: virtual ~Node() {} //! Init logging. virtual void initLogging() = 0; //! Init parameter interaction. virtual void initParameterInteraction() = 0; //! Get warnings. virtual std::string getWarnings() = 0; //! Initialize app dependencies. virtual bool baseInitialize(Config &config) = 0; //! Start node. virtual bool appInitMain(Config &config, RPCServer &rpcServer, HTTPRPCRequestProcessor &httpRPCRequestProcessor) = 0; //! Stop node. virtual void appShutdown() = 0; //! Start shutdown. virtual void startShutdown() = 0; //! Return whether shutdown was requested. virtual bool shutdownRequested() = 0; //! Map port. virtual void mapPort(bool use_upnp) = 0; //! Get proxy. virtual bool getProxy(Network net, proxyType &proxy_info) = 0; //! Get number of connections. virtual size_t getNodeCount(CConnman::NumConnections flags) = 0; //! Get stats for connected nodes. using NodesStats = std::vector>; virtual bool getNodesStats(NodesStats &stats) = 0; //! Get ban map entries. virtual bool getBanned(banmap_t &banmap) = 0; //! Ban node. virtual bool ban(const CNetAddr &net_addr, int64_t ban_time_offset) = 0; //! Unban node. virtual bool unban(const CSubNet &ip) = 0; //! Disconnect node by address. virtual bool disconnectByAddress(const CNetAddr &net_addr) = 0; //! Disconnect node by id. virtual bool disconnectById(NodeId id) = 0; //! Get total bytes recv. virtual int64_t getTotalBytesRecv() = 0; //! Get total bytes sent. virtual int64_t getTotalBytesSent() = 0; //! Get mempool size. virtual size_t getMempoolSize() = 0; //! Get mempool dynamic usage. virtual size_t getMempoolDynamicUsage() = 0; //! Get header tip height and time. virtual bool getHeaderTip(int &height, int64_t &block_time) = 0; //! Get num blocks. virtual int getNumBlocks() = 0; //! Get best block hash. virtual BlockHash getBestBlockHash() = 0; //! Get last block time. virtual int64_t getLastBlockTime() = 0; //! Get verification progress. virtual double getVerificationProgress() = 0; //! Is initial block download. virtual bool isInitialBlockDownload() = 0; //! Get reindex. virtual bool getReindex() = 0; //! Get importing. virtual bool getImporting() = 0; //! Set network active. virtual void setNetworkActive(bool active) = 0; //! Get network active. virtual bool getNetworkActive() = 0; //! Estimate smart fee. virtual CFeeRate estimateSmartFee() = 0; //! Get dust relay fee. virtual CFeeRate getDustRelayFee() = 0; //! Execute rpc command. virtual UniValue executeRpc(Config &config, const std::string &command, const UniValue ¶ms, const std::string &uri) = 0; //! List rpc commands. virtual std::vector listRpcCommands() = 0; //! Set RPC timer interface if unset. virtual void rpcSetTimerInterfaceIfUnset(RPCTimerInterface *iface) = 0; //! Unset RPC timer interface. virtual void rpcUnsetTimerInterface(RPCTimerInterface *iface) = 0; //! Get unspent outputs associated with a transaction. virtual bool getUnspentOutput(const COutPoint &output, Coin &coin) = 0; //! Return default wallet directory. virtual std::string getWalletDir() = 0; //! Return available wallets in wallet directory. virtual std::vector listWalletDir() = 0; //! Return interfaces for accessing wallets (if any). virtual std::vector> getWallets() = 0; //! Attempts to load a wallet from file or directory. //! The loaded wallet is also notified to handlers previously registered //! with handleLoadWallet. virtual std::unique_ptr loadWallet(const CChainParams ¶ms, const std::string &name, bilingual_str &error, std::vector &warnings) const = 0; //! Create a wallet from file virtual std::unique_ptr createWallet(const CChainParams ¶ms, const SecureString &passphrase, uint64_t wallet_creation_flags, const std::string &name, bilingual_str &error, std::vector &warnings, WalletCreationStatus &status) = 0; //! Register handler for init messages. using InitMessageFn = std::function; virtual std::unique_ptr handleInitMessage(InitMessageFn fn) = 0; //! Register handler for message box messages. using MessageBoxFn = std::function; virtual std::unique_ptr handleMessageBox(MessageBoxFn fn) = 0; //! Register handler for question messages. using QuestionFn = std::function; virtual std::unique_ptr handleQuestion(QuestionFn fn) = 0; //! Register handler for progress messages. using ShowProgressFn = std::function; virtual std::unique_ptr handleShowProgress(ShowProgressFn fn) = 0; //! Register handler for load wallet messages. using LoadWalletFn = std::function wallet)>; virtual std::unique_ptr handleLoadWallet(LoadWalletFn fn) = 0; //! Register handler for number of connections changed messages. using NotifyNumConnectionsChangedFn = std::function; virtual std::unique_ptr handleNotifyNumConnectionsChanged(NotifyNumConnectionsChangedFn fn) = 0; //! Register handler for network active messages. using NotifyNetworkActiveChangedFn = std::function; virtual std::unique_ptr handleNotifyNetworkActiveChanged(NotifyNetworkActiveChangedFn fn) = 0; //! Register handler for notify alert messages. using NotifyAlertChangedFn = std::function; virtual std::unique_ptr handleNotifyAlertChanged(NotifyAlertChangedFn fn) = 0; //! Register handler for ban list messages. using BannedListChangedFn = std::function; virtual std::unique_ptr handleBannedListChanged(BannedListChangedFn fn) = 0; //! Register handler for block tip messages. - using NotifyBlockTipFn = std::function; + using NotifyBlockTipFn = + std::function; virtual std::unique_ptr handleNotifyBlockTip(NotifyBlockTipFn fn) = 0; //! Register handler for header tip messages. - using NotifyHeaderTipFn = std::function; + using NotifyHeaderTipFn = + std::function; virtual std::unique_ptr handleNotifyHeaderTip(NotifyHeaderTipFn fn) = 0; //! Get and set internal node context. Useful for testing, but not //! accessible across processes. virtual NodeContext *context() { return nullptr; } virtual void setContext(NodeContext *context) {} }; //! Return implementation of Node interface. std::unique_ptr MakeNode(NodeContext *context = nullptr); +//! Block tip (could be a header or not, depends on the subscribed signal). +struct BlockTip { + int block_height; + int64_t block_time; + BlockHash block_hash; +}; + } // namespace interfaces #endif // BITCOIN_INTERFACES_NODE_H diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index cc989163f..933dc13d7 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -1,325 +1,323 @@ // 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. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int64_t nLastHeaderTipUpdateNotification = 0; static int64_t nLastBlockTipUpdateNotification = 0; ClientModel::ClientModel(interfaces::Node &node, OptionsModel *_optionsModel, QObject *parent) : QObject(parent), m_node(node), optionsModel(_optionsModel), peerTableModel(nullptr), banTableModel(nullptr), m_thread(new QThread(this)) { cachedBestHeaderHeight = -1; cachedBestHeaderTime = -1; peerTableModel = new PeerTableModel(m_node, this); banTableModel = new BanTableModel(m_node, this); QTimer *timer = new QTimer; timer->setInterval(MODEL_UPDATE_DELAY); connect(timer, &QTimer::timeout, [this] { // no locking required at this point // the following calls will acquire the required lock Q_EMIT mempoolSizeChanged(m_node.getMempoolSize(), m_node.getMempoolDynamicUsage()); Q_EMIT bytesChanged(m_node.getTotalBytesRecv(), m_node.getTotalBytesSent()); }); connect(m_thread, &QThread::finished, timer, &QObject::deleteLater); connect(m_thread, &QThread::started, [timer] { timer->start(); }); // move timer to thread so that polling doesn't disturb main event loop timer->moveToThread(m_thread); m_thread->start(); subscribeToCoreSignals(); } ClientModel::~ClientModel() { unsubscribeFromCoreSignals(); m_thread->quit(); m_thread->wait(); } int ClientModel::getNumConnections(NumConnections flags) const { CConnman::NumConnections connections = CConnman::CONNECTIONS_NONE; if (flags == CONNECTIONS_IN) { connections = CConnman::CONNECTIONS_IN; } else if (flags == CONNECTIONS_OUT) { connections = CConnman::CONNECTIONS_OUT; } else if (flags == CONNECTIONS_ALL) { connections = CConnman::CONNECTIONS_ALL; } return m_node.getNodeCount(connections); } int ClientModel::getHeaderTipHeight() const { if (cachedBestHeaderHeight == -1) { // make sure we initially populate the cache via a cs_main lock // otherwise we need to wait for a tip update int height; int64_t blockTime; if (m_node.getHeaderTip(height, blockTime)) { cachedBestHeaderHeight = height; cachedBestHeaderTime = blockTime; } } return cachedBestHeaderHeight; } int64_t ClientModel::getHeaderTipTime() const { if (cachedBestHeaderTime == -1) { int height; int64_t blockTime; if (m_node.getHeaderTip(height, blockTime)) { cachedBestHeaderHeight = height; cachedBestHeaderTime = blockTime; } } return cachedBestHeaderTime; } int ClientModel::getNumBlocks() const { if (m_cached_num_blocks == -1) { m_cached_num_blocks = m_node.getNumBlocks(); } return m_cached_num_blocks; } BlockHash ClientModel::getBestBlockHash() { BlockHash tip{WITH_LOCK(m_cached_tip_mutex, return m_cached_tip_blocks)}; if (!tip.IsNull()) { return tip; } // Lock order must be: first `cs_main`, then `m_cached_tip_mutex`. // The following will lock `cs_main` (and release it), so we must not // own `m_cached_tip_mutex` here. tip = m_node.getBestBlockHash(); LOCK(m_cached_tip_mutex); // We checked that `m_cached_tip_blocks` is not null above, but then we // released the mutex `m_cached_tip_mutex`, so it could have changed in the // meantime. Thus, check again. if (m_cached_tip_blocks.IsNull()) { m_cached_tip_blocks = tip; } return m_cached_tip_blocks; } void ClientModel::updateNumConnections(int numConnections) { Q_EMIT numConnectionsChanged(numConnections); } void ClientModel::updateNetworkActive(bool networkActive) { Q_EMIT networkActiveChanged(networkActive); } void ClientModel::updateAlert() { Q_EMIT alertsChanged(getStatusBarWarnings()); } enum BlockSource ClientModel::getBlockSource() const { if (m_node.getReindex()) { return BlockSource::REINDEX; } else if (m_node.getImporting()) { return BlockSource::DISK; } else if (getNumConnections() > 0) { return BlockSource::NETWORK; } return BlockSource::NONE; } QString ClientModel::getStatusBarWarnings() const { return QString::fromStdString(m_node.getWarnings()); } OptionsModel *ClientModel::getOptionsModel() { return optionsModel; } PeerTableModel *ClientModel::getPeerTableModel() { return peerTableModel; } BanTableModel *ClientModel::getBanTableModel() { return banTableModel; } QString ClientModel::formatFullVersion() const { return QString::fromStdString(FormatFullVersion()); } QString ClientModel::formatSubVersion() const { return QString::fromStdString(userAgent(GetConfig())); } bool ClientModel::isReleaseVersion() const { return CLIENT_VERSION_IS_RELEASE; } QString ClientModel::formatClientStartupTime() const { return QDateTime::fromTime_t(GetStartupTime()).toString(); } QString ClientModel::dataDir() const { return GUIUtil::boostPathToQString(GetDataDir()); } QString ClientModel::blocksDir() const { return GUIUtil::boostPathToQString(GetBlocksDir()); } void ClientModel::updateBanlist() { banTableModel->refresh(); } // Handlers for core signals static void ShowProgress(ClientModel *clientmodel, const std::string &title, int nProgress) { // emits signal "showProgress" bool invoked = QMetaObject::invokeMethod( clientmodel, "showProgress", Qt::QueuedConnection, Q_ARG(QString, QString::fromStdString(title)), Q_ARG(int, nProgress)); assert(invoked); } static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConnections) { // Too noisy: qDebug() << "NotifyNumConnectionsChanged: " + // QString::number(newNumConnections); bool invoked = QMetaObject::invokeMethod( clientmodel, "updateNumConnections", Qt::QueuedConnection, Q_ARG(int, newNumConnections)); assert(invoked); } static void NotifyNetworkActiveChanged(ClientModel *clientmodel, bool networkActive) { bool invoked = QMetaObject::invokeMethod(clientmodel, "updateNetworkActive", Qt::QueuedConnection, Q_ARG(bool, networkActive)); assert(invoked); } static void NotifyAlertChanged(ClientModel *clientmodel) { qDebug() << "NotifyAlertChanged"; bool invoked = QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection); assert(invoked); } static void BannedListChanged(ClientModel *clientmodel) { qDebug() << QString("%1: Requesting update for peer banlist").arg(__func__); bool invoked = QMetaObject::invokeMethod(clientmodel, "updateBanlist", Qt::QueuedConnection); assert(invoked); } static void BlockTipChanged(ClientModel *clientmodel, SynchronizationState sync_state, - const BlockHash block_hash, int height, - int64_t blockTime, double verificationProgress, - bool fHeader) { + interfaces::BlockTip tip, + double verificationProgress, bool fHeader) { if (fHeader) { // cache best headers time and height to reduce future cs_main locks - clientmodel->cachedBestHeaderHeight = height; - clientmodel->cachedBestHeaderTime = blockTime; + clientmodel->cachedBestHeaderHeight = tip.block_height; + clientmodel->cachedBestHeaderTime = tip.block_time; } else { - clientmodel->m_cached_num_blocks = height; + clientmodel->m_cached_num_blocks = tip.block_height; WITH_LOCK(clientmodel->m_cached_tip_mutex, - clientmodel->m_cached_tip_blocks = block_hash;); + clientmodel->m_cached_tip_blocks = tip.block_hash;); } // Throttle GUI notifications about (a) blocks during initial sync, and (b) // both blocks and headers during reindex. const bool throttle = (sync_state != SynchronizationState::POST_INIT && !fHeader) || sync_state == SynchronizationState::INIT_REINDEX; const int64_t now = throttle ? GetTimeMillis() : 0; int64_t &nLastUpdateNotification = fHeader ? nLastHeaderTipUpdateNotification : nLastBlockTipUpdateNotification; if (throttle && now < nLastUpdateNotification + MODEL_UPDATE_DELAY) { return; } bool invoked = QMetaObject::invokeMethod( clientmodel, "numBlocksChanged", Qt::QueuedConnection, - Q_ARG(int, height), Q_ARG(QDateTime, QDateTime::fromTime_t(blockTime)), + Q_ARG(int, tip.block_height), + Q_ARG(QDateTime, QDateTime::fromTime_t(tip.block_time)), Q_ARG(double, verificationProgress), Q_ARG(bool, fHeader), Q_ARG(SynchronizationState, sync_state)); assert(invoked); nLastUpdateNotification = now; } void ClientModel::subscribeToCoreSignals() { // Connect signals to client m_handler_show_progress = m_node.handleShowProgress(std::bind( ShowProgress, this, std::placeholders::_1, std::placeholders::_2)); m_handler_notify_num_connections_changed = m_node.handleNotifyNumConnectionsChanged(std::bind( NotifyNumConnectionsChanged, this, std::placeholders::_1)); m_handler_notify_network_active_changed = m_node.handleNotifyNetworkActiveChanged( std::bind(NotifyNetworkActiveChanged, this, std::placeholders::_1)); m_handler_notify_alert_changed = m_node.handleNotifyAlertChanged(std::bind(NotifyAlertChanged, this)); m_handler_banned_list_changed = m_node.handleBannedListChanged(std::bind(BannedListChanged, this)); m_handler_notify_block_tip = m_node.handleNotifyBlockTip( std::bind(BlockTipChanged, this, std::placeholders::_1, - std::placeholders::_2, std::placeholders::_3, - std::placeholders::_4, std::placeholders::_5, false)); + std::placeholders::_2, std::placeholders::_3, false)); m_handler_notify_header_tip = m_node.handleNotifyHeaderTip( std::bind(BlockTipChanged, this, std::placeholders::_1, - std::placeholders::_2, std::placeholders::_3, - std::placeholders::_4, std::placeholders::_5, true)); + std::placeholders::_2, std::placeholders::_3, true)); } void ClientModel::unsubscribeFromCoreSignals() { // Disconnect signals from client m_handler_show_progress->disconnect(); m_handler_notify_num_connections_changed->disconnect(); m_handler_notify_network_active_changed->disconnect(); m_handler_notify_alert_changed->disconnect(); m_handler_banned_list_changed->disconnect(); m_handler_notify_block_tip->disconnect(); m_handler_notify_header_tip->disconnect(); } bool ClientModel::getProxyInfo(std::string &ip_port) const { proxyType ipv4, ipv6; if (m_node.getProxy((Network)1, ipv4) && m_node.getProxy((Network)2, ipv6)) { ip_port = ipv4.proxy.ToStringIPPort(); return true; } return false; } diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 370f1cd71..bfbdc3c3f 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -1,130 +1,130 @@ // 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_CLIENTMODEL_H #define BITCOIN_QT_CLIENTMODEL_H #include #include #include #include #include #include class BanTableModel; class CBlockIndex; class OptionsModel; class PeerTableModel; class CBlockIndex; enum class SynchronizationState; namespace interfaces { class Handler; class Node; } // namespace interfaces QT_BEGIN_NAMESPACE class QTimer; QT_END_NAMESPACE enum class BlockSource { NONE, REINDEX, DISK, NETWORK }; /** Model for Bitcoin network client. */ class ClientModel : public QObject { Q_OBJECT public: enum NumConnections { CONNECTIONS_NONE = 0, CONNECTIONS_IN = (1U << 0), CONNECTIONS_OUT = (1U << 1), CONNECTIONS_ALL = (CONNECTIONS_IN | CONNECTIONS_OUT), }; explicit ClientModel(interfaces::Node &node, OptionsModel *optionsModel, QObject *parent = nullptr); ~ClientModel(); interfaces::Node &node() const { return m_node; } OptionsModel *getOptionsModel(); PeerTableModel *getPeerTableModel(); BanTableModel *getBanTableModel(); //! Return number of connections, default is in- and outbound (total) int getNumConnections(NumConnections flags = CONNECTIONS_ALL) const; int getNumBlocks() const; BlockHash getBestBlockHash(); int getHeaderTipHeight() const; int64_t getHeaderTipTime() const; //! Returns enum BlockSource of the current importing/syncing state enum BlockSource getBlockSource() const; //! Return warnings to be displayed in status bar QString getStatusBarWarnings() const; QString formatFullVersion() const; QString formatSubVersion() const; bool isReleaseVersion() const; QString formatClientStartupTime() const; QString dataDir() const; QString blocksDir() const; bool getProxyInfo(std::string &ip_port) const; - // caches for the best header, number of blocks + // caches for the best header: hash, number of blocks and block time mutable std::atomic cachedBestHeaderHeight; mutable std::atomic cachedBestHeaderTime; mutable std::atomic m_cached_num_blocks{-1}; Mutex m_cached_tip_mutex; BlockHash m_cached_tip_blocks GUARDED_BY(m_cached_tip_mutex){}; private: interfaces::Node &m_node; std::unique_ptr m_handler_show_progress; std::unique_ptr m_handler_notify_num_connections_changed; std::unique_ptr m_handler_notify_network_active_changed; std::unique_ptr m_handler_notify_alert_changed; std::unique_ptr m_handler_banned_list_changed; std::unique_ptr m_handler_notify_block_tip; std::unique_ptr m_handler_notify_header_tip; OptionsModel *optionsModel; PeerTableModel *peerTableModel; BanTableModel *banTableModel; //! A thread to interact with m_node asynchronously QThread *const m_thread; void subscribeToCoreSignals(); void unsubscribeFromCoreSignals(); Q_SIGNALS: void numConnectionsChanged(int count); void numBlocksChanged(int count, const QDateTime &blockDate, double nVerificationProgress, bool header, SynchronizationState sync_state); void mempoolSizeChanged(long count, size_t mempoolSizeInBytes); void networkActiveChanged(bool networkActive); void alertsChanged(const QString &warnings); void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut); //! Fired when a message should be reported to the user void message(const QString &title, const QString &message, unsigned int style); // Show progress dialog e.g. for verifychain void showProgress(const QString &title, int nProgress); public Q_SLOTS: void updateNumConnections(int numConnections); void updateNetworkActive(bool networkActive); void updateAlert(); void updateBanlist(); }; #endif // BITCOIN_QT_CLIENTMODEL_H