diff options
Diffstat (limited to 'src')
87 files changed, 466 insertions, 367 deletions
diff --git a/src/chain.h b/src/chain.h index 3b786664af..5a6f10b84f 100644 --- a/src/chain.h +++ b/src/chain.h @@ -18,7 +18,7 @@ * Maximum amount of time that a block timestamp is allowed to exceed the * current network-adjusted time before the block will be accepted. */ -static const int64_t MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60; +static constexpr int64_t MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60; /** * Timestamp window used as a grace period by code that compares external @@ -26,7 +26,15 @@ static const int64_t MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60; * to block timestamps. This should be set at least as high as * MAX_FUTURE_BLOCK_TIME. */ -static const int64_t TIMESTAMP_WINDOW = MAX_FUTURE_BLOCK_TIME; +static constexpr int64_t TIMESTAMP_WINDOW = MAX_FUTURE_BLOCK_TIME; + +/** + * Maximum gap between node time and block time used + * for the "Catching up..." mode in GUI. + * + * Ref: https://github.com/bitcoin/bitcoin/pull/1026 + */ +static constexpr int64_t MAX_BLOCK_TIME_GAP = 90 * 60; class CBlockFileInfo { diff --git a/src/chainparams.cpp b/src/chainparams.cpp index d334233224..da4832dff8 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -107,6 +107,8 @@ public: pchMessageStart[3] = 0xd9; nDefaultPort = 8333; nPruneAfterHeight = 100000; + m_assumed_blockchain_size = 200; + m_assumed_chain_state_size = 3; genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN); consensus.hashGenesisBlock = genesis.GetHash(); @@ -216,6 +218,8 @@ public: pchMessageStart[3] = 0x07; nDefaultPort = 18333; nPruneAfterHeight = 1000; + m_assumed_blockchain_size = 20; + m_assumed_chain_state_size = 2; genesis = CreateGenesisBlock(1296688602, 414098458, 0x1d00ffff, 1, 50 * COIN); consensus.hashGenesisBlock = genesis.GetHash(); @@ -305,6 +309,8 @@ public: pchMessageStart[3] = 0xda; nDefaultPort = 18444; nPruneAfterHeight = 1000; + m_assumed_blockchain_size = 0; + m_assumed_chain_state_size = 0; UpdateVersionBitsParametersFromArgs(args); diff --git a/src/chainparams.h b/src/chainparams.h index 19818b40af..6ff3dbb7e5 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -67,6 +67,10 @@ public: /** Policy: Filter transactions that do not match well-defined patterns */ bool RequireStandard() const { return fRequireStandard; } uint64_t PruneAfterHeight() const { return nPruneAfterHeight; } + /** Minimum free space (in GB) needed for data directory */ + uint64_t AssumedBlockchainSize() const { return m_assumed_blockchain_size; } + /** Minimum free space (in GB) needed for data directory when pruned; Does not include prune target*/ + uint64_t AssumedChainStateSize() const { return m_assumed_chain_state_size; } /** Make miner stop after a block is found. In RPC, don't return until nGenProcLimit blocks are generated */ bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; } /** Return the BIP70 network string (main, test or regtest) */ @@ -87,6 +91,8 @@ protected: CMessageHeader::MessageStartChars pchMessageStart; int nDefaultPort; uint64_t nPruneAfterHeight; + uint64_t m_assumed_blockchain_size; + uint64_t m_assumed_chain_state_size; std::vector<std::string> vSeeds; std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES]; std::string bech32_hrp; diff --git a/src/init.cpp b/src/init.cpp index f4f00ea691..679bf80047 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -261,10 +261,10 @@ void Shutdown(InitInterfaces& interfaces) LogPrintf("%s: Unable to remove pidfile: %s\n", __func__, e.what()); } #endif + interfaces.chain_clients.clear(); UnregisterAllValidationInterfaces(); GetMainSignals().UnregisterBackgroundSignalScheduler(); GetMainSignals().UnregisterWithMempoolSignals(mempool); - interfaces.chain_clients.clear(); globalVerifyHandle.reset(); ECC_Stop(); LogPrintf("%s: done\n", __func__); @@ -1321,7 +1321,7 @@ bool AppInitMain(InitInterfaces& interfaces) for (int n = 0; n < NET_MAX; n++) { enum Network net = (enum Network)n; if (!nets.count(net)) - SetLimited(net); + SetReachable(net, false); } } @@ -1332,7 +1332,7 @@ bool AppInitMain(InitInterfaces& interfaces) // -proxy sets a proxy for all outgoing network traffic // -noproxy (or -proxy=0) as well as the empty string can be used to not set a proxy, this is the default std::string proxyArg = gArgs.GetArg("-proxy", ""); - SetLimited(NET_ONION); + SetReachable(NET_ONION, false); if (proxyArg != "" && proxyArg != "0") { CService proxyAddr; if (!Lookup(proxyArg.c_str(), proxyAddr, 9050, fNameLookup)) { @@ -1347,7 +1347,7 @@ bool AppInitMain(InitInterfaces& interfaces) SetProxy(NET_IPV6, addrProxy); SetProxy(NET_ONION, addrProxy); SetNameProxy(addrProxy); - SetLimited(NET_ONION, false); // by default, -proxy sets onion as reachable, unless -noonion later + SetReachable(NET_ONION, true); // by default, -proxy sets onion as reachable, unless -noonion later } // -onion can be used to set only a proxy for .onion, or override normal proxy for .onion addresses @@ -1356,7 +1356,7 @@ bool AppInitMain(InitInterfaces& interfaces) std::string onionArg = gArgs.GetArg("-onion", ""); if (onionArg != "") { if (onionArg == "0") { // Handle -noonion/-onion=0 - SetLimited(NET_ONION); // set onions as unreachable + SetReachable(NET_ONION, false); } else { CService onionProxy; if (!Lookup(onionArg.c_str(), onionProxy, 9050, fNameLookup)) { @@ -1366,7 +1366,7 @@ bool AppInitMain(InitInterfaces& interfaces) if (!addrOnion.IsValid()) return InitError(strprintf(_("Invalid -onion address or hostname: '%s'"), onionArg)); SetProxy(NET_ONION, addrOnion); - SetLimited(NET_ONION, false); + SetReachable(NET_ONION, true); } } diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp index bd7e414ff3..acba05fd5e 100644 --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -60,6 +60,8 @@ public: bool softSetArg(const std::string& arg, const std::string& value) override { return gArgs.SoftSetArg(arg, value); } bool softSetBoolArg(const std::string& arg, bool value) override { return gArgs.SoftSetBoolArg(arg, value); } void selectParams(const std::string& network) override { SelectParams(network); } + uint64_t getAssumedBlockchainSize() override { return Params().AssumedBlockchainSize(); } + uint64_t getAssumedChainStateSize() override { return Params().AssumedChainStateSize(); } std::string getNetwork() override { return Params().NetworkIDString(); } void initLogging() override { InitLogging(); } void initParameterInteraction() override { InitParameterInteraction(); } diff --git a/src/interfaces/node.h b/src/interfaces/node.h index 1f8bbbff7a..7fa5958c51 100644 --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -52,6 +52,12 @@ public: //! Choose network parameters. virtual void selectParams(const std::string& network) = 0; + //! Get the (assumed) blockchain size. + virtual uint64_t getAssumedBlockchainSize() = 0; + + //! Get the (assumed) chain state size. + virtual uint64_t getAssumedChainStateSize() = 0; + //! Get network name. virtual std::string getNetwork() = 0; diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp index 672a557d41..8db34ed759 100644 --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -318,7 +318,8 @@ public: } bool tryGetTxStatus(const uint256& txid, interfaces::WalletTxStatus& tx_status, - int& num_blocks) override + int& num_blocks, + int64_t& block_time) override { auto locked_chain = m_wallet.chain().lock(true /* try_lock */); if (!locked_chain) { @@ -333,6 +334,7 @@ public: return false; } num_blocks = ::chainActive.Height(); + block_time = ::chainActive.Tip()->GetBlockTime(); tx_status = MakeWalletTxStatus(*locked_chain, mi->second); return true; } diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index c79b9afce3..da60684a4f 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -178,7 +178,8 @@ public: //! Try to get updated status for a particular transaction, if possible without blocking. virtual bool tryGetTxStatus(const uint256& txid, WalletTxStatus& tx_status, - int& num_blocks) = 0; + int& num_blocks, + int64_t& block_time) = 0; //! Get transaction details. virtual WalletTx getWalletTxDetails(const uint256& txid, diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp index 0c37bab1f8..a54268d655 100644 --- a/src/merkleblock.cpp +++ b/src/merkleblock.cpp @@ -53,7 +53,7 @@ uint256 CPartialMerkleTree::CalcHash(int height, unsigned int pos, const std::ve else right = left; // combine subhashes - return Hash(BEGIN(left), END(left), BEGIN(right), END(right)); + return Hash(left.begin(), left.end(), right.begin(), right.end()); } } @@ -109,7 +109,7 @@ uint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, uns right = left; } // and combine them before returning - return Hash(BEGIN(left), END(left), BEGIN(right), END(right)); + return Hash(left.begin(), left.end(), right.begin(), right.end()); } } diff --git a/src/net.cpp b/src/net.cpp index 86e5225839..98bd518ecc 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -183,7 +183,7 @@ bool IsPeerAddrLocalGood(CNode *pnode) { CService addrLocal = pnode->GetAddrLocal(); return fDiscover && pnode->addr.IsRoutable() && addrLocal.IsRoutable() && - !IsLimited(addrLocal.GetNetwork()); + IsReachable(addrLocal.GetNetwork()); } // pushes our own address to a peer @@ -222,7 +222,7 @@ bool AddLocal(const CService& addr, int nScore) if (!fDiscover && nScore < LOCAL_MANUAL) return false; - if (IsLimited(addr)) + if (!IsReachable(addr)) return false; LogPrintf("AddLocal(%s,%i)\n", addr.ToString(), nScore); @@ -252,24 +252,23 @@ void RemoveLocal(const CService& addr) mapLocalHost.erase(addr); } -/** Make a particular network entirely off-limits (no automatic connects to it) */ -void SetLimited(enum Network net, bool fLimited) +void SetReachable(enum Network net, bool reachable) { if (net == NET_UNROUTABLE || net == NET_INTERNAL) return; LOCK(cs_mapLocalHost); - vfLimited[net] = fLimited; + vfLimited[net] = !reachable; } -bool IsLimited(enum Network net) +bool IsReachable(enum Network net) { LOCK(cs_mapLocalHost); - return vfLimited[net]; + return !vfLimited[net]; } -bool IsLimited(const CNetAddr &addr) +bool IsReachable(const CNetAddr &addr) { - return IsLimited(addr.GetNetwork()); + return IsReachable(addr.GetNetwork()); } /** vote for a local address */ @@ -292,19 +291,6 @@ bool IsLocal(const CService& addr) return mapLocalHost.count(addr) > 0; } -/** check whether a given network is one we can probably connect to */ -bool IsReachable(enum Network net) -{ - return !IsLimited(net); -} - -/** check whether a given address is in a network we can probably connect to */ -bool IsReachable(const CNetAddr& addr) -{ - return IsReachable(addr.GetNetwork()); -} - - CNode* CConnman::FindNode(const CNetAddr& ip) { LOCK(cs_vNodes); @@ -1965,7 +1951,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) if (nTries > 100) break; - if (IsLimited(addr)) + if (!IsReachable(addr)) continue; // only consider very recently tried nodes after 30 failed attempts @@ -2327,7 +2313,7 @@ NodeId CConnman::GetNewNodeId() bool CConnman::Bind(const CService &addr, unsigned int flags) { - if (!(flags & BF_EXPLICIT) && IsLimited(addr)) + if (!(flags & BF_EXPLICIT) && !IsReachable(addr)) return false; std::string strError; if (!BindListenPort(addr, strError, (flags & BF_WHITELIST) != 0)) { @@ -2794,8 +2780,8 @@ int CConnman::GetBestHeight() const unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; } -CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress &addrBindIn, const std::string& addrNameIn, bool fInboundIn) : - nTimeConnected(GetSystemTimeInSeconds()), +CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress& addrBindIn, const std::string& addrNameIn, bool fInboundIn) + : nTimeConnected(GetSystemTimeInSeconds()), addr(addrIn), addrBind(addrBindIn), fInbound(fInboundIn), @@ -2805,56 +2791,14 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn id(idIn), nLocalHostNonce(nLocalHostNonceIn), nLocalServices(nLocalServicesIn), - nMyStartingHeight(nMyStartingHeightIn), - nSendVersion(0) + nMyStartingHeight(nMyStartingHeightIn) { - nServices = NODE_NONE; hSocket = hSocketIn; - nRecvVersion = INIT_PROTO_VERSION; - nLastSend = 0; - nLastRecv = 0; - nSendBytes = 0; - nRecvBytes = 0; - nTimeOffset = 0; addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn; - nVersion = 0; strSubVer = ""; - fWhitelisted = false; - fOneShot = false; - m_manual_connection = false; - fClient = false; // set by version message - m_limited_node = false; // set by version message - fFeeler = false; - fSuccessfullyConnected = false; - fDisconnect = false; - nRefCount = 0; - nSendSize = 0; - nSendOffset = 0; hashContinue = uint256(); - nStartingHeight = -1; filterInventoryKnown.reset(); - fSendMempool = false; - fGetAddr = false; - nNextLocalAddrSend = 0; - nNextAddrSend = 0; - nNextInvSend = 0; - fRelayTxes = false; - fSentAddr = false; pfilter = MakeUnique<CBloomFilter>(); - timeLastMempoolReq = 0; - nLastBlockTime = 0; - nLastTXTime = 0; - nPingNonceSent = 0; - nPingUsecStart = 0; - nPingUsecTime = 0; - fPingQueued = false; - nMinPingUsecTime = std::numeric_limits<int64_t>::max(); - minFeeFilter = 0; - lastSentFeeFilter = 0; - nextSendTimeFeeFilter = 0; - fPauseRecv = false; - fPauseSend = false; - nProcessQueueSize = 0; for (const std::string &msg : getAllNetMessageTypes()) mapRecvBytesPerMsgCmd[msg] = 0; @@ -520,17 +520,23 @@ enum bool IsPeerAddrLocalGood(CNode *pnode); void AdvertiseLocal(CNode *pnode); -void SetLimited(enum Network net, bool fLimited = true); -bool IsLimited(enum Network net); -bool IsLimited(const CNetAddr& addr); + +/** + * Mark a network as reachable or unreachable (no automatic connects to it) + * @note Networks are reachable by default + */ +void SetReachable(enum Network net, bool reachable); +/** @returns true if the network is reachable, false otherwise */ +bool IsReachable(enum Network net); +/** @returns true if the address is in a reachable network, false otherwise */ +bool IsReachable(const CNetAddr& addr); + bool AddLocal(const CService& addr, int nScore = LOCAL_NONE); bool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE); void RemoveLocal(const CService& addr); bool SeenLocal(const CService& addr); bool IsLocal(const CService& addr); bool GetLocal(CService &addr, const CNetAddr *paddrPeer = nullptr); -bool IsReachable(enum Network net); -bool IsReachable(const CNetAddr &addr); CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices); @@ -640,11 +646,11 @@ class CNode friend class CConnman; public: // socket - std::atomic<ServiceFlags> nServices; + std::atomic<ServiceFlags> nServices{NODE_NONE}; SOCKET hSocket GUARDED_BY(cs_hSocket); - size_t nSendSize; // total size of all vSendMsg entries - size_t nSendOffset; // offset inside the first vSendMsg already sent - uint64_t nSendBytes GUARDED_BY(cs_vSend); + size_t nSendSize{0}; // total size of all vSendMsg entries + size_t nSendOffset{0}; // offset inside the first vSendMsg already sent + uint64_t nSendBytes GUARDED_BY(cs_vSend){0}; std::deque<std::vector<unsigned char>> vSendMsg GUARDED_BY(cs_vSend); CCriticalSection cs_vSend; CCriticalSection cs_hSocket; @@ -652,52 +658,52 @@ public: CCriticalSection cs_vProcessMsg; std::list<CNetMessage> vProcessMsg GUARDED_BY(cs_vProcessMsg); - size_t nProcessQueueSize; + size_t nProcessQueueSize{0}; CCriticalSection cs_sendProcessing; std::deque<CInv> vRecvGetData; - uint64_t nRecvBytes GUARDED_BY(cs_vRecv); - std::atomic<int> nRecvVersion; + uint64_t nRecvBytes GUARDED_BY(cs_vRecv){0}; + std::atomic<int> nRecvVersion{INIT_PROTO_VERSION}; - std::atomic<int64_t> nLastSend; - std::atomic<int64_t> nLastRecv; + std::atomic<int64_t> nLastSend{0}; + std::atomic<int64_t> nLastRecv{0}; const int64_t nTimeConnected; - std::atomic<int64_t> nTimeOffset; + std::atomic<int64_t> nTimeOffset{0}; // Address of this peer const CAddress addr; // Bind address of our side of the connection const CAddress addrBind; - std::atomic<int> nVersion; + std::atomic<int> nVersion{0}; // strSubVer is whatever byte array we read from the wire. However, this field is intended // to be printed out, displayed to humans in various forms and so on. So we sanitize it and // store the sanitized version in cleanSubVer. The original should be used when dealing with // the network or wire types and the cleaned string used when displayed or logged. std::string strSubVer GUARDED_BY(cs_SubVer), cleanSubVer GUARDED_BY(cs_SubVer); CCriticalSection cs_SubVer; // used for both cleanSubVer and strSubVer - bool fWhitelisted; // This peer can bypass DoS banning. - bool fFeeler; // If true this node is being used as a short lived feeler. - bool fOneShot; - bool m_manual_connection; - bool fClient; - bool m_limited_node; //after BIP159 + bool fWhitelisted{false}; // This peer can bypass DoS banning. + bool fFeeler{false}; // If true this node is being used as a short lived feeler. + bool fOneShot{false}; + bool m_manual_connection{false}; + bool fClient{false}; // set by version message + bool m_limited_node{false}; //after BIP159, set by version message const bool fInbound; - std::atomic_bool fSuccessfullyConnected; - std::atomic_bool fDisconnect; + std::atomic_bool fSuccessfullyConnected{false}; + std::atomic_bool fDisconnect{false}; // We use fRelayTxes for two purposes - // a) it allows us to not relay tx invs before receiving the peer's version message // b) the peer may tell us in its version message that we should not relay tx invs // unless it loads a bloom filter. - bool fRelayTxes GUARDED_BY(cs_filter); - bool fSentAddr; + bool fRelayTxes GUARDED_BY(cs_filter){false}; + bool fSentAddr{false}; CSemaphoreGrant grantOutbound; mutable CCriticalSection cs_filter; std::unique_ptr<CBloomFilter> pfilter PT_GUARDED_BY(cs_filter); - std::atomic<int> nRefCount; + std::atomic<int> nRefCount{0}; const uint64_t nKeyedNetGroup; - std::atomic_bool fPauseRecv; - std::atomic_bool fPauseSend; + std::atomic_bool fPauseRecv{false}; + std::atomic_bool fPauseSend{false}; protected: mapMsgCmdSize mapSendBytesPerMsgCmd; @@ -705,15 +711,15 @@ protected: public: uint256 hashContinue; - std::atomic<int> nStartingHeight; + std::atomic<int> nStartingHeight{-1}; // flood relay std::vector<CAddress> vAddrToSend; CRollingBloomFilter addrKnown; - bool fGetAddr; + bool fGetAddr{false}; std::set<uint256> setKnown; - int64_t nNextAddrSend GUARDED_BY(cs_sendProcessing); - int64_t nNextLocalAddrSend GUARDED_BY(cs_sendProcessing); + int64_t nNextAddrSend GUARDED_BY(cs_sendProcessing){0}; + int64_t nNextLocalAddrSend GUARDED_BY(cs_sendProcessing){0}; // inventory based relay CRollingBloomFilter filterInventoryKnown GUARDED_BY(cs_inventory); @@ -727,35 +733,35 @@ public: CCriticalSection cs_inventory; std::set<uint256> setAskFor; std::multimap<int64_t, CInv> mapAskFor; - int64_t nNextInvSend; + int64_t nNextInvSend{0}; // Used for headers announcements - unfiltered blocks to relay std::vector<uint256> vBlockHashesToAnnounce GUARDED_BY(cs_inventory); // Used for BIP35 mempool sending - bool fSendMempool GUARDED_BY(cs_inventory); + bool fSendMempool GUARDED_BY(cs_inventory){false}; // Last time a "MEMPOOL" request was serviced. - std::atomic<int64_t> timeLastMempoolReq; + std::atomic<int64_t> timeLastMempoolReq{0}; // Block and TXN accept times - std::atomic<int64_t> nLastBlockTime; - std::atomic<int64_t> nLastTXTime; + std::atomic<int64_t> nLastBlockTime{0}; + std::atomic<int64_t> nLastTXTime{0}; // Ping time measurement: // The pong reply we're expecting, or 0 if no pong expected. - std::atomic<uint64_t> nPingNonceSent; + std::atomic<uint64_t> nPingNonceSent{0}; // Time (in usec) the last ping was sent, or 0 if no ping was ever sent. - std::atomic<int64_t> nPingUsecStart; + std::atomic<int64_t> nPingUsecStart{0}; // Last measured round-trip time. - std::atomic<int64_t> nPingUsecTime; + std::atomic<int64_t> nPingUsecTime{0}; // Best measured round-trip time. - std::atomic<int64_t> nMinPingUsecTime; + std::atomic<int64_t> nMinPingUsecTime{std::numeric_limits<int64_t>::max()}; // Whether a ping is requested. - std::atomic<bool> fPingQueued; + std::atomic<bool> fPingQueued{false}; // Minimum fee rate with which to filter inv's to this node - CAmount minFeeFilter GUARDED_BY(cs_feeFilter); + CAmount minFeeFilter GUARDED_BY(cs_feeFilter){0}; CCriticalSection cs_feeFilter; - CAmount lastSentFeeFilter; - int64_t nextSendTimeFeeFilter; + CAmount lastSentFeeFilter{0}; + int64_t nextSendTimeFeeFilter{0}; CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress &addrBindIn, const std::string &addrNameIn = "", bool fInboundIn = false); ~CNode(); @@ -768,7 +774,7 @@ private: // Services offered to this peer const ServiceFlags nLocalServices; const int nMyStartingHeight; - int nSendVersion; + int nSendVersion{0}; std::list<CNetMessage> vRecvMsg; // Used only by SocketHandler thread mutable CCriticalSection cs_addrName; diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index 26bdf60d4a..726dafccb0 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -59,7 +59,7 @@ protected: AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode _mode, Tabs _tab, QWidget *parent) : QDialog(parent), ui(new Ui::AddressBookPage), - model(0), + model(nullptr), mode(_mode), tab(_tab) { diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h index 32ab2dfeb5..6394d26801 100644 --- a/src/qt/addressbookpage.h +++ b/src/qt/addressbookpage.h @@ -38,7 +38,7 @@ public: ForEditing /**< Open address book for editing */ }; - explicit AddressBookPage(const PlatformStyle *platformStyle, Mode mode, Tabs tab, QWidget *parent = 0); + explicit AddressBookPage(const PlatformStyle *platformStyle, Mode mode, Tabs tab, QWidget *parent = nullptr); ~AddressBookPage(); void setModel(AddressTableModel *model); diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 2f88e15d21..c3143e948a 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -153,7 +153,7 @@ public: } else { - return 0; + return nullptr; } } }; @@ -300,8 +300,8 @@ QVariant AddressTableModel::headerData(int section, Qt::Orientation orientation, Qt::ItemFlags AddressTableModel::flags(const QModelIndex &index) const { - if(!index.isValid()) - return 0; + if (!index.isValid()) return Qt::NoItemFlags; + AddressTableEntry *rec = static_cast<AddressTableEntry*>(index.internalPointer()); Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled; diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h index 41bed4e290..035f3e0571 100644 --- a/src/qt/addresstablemodel.h +++ b/src/qt/addresstablemodel.h @@ -25,7 +25,7 @@ class AddressTableModel : public QAbstractTableModel Q_OBJECT public: - explicit AddressTableModel(WalletModel *parent = 0); + explicit AddressTableModel(WalletModel *parent = nullptr); ~AddressTableModel(); enum ColumnIndex { diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index 821c23c467..a89a15bc9d 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -22,7 +22,7 @@ AskPassphraseDialog::AskPassphraseDialog(Mode _mode, QWidget *parent) : QDialog(parent), ui(new Ui::AskPassphraseDialog), mode(_mode), - model(0), + model(nullptr), fCapsLock(false) { ui->setupUi(this); diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp index 713db595d5..00c446cc63 100644 --- a/src/qt/bantablemodel.cpp +++ b/src/qt/bantablemodel.cpp @@ -76,7 +76,7 @@ public: if (idx >= 0 && idx < cachedBanlist.size()) return &cachedBanlist[idx]; - return 0; + return nullptr; } }; @@ -145,8 +145,7 @@ QVariant BanTableModel::headerData(int section, Qt::Orientation orientation, int Qt::ItemFlags BanTableModel::flags(const QModelIndex &index) const { - if(!index.isValid()) - return 0; + if (!index.isValid()) return Qt::NoItemFlags; Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled; return retval; diff --git a/src/qt/bantablemodel.h b/src/qt/bantablemodel.h index b8505b599f..9dec5fa6a9 100644 --- a/src/qt/bantablemodel.h +++ b/src/qt/bantablemodel.h @@ -45,7 +45,7 @@ class BanTableModel : public QAbstractTableModel Q_OBJECT public: - explicit BanTableModel(interfaces::Node& node, ClientModel *parent = 0); + explicit BanTableModel(interfaces::Node& node, ClientModel *parent = nullptr); ~BanTableModel(); void startAutoRefresh(); void stopAutoRefresh(); diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 6e08dae3c4..893dda1601 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -178,18 +178,18 @@ void BitcoinCore::shutdown() BitcoinApplication::BitcoinApplication(interfaces::Node& node, int &argc, char **argv): QApplication(argc, argv), - coreThread(0), + coreThread(nullptr), m_node(node), - optionsModel(0), - clientModel(0), - window(0), - pollShutdownTimer(0), + optionsModel(nullptr), + clientModel(nullptr), + window(nullptr), + pollShutdownTimer(nullptr), #ifdef ENABLE_WALLET - paymentServer(0), + paymentServer(nullptr), m_wallet_models(), #endif returnValue(0), - platformStyle(0) + platformStyle(nullptr) { setQuitOnLastWindowClosed(false); } @@ -218,15 +218,15 @@ BitcoinApplication::~BitcoinApplication() } delete window; - window = 0; + window = nullptr; #ifdef ENABLE_WALLET delete paymentServer; - paymentServer = 0; + paymentServer = nullptr; #endif delete optionsModel; - optionsModel = 0; + optionsModel = nullptr; delete platformStyle; - platformStyle = 0; + platformStyle = nullptr; } #ifdef ENABLE_WALLET @@ -243,7 +243,7 @@ void BitcoinApplication::createOptionsModel(bool resetSettings) void BitcoinApplication::createWindow(const NetworkStyle *networkStyle) { - window = new BitcoinGUI(m_node, platformStyle, networkStyle, 0); + window = new BitcoinGUI(m_node, platformStyle, networkStyle, nullptr); pollShutdownTimer = new QTimer(window); connect(pollShutdownTimer, &QTimer::timeout, window, &BitcoinGUI::detectShutdown); @@ -251,7 +251,7 @@ void BitcoinApplication::createWindow(const NetworkStyle *networkStyle) void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle) { - SplashScreen *splash = new SplashScreen(m_node, 0, networkStyle); + SplashScreen *splash = new SplashScreen(m_node, nullptr, networkStyle); // We don't hold a direct pointer to the splash screen after creation, but the splash // screen will take care of deleting itself when finish() happens. splash->show(); @@ -312,7 +312,7 @@ void BitcoinApplication::requestShutdown() qDebug() << __func__ << ": Requesting shutdown"; startThread(); window->hide(); - window->setClientModel(0); + window->setClientModel(nullptr); pollShutdownTimer->stop(); #ifdef ENABLE_WALLET @@ -323,7 +323,7 @@ void BitcoinApplication::requestShutdown() m_wallet_models.clear(); #endif delete clientModel; - clientModel = 0; + clientModel = nullptr; m_node.startShutdown(); @@ -429,7 +429,7 @@ void BitcoinApplication::shutdownResult() void BitcoinApplication::handleRunawayException(const QString &message) { - QMessageBox::critical(0, "Runaway exception", BitcoinGUI::tr("A fatal error occurred. Bitcoin can no longer continue safely and will quit.") + QString("\n\n") + message); + QMessageBox::critical(nullptr, "Runaway exception", BitcoinGUI::tr("A fatal error occurred. Bitcoin can no longer continue safely and will quit.") + QString("\n\n") + message); ::exit(EXIT_FAILURE); } @@ -503,7 +503,7 @@ int GuiMain(int argc, char* argv[]) SetupUIArgs(); std::string error; if (!node->parseParameters(argc, argv, error)) { - QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), + QMessageBox::critical(nullptr, QObject::tr(PACKAGE_NAME), QObject::tr("Error parsing command line arguments: %1.").arg(QString::fromStdString(error))); return EXIT_FAILURE; } @@ -540,12 +540,12 @@ int GuiMain(int argc, char* argv[]) /// - Do not call GetDataDir(true) before this step finishes if (!fs::is_directory(GetDataDir(false))) { - QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), - QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(gArgs.GetArg("-datadir", "")))); + QMessageBox::critical(nullptr, QObject::tr(PACKAGE_NAME), + QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(gArgs.GetArg("-datadir", "")))); return EXIT_FAILURE; } if (!node->readConfigFiles(error)) { - QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), + QMessageBox::critical(nullptr, QObject::tr(PACKAGE_NAME), QObject::tr("Error: Cannot parse configuration file: %1.").arg(QString::fromStdString(error))); return EXIT_FAILURE; } @@ -560,7 +560,7 @@ int GuiMain(int argc, char* argv[]) try { node->selectParams(gArgs.GetChainName()); } catch(std::exception &e) { - QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), QObject::tr("Error: %1").arg(e.what())); + QMessageBox::critical(nullptr, QObject::tr(PACKAGE_NAME), QObject::tr("Error: %1").arg(e.what())); return EXIT_FAILURE; } #ifdef ENABLE_WALLET diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index 558fcf50ba..5854ade655 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -60,7 +60,7 @@ public: } } - CAmount value(bool *valid_out=0) const + CAmount value(bool *valid_out=nullptr) const { return parse(text(), valid_out); } @@ -159,7 +159,7 @@ private: * return validity. * @note Must return 0 if !valid. */ - CAmount parse(const QString &text, bool *valid_out=0) const + CAmount parse(const QString &text, bool *valid_out=nullptr) const { CAmount val = 0; bool valid = BitcoinUnits::parse(currentUnit, text, &val); @@ -196,7 +196,7 @@ protected: if (text().isEmpty()) // Allow step-up with empty field return StepUpEnabled; - StepEnabled rv = 0; + StepEnabled rv = StepNone; bool valid = false; CAmount val = value(&valid); if (valid) { @@ -216,7 +216,7 @@ Q_SIGNALS: BitcoinAmountField::BitcoinAmountField(QWidget *parent) : QWidget(parent), - amount(0) + amount(nullptr) { amount = new AmountSpinBox(this); amount->setLocale(QLocale::c()); diff --git a/src/qt/bitcoinamountfield.h b/src/qt/bitcoinamountfield.h index 650481e30d..2db6b65f2c 100644 --- a/src/qt/bitcoinamountfield.h +++ b/src/qt/bitcoinamountfield.h @@ -26,9 +26,9 @@ class BitcoinAmountField: public QWidget Q_PROPERTY(qint64 value READ value WRITE setValue NOTIFY valueChanged USER true) public: - explicit BitcoinAmountField(QWidget *parent = 0); + explicit BitcoinAmountField(QWidget *parent = nullptr); - CAmount value(bool *value=0) const; + CAmount value(bool *value=nullptr) const; void setValue(const CAmount& value); /** If allow empty is set to false the field will be set to the minimum allowed value if left empty. **/ diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 155f8efe7f..e51aa02837 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -28,6 +28,7 @@ #include <qt/macdockiconhandler.h> #endif +#include <chain.h> #include <chainparams.h> #include <interfaces/handler.h> #include <interfaces/node.h> @@ -35,6 +36,7 @@ #include <util/system.h> #include <iostream> +#include <memory> #include <QAction> #include <QApplication> @@ -43,6 +45,7 @@ #include <QDesktopWidget> #include <QDragEnterEvent> #include <QListWidget> +#include <QMenu> #include <QMenuBar> #include <QMessageBox> #include <QMimeData> @@ -52,6 +55,7 @@ #include <QStackedWidget> #include <QStatusBar> #include <QStyle> +#include <QSystemTrayIcon> #include <QTimer> #include <QToolBar> #include <QUrlQuery> @@ -72,6 +76,7 @@ const std::string BitcoinGUI::DEFAULT_UIPLATFORM = BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformStyle, const NetworkStyle *networkStyle, QWidget *parent) : QMainWindow(parent), m_node(node), + trayIconMenu{new QMenu()}, platformStyle(_platformStyle) { QSettings settings; @@ -95,7 +100,7 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty setWindowIcon(networkStyle->getTrayAndWindowIcon()); setWindowTitle(windowTitle); - rpcConsole = new RPCConsole(node, _platformStyle, 0); + rpcConsole = new RPCConsole(node, _platformStyle, nullptr); helpMessageDialog = new HelpMessageDialog(node, this, false); #ifdef ENABLE_WALLET if(enableWallet) @@ -657,16 +662,12 @@ void BitcoinGUI::createTrayIconMenu() if (!trayIcon) return; - trayIconMenu = new QMenu(this); - trayIcon->setContextMenu(trayIconMenu); - + trayIcon->setContextMenu(trayIconMenu.get()); connect(trayIcon, &QSystemTrayIcon::activated, this, &BitcoinGUI::trayIconActivated); #else // Note: On macOS, the Dock icon is used to provide the tray's functionality. MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance(); connect(dockIconHandler, &MacDockIconHandler::dockIconClicked, this, &BitcoinGUI::macosDockIconActivated); - - trayIconMenu = new QMenu(this); trayIconMenu->setAsDockMenu(); #endif @@ -901,8 +902,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer tooltip = tr("Processed %n block(s) of transaction history.", "", count); // Set icon state: spinning if catching up, tick otherwise - if(secs < 90*60) - { + if (secs < MAX_BLOCK_TIME_GAP) { tooltip = tr("Up to date") + QString(".<br>") + tooltip; labelBlocksIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); @@ -1196,7 +1196,7 @@ void BitcoinGUI::updateProxyIcon() bool proxy_enabled = clientModel->getProxyInfo(ip_port); if (proxy_enabled) { - if (labelProxyIcon->pixmap() == 0) { + if (labelProxyIcon->pixmap() == nullptr) { QString ip_port_q = QString::fromStdString(ip_port); labelProxyIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/proxy").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); labelProxyIcon->setToolTip(tr("Proxy is <b>enabled</b>: %1").arg(ip_port_q)); @@ -1242,7 +1242,7 @@ void BitcoinGUI::showProgress(const QString &title, int nProgress) progressDialog = new QProgressDialog(title, "", 0, 100); progressDialog->setWindowModality(Qt::ApplicationModal); progressDialog->setMinimumDuration(0); - progressDialog->setCancelButton(0); + progressDialog->setCancelButton(nullptr); progressDialog->setAutoClose(false); progressDialog->setValue(0); } @@ -1304,8 +1304,8 @@ void BitcoinGUI::unsubscribeFromCoreSignals() } UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle *platformStyle) : - optionsModel(0), - menu(0) + optionsModel(nullptr), + menu(nullptr) { createContextMenu(); setToolTip(tr("Unit to show amounts in. Click to select another unit.")); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 9ca9e4c926..4e52322521 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -16,7 +16,6 @@ #include <QLabel> #include <QMainWindow> #include <QMap> -#include <QMenu> #include <QPoint> #include <QSystemTrayIcon> @@ -47,6 +46,7 @@ class Node; QT_BEGIN_NAMESPACE class QAction; class QComboBox; +class QMenu; class QProgressBar; class QProgressDialog; QT_END_NAMESPACE @@ -67,7 +67,7 @@ class BitcoinGUI : public QMainWindow public: static const std::string DEFAULT_UIPLATFORM; - explicit BitcoinGUI(interfaces::Node& node, const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent = 0); + explicit BitcoinGUI(interfaces::Node& node, const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent = nullptr); ~BitcoinGUI(); /** Set the client model. @@ -146,7 +146,7 @@ private: QComboBox* m_wallet_selector = nullptr; QSystemTrayIcon* trayIcon = nullptr; - QMenu* trayIconMenu = nullptr; + const std::unique_ptr<QMenu> trayIconMenu; Notificator* notificator = nullptr; RPCConsole* rpcConsole = nullptr; HelpMessageDialog* helpMessageDialog = nullptr; diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 217326f818..30d9e977b8 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -35,9 +35,9 @@ ClientModel::ClientModel(interfaces::Node& node, OptionsModel *_optionsModel, QO QObject(parent), m_node(node), optionsModel(_optionsModel), - peerTableModel(0), - banTableModel(0), - pollTimer(0) + peerTableModel(nullptr), + banTableModel(nullptr), + pollTimer(nullptr) { cachedBestHeaderHeight = -1; cachedBestHeaderTime = -1; diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 79e7074cca..95f4521f06 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -46,7 +46,7 @@ class ClientModel : public QObject Q_OBJECT public: - explicit ClientModel(interfaces::Node& node, OptionsModel *optionsModel, QObject *parent = 0); + explicit ClientModel(interfaces::Node& node, OptionsModel *optionsModel, QObject *parent = nullptr); ~ClientModel(); interfaces::Node& node() const { return m_node; } diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 77f8bcf901..0d9f1adcd2 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -49,7 +49,7 @@ bool CCoinControlWidgetItem::operator<(const QTreeWidgetItem &other) const { CoinControlDialog::CoinControlDialog(const PlatformStyle *_platformStyle, QWidget *parent) : QDialog(parent), ui(new Ui::CoinControlDialog), - model(0), + model(nullptr), platformStyle(_platformStyle) { ui->setupUi(this); diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index 8f15ae4b20..efc06a7656 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -43,7 +43,7 @@ class CoinControlDialog : public QDialog Q_OBJECT public: - explicit CoinControlDialog(const PlatformStyle *platformStyle, QWidget *parent = 0); + explicit CoinControlDialog(const PlatformStyle *platformStyle, QWidget *parent = nullptr); ~CoinControlDialog(); void setModel(WalletModel *model); diff --git a/src/qt/coincontroltreewidget.h b/src/qt/coincontroltreewidget.h index 62645fcdb0..88fc8b704f 100644 --- a/src/qt/coincontroltreewidget.h +++ b/src/qt/coincontroltreewidget.h @@ -13,7 +13,7 @@ class CoinControlTreeWidget : public QTreeWidget Q_OBJECT public: - explicit CoinControlTreeWidget(QWidget *parent = 0); + explicit CoinControlTreeWidget(QWidget *parent = nullptr); protected: virtual void keyPressEvent(QKeyEvent *event); diff --git a/src/qt/csvmodelwriter.cpp b/src/qt/csvmodelwriter.cpp index fe63fed52c..656afb6e87 100644 --- a/src/qt/csvmodelwriter.cpp +++ b/src/qt/csvmodelwriter.cpp @@ -10,7 +10,7 @@ CSVModelWriter::CSVModelWriter(const QString &_filename, QObject *parent) : QObject(parent), - filename(_filename), model(0) + filename(_filename), model(nullptr) { } diff --git a/src/qt/csvmodelwriter.h b/src/qt/csvmodelwriter.h index edea369ad1..e8611bea35 100644 --- a/src/qt/csvmodelwriter.h +++ b/src/qt/csvmodelwriter.h @@ -20,7 +20,7 @@ class CSVModelWriter : public QObject Q_OBJECT public: - explicit CSVModelWriter(const QString &filename, QObject *parent = 0); + explicit CSVModelWriter(const QString &filename, QObject *parent = nullptr); void setModel(const QAbstractItemModel *model); void addColumn(const QString &title, int column, int role=Qt::EditRole); diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp index 0b0b96b30c..4711412ac4 100644 --- a/src/qt/editaddressdialog.cpp +++ b/src/qt/editaddressdialog.cpp @@ -15,9 +15,9 @@ EditAddressDialog::EditAddressDialog(Mode _mode, QWidget *parent) : QDialog(parent), ui(new Ui::EditAddressDialog), - mapper(0), + mapper(nullptr), mode(_mode), - model(0) + model(nullptr) { ui->setupUi(this); diff --git a/src/qt/editaddressdialog.h b/src/qt/editaddressdialog.h index fd88b45793..4d0e0709be 100644 --- a/src/qt/editaddressdialog.h +++ b/src/qt/editaddressdialog.h @@ -30,7 +30,7 @@ public: EditSendingAddress }; - explicit EditAddressDialog(Mode mode, QWidget *parent = 0); + explicit EditAddressDialog(Mode mode, QWidget *parent = nullptr); ~EditAddressDialog(); void setModel(AddressTableModel *model); diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index f1d0aa48ef..ecb770d147 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -133,7 +133,7 @@ namespace GUIUtil Q_OBJECT public: - explicit ToolTipToRichTextFilter(int size_threshold, QObject *parent = 0); + explicit ToolTipToRichTextFilter(int size_threshold, QObject *parent = nullptr); protected: bool eventFilter(QObject *obj, QEvent *evt); diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index 0b61b05318..fa9a50b1ed 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -22,10 +22,6 @@ #include <cmath> static const uint64_t GB_BYTES = 1000000000LL; -/* Minimum free space (in GB) needed for data directory */ -constexpr uint64_t BLOCK_CHAIN_SIZE = 220; -/* Minimum free space (in GB) needed for data directory when pruned; Does not include prune target */ -static const uint64_t CHAIN_STATE_SIZE = 3; /* Total required space (in GB) depending on user choice (prune, not prune) */ static uint64_t requiredSpace; @@ -114,11 +110,13 @@ void FreespaceChecker::check() } -Intro::Intro(QWidget *parent) : +Intro::Intro(QWidget *parent, uint64_t blockchain_size, uint64_t chain_state_size) : QDialog(parent), ui(new Ui::Intro), - thread(0), - signalled(false) + thread(nullptr), + signalled(false), + m_blockchain_size(blockchain_size), + m_chain_state_size(chain_state_size) { ui->setupUi(this); ui->welcomeLabel->setText(ui->welcomeLabel->text().arg(tr(PACKAGE_NAME))); @@ -126,14 +124,14 @@ Intro::Intro(QWidget *parent) : ui->lblExplanation1->setText(ui->lblExplanation1->text() .arg(tr(PACKAGE_NAME)) - .arg(BLOCK_CHAIN_SIZE) + .arg(m_blockchain_size) .arg(2009) .arg(tr("Bitcoin")) ); ui->lblExplanation2->setText(ui->lblExplanation2->text().arg(tr(PACKAGE_NAME))); uint64_t pruneTarget = std::max<int64_t>(0, gArgs.GetArg("-prune", 0)); - requiredSpace = BLOCK_CHAIN_SIZE; + requiredSpace = m_blockchain_size; QString storageRequiresMsg = tr("At least %1 GB of data will be stored in this directory, and it will grow over time."); if (pruneTarget) { uint64_t prunedGBs = std::ceil(pruneTarget * 1024 * 1024.0 / GB_BYTES); @@ -145,7 +143,7 @@ Intro::Intro(QWidget *parent) : } else { ui->lblExplanation3->setVisible(false); } - requiredSpace += CHAIN_STATE_SIZE; + requiredSpace += m_chain_state_size; ui->sizeWarningLabel->setText( tr("%1 will download and store a copy of the Bitcoin block chain.").arg(tr(PACKAGE_NAME)) + " " + storageRequiresMsg.arg(requiredSpace) + " " + @@ -201,8 +199,15 @@ bool Intro::pickDataDirectory(interfaces::Node& node) if(!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || gArgs.GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR) || settings.value("fReset", false).toBool() || gArgs.GetBoolArg("-resetguisettings", false)) { + /* Use selectParams here to guarantee Params() can be used by node interface */ + try { + node.selectParams(gArgs.GetChainName()); + } catch (const std::exception&) { + return false; + } + /* If current default data directory does not exist, let the user choose one */ - Intro intro; + Intro intro(0, node.getAssumedBlockchainSize(), node.getAssumedChainStateSize()); intro.setDataDirectory(dataDir); intro.setWindowIcon(QIcon(":icons/bitcoin")); @@ -221,7 +226,7 @@ bool Intro::pickDataDirectory(interfaces::Node& node) } break; } catch (const fs::filesystem_error&) { - QMessageBox::critical(0, tr(PACKAGE_NAME), + QMessageBox::critical(nullptr, tr(PACKAGE_NAME), tr("Error: Specified data directory \"%1\" cannot be created.").arg(dataDir)); /* fall through, back to choosing screen */ } @@ -281,7 +286,7 @@ void Intro::on_dataDirectory_textChanged(const QString &dataDirStr) void Intro::on_ellipsisButton_clicked() { - QString dir = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(0, "Choose data directory", ui->dataDirectory->text())); + QString dir = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(nullptr, "Choose data directory", ui->dataDirectory->text())); if(!dir.isEmpty()) ui->dataDirectory->setText(dir); } diff --git a/src/qt/intro.h b/src/qt/intro.h index 2b3da963e2..3da8a16114 100644 --- a/src/qt/intro.h +++ b/src/qt/intro.h @@ -30,7 +30,8 @@ class Intro : public QDialog Q_OBJECT public: - explicit Intro(QWidget *parent = 0); + explicit Intro(QWidget *parent = nullptr, + uint64_t blockchain_size = 0, uint64_t chain_state_size = 0); ~Intro(); QString getDataDirectory(); @@ -71,6 +72,8 @@ private: QMutex mutex; bool signalled; QString pathToCheck; + uint64_t m_blockchain_size; + uint64_t m_chain_state_size; void startThread(); void checkPath(const QString &dataDir); diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp index da048d3211..f0c860e669 100644 --- a/src/qt/networkstyle.cpp +++ b/src/qt/networkstyle.cpp @@ -88,5 +88,5 @@ const NetworkStyle *NetworkStyle::instantiate(const QString &networkId) network_styles[x].titleAddText); } } - return 0; + return nullptr; } diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index c9871f6c66..27cec06d4b 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -29,8 +29,8 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) : QDialog(parent), ui(new Ui::OptionsDialog), - model(0), - mapper(0) + model(nullptr), + mapper(nullptr) { ui->setupUi(this); diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 2421734527..1af3a72b92 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -31,7 +31,7 @@ class OptionsModel : public QAbstractListModel Q_OBJECT public: - explicit OptionsModel(interfaces::Node& node, QObject *parent = 0, bool resetSettings = false); + explicit OptionsModel(interfaces::Node& node, QObject *parent = nullptr, bool resetSettings = false); enum OptionID { StartAtStartup, // bool diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index bec79335e7..d8e48f350a 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -113,8 +113,8 @@ public: OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) : QWidget(parent), ui(new Ui::OverviewPage), - clientModel(0), - walletModel(0), + clientModel(nullptr), + walletModel(nullptr), txdelegate(new TxViewDelegate(platformStyle, this)) { ui->setupUi(this); diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index 75100ae6f7..00ba7ad4ce 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -30,7 +30,7 @@ class OverviewPage : public QWidget Q_OBJECT public: - explicit OverviewPage(const PlatformStyle *platformStyle, QWidget *parent = 0); + explicit OverviewPage(const PlatformStyle *platformStyle, QWidget *parent = nullptr); ~OverviewPage(); void setClientModel(ClientModel *clientModel); diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 8148986b51..b1ec90ad36 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -194,10 +194,10 @@ bool PaymentServer::ipcSendCommandLine() PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) : QObject(parent), saveURIs(true), - uriServer(0), - optionsModel(0) + uriServer(nullptr), + optionsModel(nullptr) #ifdef ENABLE_BIP70 - ,netManager(0) + ,netManager(nullptr) #endif { #ifdef ENABLE_BIP70 @@ -223,7 +223,7 @@ PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) : if (!uriServer->listen(name)) { // constructor is called early in init, so don't use "Q_EMIT message()" here - QMessageBox::critical(0, tr("Payment request error"), + QMessageBox::critical(nullptr, tr("Payment request error"), tr("Cannot start bitcoin: click-to-pay handler")); } else { diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index e2e78fe81b..496aeebf7d 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -96,7 +96,7 @@ public: if (idx >= 0 && idx < cachedNodeStats.size()) return &cachedNodeStats[idx]; - return 0; + return nullptr; } }; @@ -104,7 +104,7 @@ PeerTableModel::PeerTableModel(interfaces::Node& node, ClientModel *parent) : QAbstractTableModel(parent), m_node(node), clientModel(parent), - timer(0) + timer(nullptr) { columns << tr("NodeId") << tr("Node/Service") << tr("Ping") << tr("Sent") << tr("Received") << tr("User Agent"); priv.reset(new PeerTablePriv()); @@ -197,8 +197,7 @@ QVariant PeerTableModel::headerData(int section, Qt::Orientation orientation, in Qt::ItemFlags PeerTableModel::flags(const QModelIndex &index) const { - if(!index.isValid()) - return 0; + if (!index.isValid()) return Qt::NoItemFlags; Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled; return retval; diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h index 738a06496f..b3f5dd7dbe 100644 --- a/src/qt/peertablemodel.h +++ b/src/qt/peertablemodel.h @@ -51,7 +51,7 @@ class PeerTableModel : public QAbstractTableModel Q_OBJECT public: - explicit PeerTableModel(interfaces::Node& node, ClientModel *parent = 0); + explicit PeerTableModel(interfaces::Node& node, ClientModel *parent = nullptr); ~PeerTableModel(); const CNodeCombinedStats *getNodeStats(int idx); int getRowByNodeId(NodeId nodeid); diff --git a/src/qt/platformstyle.cpp b/src/qt/platformstyle.cpp index 56e0830cdc..d537d759de 100644 --- a/src/qt/platformstyle.cpp +++ b/src/qt/platformstyle.cpp @@ -139,6 +139,6 @@ const PlatformStyle *PlatformStyle::instantiate(const QString &platformId) platform_styles[x].useExtraSpacing); } } - return 0; + return nullptr; } diff --git a/src/qt/qvalidatedlineedit.cpp b/src/qt/qvalidatedlineedit.cpp index 85c5a58a84..aa936d6b7c 100644 --- a/src/qt/qvalidatedlineedit.cpp +++ b/src/qt/qvalidatedlineedit.cpp @@ -10,7 +10,7 @@ QValidatedLineEdit::QValidatedLineEdit(QWidget *parent) : QLineEdit(parent), valid(true), - checkValidator(0) + checkValidator(nullptr) { connect(this, &QValidatedLineEdit::textChanged, this, &QValidatedLineEdit::markValid); } diff --git a/src/qt/qvaluecombobox.h b/src/qt/qvaluecombobox.h index f266302310..8892071fba 100644 --- a/src/qt/qvaluecombobox.h +++ b/src/qt/qvaluecombobox.h @@ -16,7 +16,7 @@ class QValueComboBox : public QComboBox Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged USER true) public: - explicit QValueComboBox(QWidget *parent = 0); + explicit QValueComboBox(QWidget *parent = nullptr); QVariant value() const; void setValue(const QVariant &value); diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index a7cc5da19e..bc96b5a6f7 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -25,8 +25,8 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) : QDialog(parent), ui(new Ui::ReceiveCoinsDialog), - columnResizingFixer(0), - model(0), + columnResizingFixer(nullptr), + model(nullptr), platformStyle(_platformStyle) { ui->setupUi(this); diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h index bc0f6248f0..5bca2f46e2 100644 --- a/src/qt/receivecoinsdialog.h +++ b/src/qt/receivecoinsdialog.h @@ -39,7 +39,7 @@ public: MINIMUM_COLUMN_WIDTH = 130 }; - explicit ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent = 0); + explicit ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent = nullptr); ~ReceiveCoinsDialog(); void setModel(WalletModel *model); diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp index c561d948be..f5b30cf6d2 100644 --- a/src/qt/receiverequestdialog.cpp +++ b/src/qt/receiverequestdialog.cpp @@ -26,7 +26,7 @@ #endif QRImageWidget::QRImageWidget(QWidget *parent): - QLabel(parent), contextMenu(0) + QLabel(parent), contextMenu(nullptr) { contextMenu = new QMenu(this); QAction *saveImageAction = new QAction(tr("&Save Image..."), this); @@ -88,7 +88,7 @@ void QRImageWidget::contextMenuEvent(QContextMenuEvent *event) ReceiveRequestDialog::ReceiveRequestDialog(QWidget *parent) : QDialog(parent), ui(new Ui::ReceiveRequestDialog), - model(0) + model(nullptr) { ui->setupUi(this); diff --git a/src/qt/receiverequestdialog.h b/src/qt/receiverequestdialog.h index 5662af18b7..dd28fd73c8 100644 --- a/src/qt/receiverequestdialog.h +++ b/src/qt/receiverequestdialog.h @@ -28,7 +28,7 @@ class QRImageWidget : public QLabel Q_OBJECT public: - explicit QRImageWidget(QWidget *parent = 0); + explicit QRImageWidget(QWidget *parent = nullptr); QImage exportImage(); public Q_SLOTS: @@ -48,7 +48,7 @@ class ReceiveRequestDialog : public QDialog Q_OBJECT public: - explicit ReceiveRequestDialog(QWidget *parent = 0); + explicit ReceiveRequestDialog(QWidget *parent = nullptr); ~ReceiveRequestDialog(); void setModel(WalletModel *model); diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index d062ea49bd..3d7211aca2 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -485,7 +485,7 @@ RPCConsole::RPCConsole(interfaces::Node& node, const PlatformStyle *_platformSty // set library version labels #ifdef ENABLE_WALLET - ui->berkeleyDBVersion->setText(DbEnv::version(0, 0, 0)); + ui->berkeleyDBVersion->setText(DbEnv::version(nullptr, nullptr, nullptr)); #else ui->label_berkeleyDBVersion->hide(); ui->berkeleyDBVersion->hide(); diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 65db0280b7..6e00ab755c 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -54,8 +54,8 @@ int getIndexForConfTarget(int target) { SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) : QDialog(parent), ui(new Ui::SendCoinsDialog), - clientModel(0), - model(0), + clientModel(nullptr), + model(nullptr), fNewRecipientAllowed(true), fFeeMinimized(true), platformStyle(_platformStyle) @@ -443,7 +443,7 @@ SendCoinsEntry *SendCoinsDialog::addEntry() void SendCoinsDialog::updateTabsAndLabels() { - setupTabChain(0); + setupTabChain(nullptr); coinControlUpdateLabels(); } @@ -478,7 +478,7 @@ QWidget *SendCoinsDialog::setupTabChain(QWidget *prev) void SendCoinsDialog::setAddress(const QString &address) { - SendCoinsEntry *entry = 0; + SendCoinsEntry *entry = nullptr; // Replace the first entry if it is still unused if(ui->entries->count() == 1) { @@ -501,7 +501,7 @@ void SendCoinsDialog::pasteEntry(const SendCoinsRecipient &rv) if(!fNewRecipientAllowed) return; - SendCoinsEntry *entry = 0; + SendCoinsEntry *entry = nullptr; // Replace the first entry if it is still unused if(ui->entries->count() == 1) { diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h index e1ebc77d59..337a72b878 100644 --- a/src/qt/sendcoinsdialog.h +++ b/src/qt/sendcoinsdialog.h @@ -31,7 +31,7 @@ class SendCoinsDialog : public QDialog Q_OBJECT public: - explicit SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent = 0); + explicit SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent = nullptr); ~SendCoinsDialog(); void setClientModel(ClientModel *clientModel); @@ -108,7 +108,7 @@ class SendConfirmationDialog : public QMessageBox Q_OBJECT public: - SendConfirmationDialog(const QString &title, const QString &text, int secDelay = SEND_CONFIRM_DELAY, QWidget *parent = 0); + SendConfirmationDialog(const QString &title, const QString &text, int secDelay = SEND_CONFIRM_DELAY, QWidget *parent = nullptr); int exec(); private Q_SLOTS: diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index 76c942c8b9..7324d759fb 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -21,7 +21,7 @@ SendCoinsEntry::SendCoinsEntry(const PlatformStyle *_platformStyle, QWidget *parent) : QStackedWidget(parent), ui(new Ui::SendCoinsEntry), - model(0), + model(nullptr), platformStyle(_platformStyle) { ui->setupUi(this); @@ -155,7 +155,7 @@ bool SendCoinsEntry::validate(interfaces::Node& node) } // Sending a zero amount is invalid - if (ui->payAmount->value(0) <= 0) + if (ui->payAmount->value(nullptr) <= 0) { ui->payAmount->setValid(false); retval = false; diff --git a/src/qt/sendcoinsentry.h b/src/qt/sendcoinsentry.h index 48ecd598d6..42e2217130 100644 --- a/src/qt/sendcoinsentry.h +++ b/src/qt/sendcoinsentry.h @@ -26,7 +26,7 @@ class SendCoinsEntry : public QStackedWidget Q_OBJECT public: - explicit SendCoinsEntry(const PlatformStyle *platformStyle, QWidget *parent = 0); + explicit SendCoinsEntry(const PlatformStyle *platformStyle, QWidget *parent = nullptr); ~SendCoinsEntry(); void setModel(WalletModel *model); diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index 487fc9ee1e..d37a78fa8c 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -22,7 +22,7 @@ SignVerifyMessageDialog::SignVerifyMessageDialog(const PlatformStyle *_platformStyle, QWidget *parent) : QDialog(parent), ui(new Ui::SignVerifyMessageDialog), - model(0), + model(nullptr), platformStyle(_platformStyle) { ui->setupUi(this); diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index b109a08b1c..0126a2920e 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -26,7 +26,7 @@ SplashScreen::SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const NetworkStyle *networkStyle) : - QWidget(0, f), curAlignment(0), m_node(node) + QWidget(nullptr, f), curAlignment(0), m_node(node) { // set reference point, paddings int paddingRight = 50; diff --git a/src/qt/trafficgraphwidget.cpp b/src/qt/trafficgraphwidget.cpp index 3aed3f2b97..1588be8da3 100644 --- a/src/qt/trafficgraphwidget.cpp +++ b/src/qt/trafficgraphwidget.cpp @@ -19,14 +19,14 @@ TrafficGraphWidget::TrafficGraphWidget(QWidget *parent) : QWidget(parent), - timer(0), + timer(nullptr), fMax(0.0f), nMins(0), vSamplesIn(), vSamplesOut(), nLastBytesIn(0), nLastBytesOut(0), - clientModel(0) + clientModel(nullptr) { timer = new QTimer(this); connect(timer, &QTimer::timeout, this, &TrafficGraphWidget::updateRates); diff --git a/src/qt/trafficgraphwidget.h b/src/qt/trafficgraphwidget.h index 00660574af..48bd246b34 100644 --- a/src/qt/trafficgraphwidget.h +++ b/src/qt/trafficgraphwidget.h @@ -20,7 +20,7 @@ class TrafficGraphWidget : public QWidget Q_OBJECT public: - explicit TrafficGraphWidget(QWidget *parent = 0); + explicit TrafficGraphWidget(QWidget *parent = nullptr); void setClientModel(ClientModel *model); int getGraphRangeMins() const; diff --git a/src/qt/transactiondescdialog.h b/src/qt/transactiondescdialog.h index f1371b3856..8fd3f3166a 100644 --- a/src/qt/transactiondescdialog.h +++ b/src/qt/transactiondescdialog.h @@ -21,7 +21,7 @@ class TransactionDescDialog : public QDialog Q_OBJECT public: - explicit TransactionDescDialog(const QModelIndex &idx, QWidget *parent = 0); + explicit TransactionDescDialog(const QModelIndex &idx, QWidget *parent = nullptr); ~TransactionDescDialog(); private: diff --git a/src/qt/transactionfilterproxy.h b/src/qt/transactionfilterproxy.h index 9febd59820..685f8d3a26 100644 --- a/src/qt/transactionfilterproxy.h +++ b/src/qt/transactionfilterproxy.h @@ -16,7 +16,7 @@ class TransactionFilterProxy : public QSortFilterProxyModel Q_OBJECT public: - explicit TransactionFilterProxy(QObject *parent = 0); + explicit TransactionFilterProxy(QObject *parent = nullptr); /** Earliest date that can be represented (far in the past) */ static const QDateTime MIN_DATE; diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index d88cfe52ed..aa785553c8 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -4,6 +4,7 @@ #include <qt/transactionrecord.h> +#include <chain.h> #include <consensus/consensus.h> #include <interfaces/wallet.h> #include <key_io.h> @@ -12,6 +13,7 @@ #include <stdint.h> +#include <QDateTime> /* Return positive answer if transaction should be shown in list. */ @@ -158,7 +160,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const interface return parts; } -void TransactionRecord::updateStatus(const interfaces::WalletTxStatus& wtx, int numBlocks) +void TransactionRecord::updateStatus(const interfaces::WalletTxStatus& wtx, int numBlocks, int64_t block_time) { // Determine transaction status @@ -172,10 +174,9 @@ void TransactionRecord::updateStatus(const interfaces::WalletTxStatus& wtx, int status.depth = wtx.depth_in_main_chain; status.cur_num_blocks = numBlocks; - if (!wtx.is_final) - { - if (wtx.lock_time < LOCKTIME_THRESHOLD) - { + const bool up_to_date = ((int64_t)QDateTime::currentMSecsSinceEpoch() / 1000 - block_time < MAX_BLOCK_TIME_GAP); + if (up_to_date && !wtx.is_final) { + if (wtx.lock_time < LOCKTIME_THRESHOLD) { status.status = TransactionStatus::OpenUntilBlock; status.open_for = wtx.lock_time - numBlocks; } diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h index 470f70e2ab..3f64cefd09 100644 --- a/src/qt/transactionrecord.h +++ b/src/qt/transactionrecord.h @@ -138,7 +138,7 @@ public: /** Update status from core wallet tx. */ - void updateStatus(const interfaces::WalletTxStatus& wtx, int numBlocks); + void updateStatus(const interfaces::WalletTxStatus& wtx, int numBlocks, int64_t block_time); /** Return whether a status update is needed. */ diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 01722146c5..631a9b891d 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -192,12 +192,13 @@ public: // simply re-use the cached status. interfaces::WalletTxStatus wtx; int numBlocks; - if (wallet.tryGetTxStatus(rec->hash, wtx, numBlocks) && rec->statusUpdateNeeded(numBlocks)) { - rec->updateStatus(wtx, numBlocks); + int64_t block_time; + if (wallet.tryGetTxStatus(rec->hash, wtx, numBlocks, block_time) && rec->statusUpdateNeeded(numBlocks)) { + rec->updateStatus(wtx, numBlocks, block_time); } return rec; } - return 0; + return nullptr; } QString describe(interfaces::Node& node, interfaces::Wallet& wallet, TransactionRecord *rec, int unit) diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h index 8be3a7ab2e..7a7d98962b 100644 --- a/src/qt/transactiontablemodel.h +++ b/src/qt/transactiontablemodel.h @@ -28,7 +28,7 @@ class TransactionTableModel : public QAbstractTableModel Q_OBJECT public: - explicit TransactionTableModel(const PlatformStyle *platformStyle, WalletModel *parent = 0); + explicit TransactionTableModel(const PlatformStyle *platformStyle, WalletModel *parent = nullptr); ~TransactionTableModel(); enum ColumnIndex { diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 68410c8bd6..eb6437eb31 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -38,8 +38,8 @@ #include <QVBoxLayout> TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *parent) : - QWidget(parent), model(0), transactionProxyModel(0), - transactionView(0), abandonAction(0), bumpFeeAction(0), columnResizingFixer(0) + QWidget(parent), model(nullptr), transactionProxyModel(nullptr), + transactionView(nullptr), abandonAction(nullptr), bumpFeeAction(nullptr), columnResizingFixer(nullptr) { // Build filter row setContentsMargins(0,0,0,0); diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h index fdd8b069c7..e07181d1c8 100644 --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -35,7 +35,7 @@ class TransactionView : public QWidget Q_OBJECT public: - explicit TransactionView(const PlatformStyle *platformStyle, QWidget *parent = 0); + explicit TransactionView(const PlatformStyle *platformStyle, QWidget *parent = nullptr); void setModel(WalletModel *model); diff --git a/src/qt/utilitydialog.h b/src/qt/utilitydialog.h index ad1fda4573..f1cedff282 100644 --- a/src/qt/utilitydialog.h +++ b/src/qt/utilitydialog.h @@ -45,7 +45,7 @@ class ShutdownWindow : public QWidget Q_OBJECT public: - explicit ShutdownWindow(QWidget *parent=0, Qt::WindowFlags f=0); + explicit ShutdownWindow(QWidget *parent=nullptr, Qt::WindowFlags f=Qt::Widget); static QWidget *showShutdownWindow(BitcoinGUI *window); protected: diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index 9fbc8b4d52..10d063b2b7 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -31,7 +31,7 @@ class WalletFrame : public QFrame Q_OBJECT public: - explicit WalletFrame(const PlatformStyle *platformStyle, BitcoinGUI *_gui = 0); + explicit WalletFrame(const PlatformStyle *platformStyle, BitcoinGUI *_gui = nullptr); ~WalletFrame(); void setClientModel(ClientModel *clientModel); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 0a5b21f997..e1fb4819f1 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -33,9 +33,9 @@ WalletModel::WalletModel(std::unique_ptr<interfaces::Wallet> wallet, interfaces::Node& node, const PlatformStyle *platformStyle, OptionsModel *_optionsModel, QObject *parent) : - QObject(parent), m_wallet(std::move(wallet)), m_node(node), optionsModel(_optionsModel), addressTableModel(0), - transactionTableModel(0), - recentRequestsTableModel(0), + QObject(parent), m_wallet(std::move(wallet)), m_node(node), optionsModel(_optionsModel), addressTableModel(nullptr), + transactionTableModel(nullptr), + recentRequestsTableModel(nullptr), cachedEncryptionStatus(Unencrypted), cachedNumBlocks(0) { @@ -510,7 +510,7 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash) CAmount new_fee; CMutableTransaction mtx; if (!m_wallet->createBumpTransaction(hash, coin_control, 0 /* totalFee */, errors, old_fee, new_fee, mtx)) { - QMessageBox::critical(0, tr("Fee bump error"), tr("Increasing transaction fee failed") + "<br />(" + + QMessageBox::critical(nullptr, tr("Fee bump error"), tr("Increasing transaction fee failed") + "<br />(" + (errors.size() ? QString::fromStdString(errors[0]) : "") +")"); return false; } @@ -549,12 +549,12 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash) // sign bumped transaction if (!m_wallet->signBumpTransaction(mtx)) { - QMessageBox::critical(0, tr("Fee bump error"), tr("Can't sign transaction.")); + QMessageBox::critical(nullptr, tr("Fee bump error"), tr("Can't sign transaction.")); return false; } // commit the bumped transaction if(!m_wallet->commitBumpTransaction(hash, std::move(mtx), errors, new_hash)) { - QMessageBox::critical(0, tr("Fee bump error"), tr("Could not commit transaction") + "<br />(" + + QMessageBox::critical(nullptr, tr("Fee bump error"), tr("Could not commit transaction") + "<br />(" + QString::fromStdString(errors[0])+")"); return false; } diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 6a6c538157..c3c8f36909 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -127,7 +127,7 @@ class WalletModel : public QObject Q_OBJECT public: - explicit WalletModel(std::unique_ptr<interfaces::Wallet> wallet, interfaces::Node& node, const PlatformStyle *platformStyle, OptionsModel *optionsModel, QObject *parent = 0); + explicit WalletModel(std::unique_ptr<interfaces::Wallet> wallet, interfaces::Node& node, const PlatformStyle *platformStyle, OptionsModel *optionsModel, QObject *parent = nullptr); ~WalletModel(); enum StatusCode // Returned by sendCoins diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index a619992344..dd089d8310 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -32,8 +32,8 @@ WalletView::WalletView(const PlatformStyle *_platformStyle, QWidget *parent): QStackedWidget(parent), - clientModel(0), - walletModel(0), + clientModel(nullptr), + walletModel(nullptr), platformStyle(_platformStyle) { // Create tabs diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index cc229367ba..6fdf80dc5f 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -423,7 +423,7 @@ static UniValue GetNetworksInfo() UniValue obj(UniValue::VOBJ); GetProxy(network, proxy); obj.pushKV("name", GetNetworkName(network)); - obj.pushKV("limited", IsLimited(network)); + obj.pushKV("limited", !IsReachable(network)); obj.pushKV("reachable", IsReachable(network)); obj.pushKV("proxy", proxy.IsValid() ? proxy.proxy.ToStringIPPort() : std::string()); obj.pushKV("proxy_randomize_credentials", proxy.randomize_credentials); diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index e7e047334e..edaf64f3e1 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -31,11 +31,39 @@ static RPCTimerInterface* timerInterface = nullptr; /* Map of name to timer. */ static std::map<std::string, std::unique_ptr<RPCTimerBase> > deadlineTimers; +struct RPCCommandExecutionInfo +{ + std::string method; + int64_t start; +}; + +struct RPCServerInfo +{ + Mutex mutex; + std::list<RPCCommandExecutionInfo> active_commands GUARDED_BY(mutex); +}; + +static RPCServerInfo g_rpc_server_info; + +struct RPCCommandExecution +{ + std::list<RPCCommandExecutionInfo>::iterator it; + explicit RPCCommandExecution(const std::string& method) + { + LOCK(g_rpc_server_info.mutex); + it = g_rpc_server_info.active_commands.insert(g_rpc_server_info.active_commands.cend(), {method, GetTimeMicros()}); + } + ~RPCCommandExecution() + { + LOCK(g_rpc_server_info.mutex); + g_rpc_server_info.active_commands.erase(it); + } +}; + static struct CRPCSignals { boost::signals2::signal<void ()> Started; boost::signals2::signal<void ()> Stopped; - boost::signals2::signal<void (const CRPCCommand&)> PreCommand; } g_rpcSignals; void RPCServer::OnStarted(std::function<void ()> slot) @@ -254,11 +282,37 @@ static UniValue uptime(const JSONRPCRequest& jsonRequest) return GetTime() - GetStartupTime(); } +static UniValue getrpcinfo(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() > 0) { + throw std::runtime_error( + RPCHelpMan{"getrpcinfo", + "\nReturns details of the RPC server.\n", {}} + .ToString() + ); + } + + LOCK(g_rpc_server_info.mutex); + UniValue active_commands(UniValue::VARR); + for (const RPCCommandExecutionInfo& info : g_rpc_server_info.active_commands) { + UniValue entry(UniValue::VOBJ); + entry.pushKV("method", info.method); + entry.pushKV("duration", GetTimeMicros() - info.start); + active_commands.push_back(entry); + } + + UniValue result(UniValue::VOBJ); + result.pushKV("active_commands", active_commands); + + return result; +} + // clang-format off static const CRPCCommand vRPCCommands[] = { // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- /* Overall control/query calls */ + { "control", "getrpcinfo", &getrpcinfo, {} }, { "control", "help", &help, {"command"} }, { "control", "stop", &stop, {"wait"} }, { "control", "uptime", &uptime, {} }, @@ -483,10 +537,9 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const if (!pcmd) throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found"); - g_rpcSignals.PreCommand(*pcmd); - try { + RPCCommandExecution execution(request.strMethod); // Execute, convert arguments to array if necessary if (request.params.isObject()) { return pcmd->actor(transformNamedArguments(request, pcmd->argNames)); diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp index 5a108dcdad..80328458c4 100644 --- a/src/test/allocator_tests.cpp +++ b/src/test/allocator_tests.cpp @@ -105,13 +105,13 @@ BOOST_AUTO_TEST_CASE(arena_tests) // Go entirely wild: free and alloc interleaved, // generate targets and sizes using pseudo-randomness. for (int x=0; x<2048; ++x) - addr.push_back(0); + addr.push_back(nullptr); uint32_t s = 0x12345678; for (int x=0; x<5000; ++x) { int idx = s & (addr.size()-1); if (s & 0x80000000) { b.free(addr[idx]); - addr[idx] = 0; + addr[idx] = nullptr; } else if(!addr[idx]) { addr[idx] = b.alloc((s >> 16) & 2047); } @@ -146,7 +146,7 @@ public: return reinterpret_cast<void*>(0x08000000 + (count<<24)); // Fake address, do not actually use this memory } - return 0; + return nullptr; } void FreeLocked(void* addr, size_t len) override { diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp index 5e55ad6622..4cdf0f003e 100644 --- a/src/test/merkle_tests.cpp +++ b/src/test/merkle_tests.cpp @@ -13,9 +13,9 @@ static uint256 ComputeMerkleRootFromBranch(const uint256& leaf, const std::vecto uint256 hash = leaf; for (std::vector<uint256>::const_iterator it = vMerkleBranch.begin(); it != vMerkleBranch.end(); ++it) { if (nIndex & 1) { - hash = Hash(BEGIN(*it), END(*it), BEGIN(hash), END(hash)); + hash = Hash(it->begin(), it->end(), hash.begin(), hash.end()); } else { - hash = Hash(BEGIN(hash), END(hash), BEGIN(*it), END(*it)); + hash = Hash(hash.begin(), hash.end(), it->begin(), it->end()); } nIndex >>= 1; } diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index 4dc394b86d..b4ae8e9765 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -230,26 +230,21 @@ BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test) BOOST_AUTO_TEST_CASE(LimitedAndReachable_Network) { - SetLimited(NET_IPV4, true); - SetLimited(NET_IPV6, true); - SetLimited(NET_ONION, true); + BOOST_CHECK_EQUAL(IsReachable(NET_IPV4), true); + BOOST_CHECK_EQUAL(IsReachable(NET_IPV6), true); + BOOST_CHECK_EQUAL(IsReachable(NET_ONION), true); - BOOST_CHECK_EQUAL(IsLimited(NET_IPV4), true); - BOOST_CHECK_EQUAL(IsLimited(NET_IPV6), true); - BOOST_CHECK_EQUAL(IsLimited(NET_ONION), true); + SetReachable(NET_IPV4, false); + SetReachable(NET_IPV6, false); + SetReachable(NET_ONION, false); BOOST_CHECK_EQUAL(IsReachable(NET_IPV4), false); BOOST_CHECK_EQUAL(IsReachable(NET_IPV6), false); BOOST_CHECK_EQUAL(IsReachable(NET_ONION), false); - - SetLimited(NET_IPV4, false); - SetLimited(NET_IPV6, false); - SetLimited(NET_ONION, false); - - BOOST_CHECK_EQUAL(IsLimited(NET_IPV4), false); - BOOST_CHECK_EQUAL(IsLimited(NET_IPV6), false); - BOOST_CHECK_EQUAL(IsLimited(NET_ONION), false); + SetReachable(NET_IPV4, true); + SetReachable(NET_IPV6, true); + SetReachable(NET_ONION, true); BOOST_CHECK_EQUAL(IsReachable(NET_IPV4), true); BOOST_CHECK_EQUAL(IsReachable(NET_IPV6), true); @@ -258,19 +253,13 @@ BOOST_AUTO_TEST_CASE(LimitedAndReachable_Network) BOOST_AUTO_TEST_CASE(LimitedAndReachable_NetworkCaseUnroutableAndInternal) { - BOOST_CHECK_EQUAL(IsLimited(NET_UNROUTABLE), false); - BOOST_CHECK_EQUAL(IsLimited(NET_INTERNAL), false); - BOOST_CHECK_EQUAL(IsReachable(NET_UNROUTABLE), true); BOOST_CHECK_EQUAL(IsReachable(NET_INTERNAL), true); - SetLimited(NET_UNROUTABLE, true); - SetLimited(NET_INTERNAL, true); + SetReachable(NET_UNROUTABLE, false); + SetReachable(NET_INTERNAL, false); - BOOST_CHECK_EQUAL(IsLimited(NET_UNROUTABLE), false); // Ignored for both networks - BOOST_CHECK_EQUAL(IsLimited(NET_INTERNAL), false); - - BOOST_CHECK_EQUAL(IsReachable(NET_UNROUTABLE), true); + BOOST_CHECK_EQUAL(IsReachable(NET_UNROUTABLE), true); // Ignored for both networks BOOST_CHECK_EQUAL(IsReachable(NET_INTERNAL), true); } @@ -289,15 +278,13 @@ BOOST_AUTO_TEST_CASE(LimitedAndReachable_CNetAddr) { CNetAddr addr = UtilBuildAddress(0x001, 0x001, 0x001, 0x001); // 1.1.1.1 - SetLimited(NET_IPV4, false); - BOOST_CHECK_EQUAL(IsLimited(addr), false); + SetReachable(NET_IPV4, true); BOOST_CHECK_EQUAL(IsReachable(addr), true); - SetLimited(NET_IPV4, true); - BOOST_CHECK_EQUAL(IsLimited(addr), true); + SetReachable(NET_IPV4, false); BOOST_CHECK_EQUAL(IsReachable(addr), false); - SetLimited(NET_IPV4, false); // have to reset this, because this is stateful. + SetReachable(NET_IPV4, true); // have to reset this, because this is stateful. } @@ -305,7 +292,7 @@ BOOST_AUTO_TEST_CASE(LocalAddress_BasicLifecycle) { CService addr = CService(UtilBuildAddress(0x002, 0x001, 0x001, 0x001), 1000); // 2.1.1.1:1000 - SetLimited(NET_IPV4, false); + SetReachable(NET_IPV4, true); BOOST_CHECK_EQUAL(IsLocal(addr), false); BOOST_CHECK_EQUAL(AddLocal(addr, 1000), true); diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 9acebdd820..71b6ec7425 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -1224,7 +1224,7 @@ BOOST_AUTO_TEST_CASE(test_ToLower) BOOST_CHECK_EQUAL(ToLower('Z'), 'z'); BOOST_CHECK_EQUAL(ToLower('['), '['); BOOST_CHECK_EQUAL(ToLower(0), 0); - BOOST_CHECK_EQUAL(ToLower(255), 255); + BOOST_CHECK_EQUAL(ToLower('\xff'), '\xff'); std::string testVector; Downcase(testVector); @@ -1246,7 +1246,7 @@ BOOST_AUTO_TEST_CASE(test_ToUpper) BOOST_CHECK_EQUAL(ToUpper('z'), 'Z'); BOOST_CHECK_EQUAL(ToUpper('{'), '{'); BOOST_CHECK_EQUAL(ToUpper(0), 0); - BOOST_CHECK_EQUAL(ToUpper(255), 255); + BOOST_CHECK_EQUAL(ToUpper('\xff'), '\xff'); } BOOST_AUTO_TEST_CASE(test_Capitalize) diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index c9ee6f9f81..550e23b222 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -527,7 +527,7 @@ void TorController::auth_cb(TorControlConnection& _conn, const TorControlReply& CService resolved(LookupNumeric("127.0.0.1", 9050)); proxyType addrOnion = proxyType(resolved, true); SetProxy(NET_ONION, addrOnion); - SetLimited(NET_ONION, false); + SetReachable(NET_ONION, true); } // Finally - now create the service diff --git a/src/uint256.cpp b/src/uint256.cpp index b723f9ee54..e3bc9712e8 100644 --- a/src/uint256.cpp +++ b/src/uint256.cpp @@ -33,7 +33,7 @@ void base_blob<BITS>::SetHex(const char* psz) psz++; // skip 0x - if (psz[0] == '0' && ToLower((unsigned char)psz[1]) == 'x') + if (psz[0] == '0' && ToLower(psz[1]) == 'x') psz += 2; // hex string to uint diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp index 46146be66f..fedeeac39b 100644 --- a/src/util/strencodings.cpp +++ b/src/util/strencodings.cpp @@ -589,7 +589,7 @@ bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypa void Downcase(std::string& str) { - std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c){return ToLower(c);}); + std::transform(str.begin(), str.end(), str.begin(), [](char c){return ToLower(c);}); } std::string Capitalize(std::string str) diff --git a/src/util/strencodings.h b/src/util/strencodings.h index 7d16d7dcfd..e392055f27 100644 --- a/src/util/strencodings.h +++ b/src/util/strencodings.h @@ -15,10 +15,6 @@ #include <string> #include <vector> -#define BEGIN(a) ((char*)&(a)) -#define END(a) ((char*)&((&(a))[1])) -#define UBEGIN(a) ((unsigned char*)&(a)) -#define UEND(a) ((unsigned char*)&((&(a))[1])) #define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0])) /** Used by SanitizeString() */ @@ -212,7 +208,7 @@ NODISCARD bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32 * @return the lowercase equivalent of c; or the argument * if no conversion is possible. */ -constexpr unsigned char ToLower(unsigned char c) +constexpr char ToLower(char c) { return (c >= 'A' && c <= 'Z' ? (c - 'A') + 'a' : c); } @@ -233,7 +229,7 @@ void Downcase(std::string& str); * @return the uppercase equivalent of c; or the argument * if no conversion is possible. */ -constexpr unsigned char ToUpper(unsigned char c) +constexpr char ToUpper(char c) { return (c >= 'a' && c <= 'z' ? (c - 'a') + 'A' : c); } diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index 98e2abbd18..3677194a40 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -338,7 +338,7 @@ bool BerkeleyBatch::VerifyEnvironment(const fs::path& file_path, std::string& er BerkeleyEnvironment* env = GetWalletEnv(file_path, walletFile); fs::path walletDir = env->Directory(); - LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0)); + LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(nullptr, nullptr, nullptr)); LogPrintf("Using wallet %s\n", walletFile); // Wallet file must be a plain filename without a directory diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 14d811c6cd..87cd264c3d 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -242,7 +242,11 @@ void StopWallets() void UnloadWallets() { - for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) { - RemoveWallet(pwallet); + auto wallets = GetWallets(); + while (!wallets.empty()) { + auto wallet = wallets.back(); + wallets.pop_back(); + RemoveWallet(wallet); + UnloadWallet(std::move(wallet)); } } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 38397a3940..39c17743ec 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2637,16 +2637,8 @@ static UniValue unloadwallet(const JSONRPCRequest& request) if (!RemoveWallet(wallet)) { throw JSONRPCError(RPC_MISC_ERROR, "Requested wallet already unloaded"); } - UnregisterValidationInterface(wallet.get()); - // The wallet can be in use so it's not possible to explicitly unload here. - // Just notify the unload intent so that all shared pointers are released. - // The wallet will be destroyed once the last shared pointer is released. - wallet->NotifyUnload(); - - // There's no point in waiting for the wallet to unload. - // At this point this method should never fail. The unloading could only - // fail due to an unexpected error which would cause a process termination. + UnloadWallet(std::move(wallet)); return NullUniValue; } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 109f8e6da0..098055673b 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -82,13 +82,52 @@ std::shared_ptr<CWallet> GetWallet(const std::string& name) return nullptr; } +static Mutex g_wallet_release_mutex; +static std::condition_variable g_wallet_release_cv; +static std::set<CWallet*> g_unloading_wallet_set; + // Custom deleter for shared_ptr<CWallet>. static void ReleaseWallet(CWallet* wallet) { + // Unregister and delete the wallet right after BlockUntilSyncedToCurrentChain + // so that it's in sync with the current chainstate. wallet->WalletLogPrintf("Releasing wallet\n"); wallet->BlockUntilSyncedToCurrentChain(); wallet->Flush(); + UnregisterValidationInterface(wallet); delete wallet; + // Wallet is now released, notify UnloadWallet, if any. + { + LOCK(g_wallet_release_mutex); + if (g_unloading_wallet_set.erase(wallet) == 0) { + // UnloadWallet was not called for this wallet, all done. + return; + } + } + g_wallet_release_cv.notify_all(); +} + +void UnloadWallet(std::shared_ptr<CWallet>&& wallet) +{ + // Mark wallet for unloading. + CWallet* pwallet = wallet.get(); + { + LOCK(g_wallet_release_mutex); + auto it = g_unloading_wallet_set.insert(pwallet); + assert(it.second); + } + // The wallet can be in use so it's not possible to explicitly unload here. + // Notify the unload intent so that all remaining shared pointers are + // released. + pwallet->NotifyUnload(); + // Time to ditch our shared_ptr and wait for ReleaseWallet call. + wallet.reset(); + { + WAIT_LOCK(g_wallet_release_mutex, lock); + while (g_unloading_wallet_set.count(pwallet) == 1) { + g_wallet_release_cv.wait(lock); + } + } } const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000; @@ -2516,6 +2555,65 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC return true; } +static bool IsCurrentForAntiFeeSniping(interfaces::Chain::Lock& locked_chain) +{ + if (IsInitialBlockDownload()) { + return false; + } + constexpr int64_t MAX_ANTI_FEE_SNIPING_TIP_AGE = 8 * 60 * 60; // in seconds + if (chainActive.Tip()->GetBlockTime() < (GetTime() - MAX_ANTI_FEE_SNIPING_TIP_AGE)) { + return false; + } + return true; +} + +/** + * Return a height-based locktime for new transactions (uses the height of the + * current chain tip unless we are not synced with the current chain + */ +static uint32_t GetLocktimeForNewTransaction(interfaces::Chain::Lock& locked_chain) +{ + uint32_t locktime; + // Discourage fee sniping. + // + // For a large miner the value of the transactions in the best block and + // the mempool can exceed the cost of deliberately attempting to mine two + // blocks to orphan the current best block. By setting nLockTime such that + // only the next block can include the transaction, we discourage this + // practice as the height restricted and limited blocksize gives miners + // considering fee sniping fewer options for pulling off this attack. + // + // A simple way to think about this is from the wallet's point of view we + // always want the blockchain to move forward. By setting nLockTime this + // way we're basically making the statement that we only want this + // transaction to appear in the next block; we don't want to potentially + // encourage reorgs by allowing transactions to appear at lower heights + // than the next block in forks of the best chain. + // + // Of course, the subsidy is high enough, and transaction volume low + // enough, that fee sniping isn't a problem yet, but by implementing a fix + // now we ensure code won't be written that makes assumptions about + // nLockTime that preclude a fix later. + if (IsCurrentForAntiFeeSniping(locked_chain)) { + locktime = chainActive.Height(); + + // Secondly occasionally randomly pick a nLockTime even further back, so + // that transactions that are delayed after signing for whatever reason, + // e.g. high-latency mix networks and some CoinJoin implementations, have + // better privacy. + if (GetRandInt(10) == 0) + locktime = std::max(0, (int)locktime - GetRandInt(100)); + } else { + // If our chain is lagging behind, we can't discourage fee sniping nor help + // the privacy of high-latency transactions. To avoid leaking a potentially + // unique "nLockTime fingerprint", set nLockTime to a constant. + locktime = 0; + } + assert(locktime <= (unsigned int)chainActive.Height()); + assert(locktime < LOCKTIME_THRESHOLD); + return locktime; +} + OutputType CWallet::TransactionChangeType(OutputType change_type, const std::vector<CRecipient>& vecSend) { // If -changetype is specified, always use that change type. @@ -2570,37 +2668,8 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std CMutableTransaction txNew; - // Discourage fee sniping. - // - // For a large miner the value of the transactions in the best block and - // the mempool can exceed the cost of deliberately attempting to mine two - // blocks to orphan the current best block. By setting nLockTime such that - // only the next block can include the transaction, we discourage this - // practice as the height restricted and limited blocksize gives miners - // considering fee sniping fewer options for pulling off this attack. - // - // A simple way to think about this is from the wallet's point of view we - // always want the blockchain to move forward. By setting nLockTime this - // way we're basically making the statement that we only want this - // transaction to appear in the next block; we don't want to potentially - // encourage reorgs by allowing transactions to appear at lower heights - // than the next block in forks of the best chain. - // - // Of course, the subsidy is high enough, and transaction volume low - // enough, that fee sniping isn't a problem yet, but by implementing a fix - // now we ensure code won't be written that makes assumptions about - // nLockTime that preclude a fix later. - txNew.nLockTime = chainActive.Height(); - - // Secondly occasionally randomly pick a nLockTime even further back, so - // that transactions that are delayed after signing for whatever reason, - // e.g. high-latency mix networks and some CoinJoin implementations, have - // better privacy. - if (GetRandInt(10) == 0) - txNew.nLockTime = std::max(0, (int)txNew.nLockTime - GetRandInt(100)); + txNew.nLockTime = GetLocktimeForNewTransaction(locked_chain); - assert(txNew.nLockTime <= (unsigned int)chainActive.Height()); - assert(txNew.nLockTime < LOCKTIME_THRESHOLD); FeeCalculation feeCalc; CAmount nFeeNeeded; int nBytes; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 3a3ec43c9b..6872fbad2d 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -54,6 +54,13 @@ void StopWallets(); //! Close all wallets. void UnloadWallets(); +//! Explicitly unload and delete the wallet. +// Blocks the current thread after signaling the unload intent so that all +// wallet clients release the wallet. +// Note that, when blocking is not required, the wallet is implicitly unloaded +// by the shared pointer deleter. +void UnloadWallet(std::shared_ptr<CWallet>&& wallet); + bool AddWallet(const std::shared_ptr<CWallet>& wallet); bool RemoveWallet(const std::shared_ptr<CWallet>& wallet); bool HasWallets(); @@ -770,6 +777,8 @@ public: ~CWallet() { + // Should not have slots connected at this point. + assert(NotifyUnload.empty()); delete encrypted_batch; encrypted_batch = nullptr; } |