diff options
Diffstat (limited to 'src')
34 files changed, 416 insertions, 408 deletions
diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp index e5b6875a36..ab805ac1ec 100644 --- a/src/bitcoin-chainstate.cpp +++ b/src/bitcoin-chainstate.cpp @@ -70,7 +70,7 @@ int main(int argc, char* argv[]) // SETUP: Chainstate - ChainstateManager chainman; + ChainstateManager chainman{chainparams}; auto rv = node::LoadChainstate(false, std::ref(chainman), @@ -163,7 +163,7 @@ int main(int argc, char* argv[]) LOCK(cs_main); const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock); if (pindex) { - UpdateUncommittedBlockStructures(block, pindex, chainparams.GetConsensus()); + chainman.UpdateUncommittedBlockStructures(block, pindex); } } @@ -190,7 +190,7 @@ int main(int argc, char* argv[]) bool new_block; auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash()); RegisterSharedValidationInterface(sc); - bool accepted = chainman.ProcessNewBlock(chainparams, blockptr, /*force_processing=*/true, /*new_block=*/&new_block); + bool accepted = chainman.ProcessNewBlock(blockptr, /*force_processing=*/true, /*new_block=*/&new_block); UnregisterSharedValidationInterface(sc); if (!new_block && accepted) { std::cerr << "duplicate" << std::endl; diff --git a/src/checkqueue.h b/src/checkqueue.h index d0e88a3410..bead6f0c6f 100644 --- a/src/checkqueue.h +++ b/src/checkqueue.h @@ -66,7 +66,7 @@ private: bool m_request_stop GUARDED_BY(m_mutex){false}; /** Internal function that does bulk of the verification work. */ - bool Loop(bool fMaster) + bool Loop(bool fMaster) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) { std::condition_variable& cond = fMaster ? m_master_cv : m_worker_cv; std::vector<T> vChecks; @@ -140,7 +140,7 @@ public: } //! Create a pool of new worker threads. - void StartWorkerThreads(const int threads_num) + void StartWorkerThreads(const int threads_num) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) { { LOCK(m_mutex); @@ -159,13 +159,13 @@ public: } //! Wait until execution finishes, and return whether all evaluations were successful. - bool Wait() + bool Wait() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) { return Loop(true /* master thread */); } //! Add a batch of checks to the queue - void Add(std::vector<T>& vChecks) + void Add(std::vector<T>& vChecks) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) { if (vChecks.empty()) { return; @@ -188,7 +188,7 @@ public: } //! Stop all of the worker threads. - void StopWorkerThreads() + void StopWorkerThreads() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) { WITH_LOCK(m_mutex, m_request_stop = true); m_worker_cv.notify_all(); diff --git a/src/deploymentstatus.cpp b/src/deploymentstatus.cpp index ae19a6e40d..3a524af29e 100644 --- a/src/deploymentstatus.cpp +++ b/src/deploymentstatus.cpp @@ -9,8 +9,6 @@ #include <type_traits> -VersionBitsCache g_versionbitscache; - /* Basic sanity checking for BuriedDeployment/DeploymentPos enums and * ValidDeployment check */ diff --git a/src/deploymentstatus.h b/src/deploymentstatus.h index ba5103de74..9f5919f71b 100644 --- a/src/deploymentstatus.h +++ b/src/deploymentstatus.h @@ -10,33 +10,30 @@ #include <limits> -/** Global cache for versionbits deployment status */ -extern VersionBitsCache g_versionbitscache; - /** Determine if a deployment is active for the next block */ -inline bool DeploymentActiveAfter(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::BuriedDeployment dep) +inline bool DeploymentActiveAfter(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::BuriedDeployment dep, [[maybe_unused]] VersionBitsCache& versionbitscache) { assert(Consensus::ValidDeployment(dep)); return (pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1) >= params.DeploymentHeight(dep); } -inline bool DeploymentActiveAfter(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos dep) +inline bool DeploymentActiveAfter(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos dep, VersionBitsCache& versionbitscache) { assert(Consensus::ValidDeployment(dep)); - return ThresholdState::ACTIVE == g_versionbitscache.State(pindexPrev, params, dep); + return ThresholdState::ACTIVE == versionbitscache.State(pindexPrev, params, dep); } /** Determine if a deployment is active for this block */ -inline bool DeploymentActiveAt(const CBlockIndex& index, const Consensus::Params& params, Consensus::BuriedDeployment dep) +inline bool DeploymentActiveAt(const CBlockIndex& index, const Consensus::Params& params, Consensus::BuriedDeployment dep, [[maybe_unused]] VersionBitsCache& versionbitscache) { assert(Consensus::ValidDeployment(dep)); return index.nHeight >= params.DeploymentHeight(dep); } -inline bool DeploymentActiveAt(const CBlockIndex& index, const Consensus::Params& params, Consensus::DeploymentPos dep) +inline bool DeploymentActiveAt(const CBlockIndex& index, const Consensus::Params& params, Consensus::DeploymentPos dep, VersionBitsCache& versionbitscache) { assert(Consensus::ValidDeployment(dep)); - return DeploymentActiveAfter(index.pprev, params, dep); + return DeploymentActiveAfter(index.pprev, params, dep, versionbitscache); } /** Determine if a deployment is enabled (can ever be active) */ diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 96bee8640d..dba66becc0 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -87,7 +87,7 @@ public: { } /** Enqueue a work item */ - bool Enqueue(WorkItem* item) + bool Enqueue(WorkItem* item) EXCLUSIVE_LOCKS_REQUIRED(!cs) { LOCK(cs); if (!running || queue.size() >= maxDepth) { @@ -98,7 +98,7 @@ public: return true; } /** Thread function */ - void Run() + void Run() EXCLUSIVE_LOCKS_REQUIRED(!cs) { while (true) { std::unique_ptr<WorkItem> i; @@ -115,7 +115,7 @@ public: } } /** Interrupt and exit loops */ - void Interrupt() + void Interrupt() EXCLUSIVE_LOCKS_REQUIRED(!cs) { LOCK(cs); running = false; @@ -84,7 +84,7 @@ public: * to the listening socket and address. * @return true on success */ - bool Listen(Connection& conn); + bool Listen(Connection& conn) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); /** * Wait for and accept a new incoming connection. @@ -103,7 +103,7 @@ public: * it is set to `false`. Only set if `false` is returned. * @return true on success */ - bool Connect(const CService& to, Connection& conn, bool& proxy_error); + bool Connect(const CService& to, Connection& conn, bool& proxy_error) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); private: /** @@ -172,7 +172,7 @@ private: /** * Check the control socket for errors and possibly disconnect. */ - void CheckControlSock(); + void CheckControlSock() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); /** * Generate a new destination with the SAM proxy and set `m_private_key` to it. diff --git a/src/index/blockfilterindex.h b/src/index/blockfilterindex.h index b1836fe12f..6deff59000 100644 --- a/src/index/blockfilterindex.h +++ b/src/index/blockfilterindex.h @@ -64,7 +64,7 @@ public: bool LookupFilter(const CBlockIndex* block_index, BlockFilter& filter_out) const; /** Get a single filter header by block. */ - bool LookupFilterHeader(const CBlockIndex* block_index, uint256& header_out); + bool LookupFilterHeader(const CBlockIndex* block_index, uint256& header_out) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_headers_cache); /** Get a range of filters between two heights on a chain. */ bool LookupFilterRange(int start_height, const CBlockIndex* stop_index, diff --git a/src/init.cpp b/src/init.cpp index feb4ad52a6..e180a2b5cd 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1424,7 +1424,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) for (bool fLoaded = false; !fLoaded && !ShutdownRequested();) { node.mempool = std::make_unique<CTxMemPool>(node.fee_estimator.get(), mempool_check_ratio); - node.chainman = std::make_unique<ChainstateManager>(); + node.chainman = std::make_unique<ChainstateManager>(chainparams); ChainstateManager& chainman = *node.chainman; const bool fReset = fReindex; diff --git a/src/net.cpp b/src/net.cpp index 41ac31445d..1c775f9a3f 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1867,6 +1867,12 @@ void CConnman::SetTryNewOutboundPeer(bool flag) LogPrint(BCLog::NET, "net: setting try another outbound peer=%s\n", flag ? "true" : "false"); } +void CConnman::StartExtraBlockRelayPeers() +{ + LogPrint(BCLog::NET, "net: enabling extra block-relay-only peers\n"); + m_start_extra_block_relay_peers = true; +} + // Return the number of peers we have over our outbound connection limit // Exclude peers that are marked for disconnect, or are going to be // disconnected soon (eg ADDR_FETCH and FEELER) @@ -13,7 +13,6 @@ #include <crypto/siphash.h> #include <hash.h> #include <i2p.h> -#include <logging.h> #include <net_permissions.h> #include <netaddress.h> #include <netbase.h> @@ -613,7 +612,7 @@ public: * @return True if the peer should stay connected, * False if the peer should be disconnected from. */ - bool ReceiveMsgBytes(Span<const uint8_t> msg_bytes, bool& complete); + bool ReceiveMsgBytes(Span<const uint8_t> msg_bytes, bool& complete) EXCLUSIVE_LOCKS_REQUIRED(!cs_vRecv); void SetCommonVersion(int greatest_common_version) { @@ -625,9 +624,9 @@ public: return m_greatest_common_version; } - CService GetAddrLocal() const LOCKS_EXCLUDED(m_addr_local_mutex); + CService GetAddrLocal() const EXCLUSIVE_LOCKS_REQUIRED(!m_addr_local_mutex); //! May not be called more than once - void SetAddrLocal(const CService& addrLocalIn) LOCKS_EXCLUDED(m_addr_local_mutex); + void SetAddrLocal(const CService& addrLocalIn) EXCLUSIVE_LOCKS_REQUIRED(!m_addr_local_mutex); CNode* AddRef() { @@ -640,9 +639,9 @@ public: nRefCount--; } - void CloseSocketDisconnect(); + void CloseSocketDisconnect() EXCLUSIVE_LOCKS_REQUIRED(!m_sock_mutex); - void CopyStats(CNodeStats& stats); + void CopyStats(CNodeStats& stats) EXCLUSIVE_LOCKS_REQUIRED(!m_subver_mutex, !m_addr_local_mutex, !cs_vSend, !cs_vRecv); ServiceFlags GetLocalServices() const { @@ -761,7 +760,7 @@ public: bool m_i2p_accept_incoming; }; - void Init(const Options& connOptions) EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex) + void Init(const Options& connOptions) EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex, !m_total_bytes_sent_mutex) { AssertLockNotHeld(m_total_bytes_sent_mutex); @@ -795,7 +794,8 @@ public: bool network_active = true); ~CConnman(); - bool Start(CScheduler& scheduler, const Options& options) EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex); + + bool Start(CScheduler& scheduler, const Options& options) EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex, !m_added_nodes_mutex, !m_addr_fetches_mutex, !mutexMsgProc); void StopThreads(); void StopNodes(); @@ -805,7 +805,7 @@ public: StopNodes(); }; - void Interrupt(); + void Interrupt() EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc); bool GetNetworkActive() const { return fNetworkActive; }; bool GetUseAddrmanOutgoing() const { return m_use_addrman_outgoing; }; void SetNetworkActive(bool active); @@ -857,10 +857,7 @@ public: void SetTryNewOutboundPeer(bool flag); bool GetTryNewOutboundPeer() const; - void StartExtraBlockRelayPeers() { - LogPrint(BCLog::NET, "net: enabling extra block-relay-only peers\n"); - m_start_extra_block_relay_peers = true; - } + void StartExtraBlockRelayPeers(); // Return the number of outbound peers we have in excess of our target (eg, // if we previously called SetTryNewOutboundPeer(true), and have since set @@ -872,9 +869,9 @@ public: // Count the number of block-relay-only peers we have over our limit. int GetExtraBlockRelayCount() const; - bool AddNode(const std::string& node); - bool RemoveAddedNode(const std::string& node); - std::vector<AddedNodeInfo> GetAddedNodeInfo() const; + bool AddNode(const std::string& node) EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex); + bool RemoveAddedNode(const std::string& node) EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex); + std::vector<AddedNodeInfo> GetAddedNodeInfo() const EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex); /** * Attempts to open a connection. Currently only used from tests. @@ -927,7 +924,7 @@ public: unsigned int GetReceiveFloodSize() const; - void WakeMessageHandler(); + void WakeMessageHandler() EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc); /** Return true if we should disconnect the peer for failing an inactivity check. */ bool ShouldRunInactivityChecks(const CNode& node, std::chrono::seconds now) const; @@ -954,11 +951,11 @@ private: bool Bind(const CService& addr, unsigned int flags, NetPermissionFlags permissions); bool InitBinds(const Options& options); - void ThreadOpenAddedConnections(); - void AddAddrFetch(const std::string& strDest); - void ProcessAddrFetch(); - void ThreadOpenConnections(std::vector<std::string> connect); - void ThreadMessageHandler(); + void ThreadOpenAddedConnections() EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex); + void AddAddrFetch(const std::string& strDest) EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex); + void ProcessAddrFetch() EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex); + void ThreadOpenConnections(std::vector<std::string> connect) EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_added_nodes_mutex, !m_nodes_mutex); + void ThreadMessageHandler() EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc); void ThreadI2PAcceptIncoming(); void AcceptConnection(const ListenSocket& hListenSocket); @@ -1009,7 +1006,7 @@ private: /** * Check connected and listening sockets for IO readiness and process them accordingly. */ - void SocketHandler() EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex); + void SocketHandler() EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex, !mutexMsgProc); /** * Do the read/write for connected sockets that are ready for IO. @@ -1023,7 +1020,7 @@ private: const std::set<SOCKET>& recv_set, const std::set<SOCKET>& send_set, const std::set<SOCKET>& error_set) - EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex); + EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex, !mutexMsgProc); /** * Accept incoming connections, one from each read-ready listening socket. @@ -1031,8 +1028,8 @@ private: */ void SocketHandlerListening(const std::set<SOCKET>& recv_set); - void ThreadSocketHandler() EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex); - void ThreadDNSAddressSeed(); + void ThreadSocketHandler() EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex, !mutexMsgProc); + void ThreadDNSAddressSeed() EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_nodes_mutex); uint64_t CalculateKeyedNetGroup(const CAddress& ad) const; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index cb0e8c88f8..349d7fd8fb 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -175,6 +175,8 @@ static constexpr double MAX_ADDR_RATE_PER_SECOND{0.1}; * based increments won't go above this, but the MAX_ADDR_TO_SEND increment following GETADDR * is exempt from this limit). */ static constexpr size_t MAX_ADDR_PROCESSING_TOKEN_BUCKET{MAX_ADDR_TO_SEND}; +/** The compactblocks version we support. See BIP 152. */ +static constexpr uint64_t CMPCTBLOCKS_VERSION{2}; // Internal stuff namespace { @@ -365,23 +367,12 @@ struct CNodeState { bool fPreferredDownload{false}; //! Whether this peer wants invs or headers (when possible) for block announcements. bool fPreferHeaders{false}; - //! Whether this peer wants invs or cmpctblocks (when possible) for block announcements. - bool fPreferHeaderAndIDs{false}; - /** - * Whether this peer will send us cmpctblocks if we request them. - * This is not used to gate request logic, as we really only care about fSupportsDesiredCmpctVersion, - * but is used as a flag to "lock in" the version of compact blocks (fWantsCmpctWitness) we send. - */ - bool fProvidesHeaderAndIDs{false}; + /** Whether this peer wants invs or cmpctblocks (when possible) for block announcements. */ + bool m_requested_hb_cmpctblocks{false}; + /** Whether this peer will send us cmpctblocks if we request them. */ + bool m_provides_cmpctblocks{false}; //! Whether this peer can give us witnesses bool fHaveWitness{false}; - //! Whether this peer wants witnesses in cmpctblocks/blocktxns - bool fWantsCmpctWitness{false}; - /** - * If we've announced NODE_WITNESS to this peer: whether the peer sends witnesses in cmpctblocks/blocktxns, - * otherwise: whether this peer sends non-witnesses in cmpctblocks/blocktxns. - */ - bool fSupportsDesiredCmpctVersion{false}; /** State used to enforce CHAIN_SYNC_TIMEOUT and EXTRA_PEER_CHECK_INTERVAL logic. * @@ -440,30 +431,37 @@ public: CTxMemPool& pool, bool ignore_incoming_txs); /** Overridden from CValidationInterface. */ - void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected) override; - void BlockDisconnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex* pindex) override; - void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override; - void BlockChecked(const CBlock& block, const BlockValidationState& state) override; + void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected) override + EXCLUSIVE_LOCKS_REQUIRED(!m_recent_confirmed_transactions_mutex); + void BlockDisconnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex* pindex) override + EXCLUSIVE_LOCKS_REQUIRED(!m_recent_confirmed_transactions_mutex); + void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); + void BlockChecked(const CBlock& block, const BlockValidationState& state) override + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock) override; /** Implement NetEventsInterface */ - void InitializeNode(CNode* pnode) override; - void FinalizeNode(const CNode& node) override; - bool ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt) override; - bool SendMessages(CNode* pto) override EXCLUSIVE_LOCKS_REQUIRED(pto->cs_sendProcessing); + void InitializeNode(CNode* pnode) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); + void FinalizeNode(const CNode& node) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); + bool ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt) override + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex); + bool SendMessages(CNode* pto) override EXCLUSIVE_LOCKS_REQUIRED(pto->cs_sendProcessing) + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex); /** Implement PeerManager */ void StartScheduledTasks(CScheduler& scheduler) override; void CheckForStaleTipAndEvictPeers() override; std::optional<std::string> FetchBlock(NodeId peer_id, const CBlockIndex& block_index) override; - bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) const override; + bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) const override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); bool IgnoresIncomingTxs() override { return m_ignore_incoming_txs; } - void SendPings() override; - void RelayTransaction(const uint256& txid, const uint256& wtxid) override; + void SendPings() override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); + void RelayTransaction(const uint256& txid, const uint256& wtxid) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void SetBestHeight(int height) override { m_best_height = height; }; - void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message) override; + void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv, - const std::chrono::microseconds time_received, const std::atomic<bool>& interruptMsgProc) override; + const std::chrono::microseconds time_received, const std::atomic<bool>& interruptMsgProc) override + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex); void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds) override; private: @@ -474,15 +472,15 @@ private: void EvictExtraOutboundPeers(std::chrono::seconds now) EXCLUSIVE_LOCKS_REQUIRED(cs_main); /** Retrieve unbroadcast transactions from the mempool and reattempt sending to peers */ - void ReattemptInitialBroadcast(CScheduler& scheduler); + void ReattemptInitialBroadcast(CScheduler& scheduler) EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); /** Get a shared pointer to the Peer object. * May return an empty shared_ptr if the Peer object can't be found. */ - PeerRef GetPeerRef(NodeId id) const; + PeerRef GetPeerRef(NodeId id) const EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); /** Get a shared pointer to the Peer object and remove it from m_peer_map. * May return an empty shared_ptr if the Peer object can't be found. */ - PeerRef RemovePeer(NodeId id); + PeerRef RemovePeer(NodeId id) EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); /** * Potentially mark a node discouraged based on the contents of a BlockValidationState object @@ -495,14 +493,16 @@ private: * @return Returns true if the peer was punished (probably disconnected) */ bool MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state, - bool via_compact_block, const std::string& message = ""); + bool via_compact_block, const std::string& message = "") + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); /** * Potentially disconnect and discourage a node based on the contents of a TxValidationState object * * @return Returns true if the peer was punished (probably disconnected) */ - bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message = ""); + bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message = "") + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); /** Maybe disconnect a peer and discourage future connections from its address. * @@ -512,13 +512,16 @@ private: */ bool MaybeDiscourageAndDisconnect(CNode& pnode, Peer& peer); - void ProcessOrphanTx(std::set<uint256>& orphan_work_set) EXCLUSIVE_LOCKS_REQUIRED(cs_main, g_cs_orphans); + void ProcessOrphanTx(std::set<uint256>& orphan_work_set) EXCLUSIVE_LOCKS_REQUIRED(cs_main, g_cs_orphans) + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); /** Process a single headers message from a peer. */ void ProcessHeadersMessage(CNode& pfrom, const Peer& peer, const std::vector<CBlockHeader>& headers, - bool via_compact_block); + bool via_compact_block) + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); - void SendBlockTransactions(CNode& pfrom, const CBlock& block, const BlockTransactionsRequest& req); + void SendBlockTransactions(CNode& pfrom, const CBlock& block, const BlockTransactionsRequest& req) + EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); /** Register with TxRequestTracker that an INV has been received from a * peer. The announcement parameters are decided in PeerManager and then @@ -545,7 +548,7 @@ private: * @param[in] fReachable Whether the address' network is reachable. We relay unreachable * addresses less. */ - void RelayAddress(NodeId originator, const CAddress& addr, bool fReachable); + void RelayAddress(NodeId originator, const CAddress& addr, bool fReachable) EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); /** Send `feefilter` message. */ void MaybeSendFeefilter(CNode& node, Peer& peer, std::chrono::microseconds current_time); @@ -615,7 +618,8 @@ private: /** Number of preferable block download peers. */ int m_num_preferred_download_peers GUARDED_BY(cs_main){0}; - bool AlreadyHaveTx(const GenTxid& gtxid) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + bool AlreadyHaveTx(const GenTxid& gtxid) + EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_recent_confirmed_transactions_mutex); /** * Filter for transactions that were recently rejected by the mempool. @@ -687,7 +691,6 @@ private: std::shared_ptr<const CBlock> m_most_recent_block GUARDED_BY(m_most_recent_block_mutex); std::shared_ptr<const CBlockHeaderAndShortTxIDs> m_most_recent_compact_block GUARDED_BY(m_most_recent_block_mutex); uint256 m_most_recent_block_hash GUARDED_BY(m_most_recent_block_mutex); - bool m_most_recent_compact_block_has_witnesses GUARDED_BY(m_most_recent_block_mutex){false}; /** Height of the highest block announced using BIP 152 high-bandwidth mode. */ int m_highest_fast_announce{0}; @@ -974,54 +977,52 @@ void PeerManagerImpl::MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid) if (m_ignore_incoming_txs) return; CNodeState* nodestate = State(nodeid); - if (!nodestate || !nodestate->fSupportsDesiredCmpctVersion) { - // Never ask from peers who can't provide witnesses. + if (!nodestate || !nodestate->m_provides_cmpctblocks) { + // Don't request compact blocks if the peer has not signalled support return; } - if (nodestate->fProvidesHeaderAndIDs) { - int num_outbound_hb_peers = 0; - for (std::list<NodeId>::iterator it = lNodesAnnouncingHeaderAndIDs.begin(); it != lNodesAnnouncingHeaderAndIDs.end(); it++) { - if (*it == nodeid) { - lNodesAnnouncingHeaderAndIDs.erase(it); - lNodesAnnouncingHeaderAndIDs.push_back(nodeid); - return; - } - CNodeState *state = State(*it); - if (state != nullptr && !state->m_is_inbound) ++num_outbound_hb_peers; - } - if (nodestate->m_is_inbound) { - // If we're adding an inbound HB peer, make sure we're not removing - // our last outbound HB peer in the process. - if (lNodesAnnouncingHeaderAndIDs.size() >= 3 && num_outbound_hb_peers == 1) { - CNodeState *remove_node = State(lNodesAnnouncingHeaderAndIDs.front()); - if (remove_node != nullptr && !remove_node->m_is_inbound) { - // Put the HB outbound peer in the second slot, so that it - // doesn't get removed. - std::swap(lNodesAnnouncingHeaderAndIDs.front(), *std::next(lNodesAnnouncingHeaderAndIDs.begin())); - } - } + + int num_outbound_hb_peers = 0; + for (std::list<NodeId>::iterator it = lNodesAnnouncingHeaderAndIDs.begin(); it != lNodesAnnouncingHeaderAndIDs.end(); it++) { + if (*it == nodeid) { + lNodesAnnouncingHeaderAndIDs.erase(it); + lNodesAnnouncingHeaderAndIDs.push_back(nodeid); + return; } - m_connman.ForNode(nodeid, [this](CNode* pfrom) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { - AssertLockHeld(::cs_main); - uint64_t nCMPCTBLOCKVersion = 2; - if (lNodesAnnouncingHeaderAndIDs.size() >= 3) { - // As per BIP152, we only get 3 of our peers to announce - // blocks using compact encodings. - m_connman.ForNode(lNodesAnnouncingHeaderAndIDs.front(), [this, nCMPCTBLOCKVersion](CNode* pnodeStop){ - m_connman.PushMessage(pnodeStop, CNetMsgMaker(pnodeStop->GetCommonVersion()).Make(NetMsgType::SENDCMPCT, /*fAnnounceUsingCMPCTBLOCK=*/false, nCMPCTBLOCKVersion)); - // save BIP152 bandwidth state: we select peer to be low-bandwidth - pnodeStop->m_bip152_highbandwidth_to = false; - return true; - }); - lNodesAnnouncingHeaderAndIDs.pop_front(); + CNodeState *state = State(*it); + if (state != nullptr && !state->m_is_inbound) ++num_outbound_hb_peers; + } + if (nodestate->m_is_inbound) { + // If we're adding an inbound HB peer, make sure we're not removing + // our last outbound HB peer in the process. + if (lNodesAnnouncingHeaderAndIDs.size() >= 3 && num_outbound_hb_peers == 1) { + CNodeState *remove_node = State(lNodesAnnouncingHeaderAndIDs.front()); + if (remove_node != nullptr && !remove_node->m_is_inbound) { + // Put the HB outbound peer in the second slot, so that it + // doesn't get removed. + std::swap(lNodesAnnouncingHeaderAndIDs.front(), *std::next(lNodesAnnouncingHeaderAndIDs.begin())); } - m_connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetCommonVersion()).Make(NetMsgType::SENDCMPCT, /*fAnnounceUsingCMPCTBLOCK=*/true, nCMPCTBLOCKVersion)); - // save BIP152 bandwidth state: we select peer to be high-bandwidth - pfrom->m_bip152_highbandwidth_to = true; - lNodesAnnouncingHeaderAndIDs.push_back(pfrom->GetId()); - return true; - }); + } } + m_connman.ForNode(nodeid, [this](CNode* pfrom) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { + AssertLockHeld(::cs_main); + if (lNodesAnnouncingHeaderAndIDs.size() >= 3) { + // As per BIP152, we only get 3 of our peers to announce + // blocks using compact encodings. + m_connman.ForNode(lNodesAnnouncingHeaderAndIDs.front(), [this](CNode* pnodeStop){ + m_connman.PushMessage(pnodeStop, CNetMsgMaker(pnodeStop->GetCommonVersion()).Make(NetMsgType::SENDCMPCT, /*high_bandwidth=*/false, /*version=*/CMPCTBLOCKS_VERSION)); + // save BIP152 bandwidth state: we select peer to be low-bandwidth + pnodeStop->m_bip152_highbandwidth_to = false; + return true; + }); + lNodesAnnouncingHeaderAndIDs.pop_front(); + } + m_connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetCommonVersion()).Make(NetMsgType::SENDCMPCT, /*high_bandwidth=*/true, /*version=*/CMPCTBLOCKS_VERSION)); + // save BIP152 bandwidth state: we select peer to be high-bandwidth + pfrom->m_bip152_highbandwidth_to = true; + lNodesAnnouncingHeaderAndIDs.push_back(pfrom->GetId()); + return true; + }); } bool PeerManagerImpl::TipMayBeStale() @@ -1110,7 +1111,6 @@ void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count if (state->pindexLastCommonBlock == state->pindexBestKnownBlock) return; - const Consensus::Params& consensusParams = m_chainparams.GetConsensus(); std::vector<const CBlockIndex*> vToFetch; const CBlockIndex *pindexWalk = state->pindexLastCommonBlock; // Never fetch further than the best block we know the peer has, or more than BLOCK_DOWNLOAD_WINDOW + 1 beyond the last @@ -1140,7 +1140,7 @@ void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count // We consider the chain that this peer is on invalid. return; } - if (!State(nodeid)->fHaveWitness && DeploymentActiveAt(*pindex, consensusParams, Consensus::DEPLOYMENT_SEGWIT)) { + if (!State(nodeid)->fHaveWitness && DeploymentActiveAt(*pindex, m_chainman, Consensus::DEPLOYMENT_SEGWIT)) { // We wouldn't download this block or its descendants from this peer. return; } @@ -1641,7 +1641,8 @@ void PeerManagerImpl::NewPoWValidBlock(const CBlockIndex *pindex, const std::sha return; m_highest_fast_announce = pindex->nHeight; - bool fWitnessEnabled = DeploymentActiveAt(*pindex, m_chainparams.GetConsensus(), Consensus::DEPLOYMENT_SEGWIT); + if (!DeploymentActiveAt(*pindex, m_chainman, Consensus::DEPLOYMENT_SEGWIT)) return; + uint256 hashBlock(pblock->GetHash()); const std::shared_future<CSerializedNetMsg> lazy_ser{ std::async(std::launch::deferred, [&] { return msgMaker.Make(NetMsgType::CMPCTBLOCK, *pcmpctblock); })}; @@ -1651,10 +1652,9 @@ void PeerManagerImpl::NewPoWValidBlock(const CBlockIndex *pindex, const std::sha m_most_recent_block_hash = hashBlock; m_most_recent_block = pblock; m_most_recent_compact_block = pcmpctblock; - m_most_recent_compact_block_has_witnesses = fWitnessEnabled; } - m_connman.ForEachNode([this, pindex, fWitnessEnabled, &lazy_ser, &hashBlock](CNode* pnode) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { + m_connman.ForEachNode([this, pindex, &lazy_ser, &hashBlock](CNode* pnode) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { AssertLockHeld(::cs_main); if (pnode->GetCommonVersion() < INVALID_CB_NO_BAN_VERSION || pnode->fDisconnect) @@ -1663,8 +1663,7 @@ void PeerManagerImpl::NewPoWValidBlock(const CBlockIndex *pindex, const std::sha CNodeState &state = *State(pnode->GetId()); // If the peer has, or we announced to them the previous block already, // but we don't think they have this one, go ahead and announce it - if (state.fPreferHeaderAndIDs && (!fWitnessEnabled || state.fWantsCmpctWitness) && - !PeerHasHeader(&state, pindex) && PeerHasHeader(&state, pindex->pprev)) { + if (state.m_requested_hb_cmpctblocks && !PeerHasHeader(&state, pindex) && PeerHasHeader(&state, pindex->pprev)) { LogPrint(BCLog::NET, "%s sending header-and-ids %s to peer=%d\n", "PeerManager::NewPoWValidBlock", hashBlock.ToString(), pnode->GetId()); @@ -1859,12 +1858,10 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& { std::shared_ptr<const CBlock> a_recent_block; std::shared_ptr<const CBlockHeaderAndShortTxIDs> a_recent_compact_block; - bool fWitnessesPresentInARecentCompactBlock; { LOCK(m_most_recent_block_mutex); a_recent_block = m_most_recent_block; a_recent_compact_block = m_most_recent_compact_block; - fWitnessesPresentInARecentCompactBlock = m_most_recent_compact_block_has_witnesses; } bool need_activate_chain = false; @@ -1977,17 +1974,15 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& // they won't have a useful mempool to match against a compact block, // and we don't feel like constructing the object for them, so // instead we respond with the full, non-compact block. - bool fPeerWantsWitness = State(pfrom.GetId())->fWantsCmpctWitness; - int nSendFlags = fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS; if (CanDirectFetch() && pindex->nHeight >= m_chainman.ActiveChain().Height() - MAX_CMPCTBLOCK_DEPTH) { - if ((fPeerWantsWitness || !fWitnessesPresentInARecentCompactBlock) && a_recent_compact_block && a_recent_compact_block->header.GetHash() == pindex->GetBlockHash()) { - m_connman.PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *a_recent_compact_block)); + if (a_recent_compact_block && a_recent_compact_block->header.GetHash() == pindex->GetBlockHash()) { + m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::CMPCTBLOCK, *a_recent_compact_block)); } else { - CBlockHeaderAndShortTxIDs cmpctblock(*pblock, fPeerWantsWitness); - m_connman.PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock)); + CBlockHeaderAndShortTxIDs cmpctblock(*pblock, true); + m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::CMPCTBLOCK, cmpctblock)); } } else { - m_connman.PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCK, *pblock)); + m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::BLOCK, *pblock)); } } } @@ -2146,10 +2141,9 @@ void PeerManagerImpl::SendBlockTransactions(CNode& pfrom, const CBlock& block, c } resp.txn[i] = block.vtx[req.indexes[i]]; } - LOCK(cs_main); + const CNetMsgMaker msgMaker(pfrom.GetCommonVersion()); - int nSendFlags = State(pfrom.GetId())->fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS; - m_connman.PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp)); + m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::BLOCKTXN, resp)); } void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer, @@ -2214,7 +2208,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer, } BlockValidationState state; - if (!m_chainman.ProcessNewBlockHeaders(headers, state, m_chainparams, &pindexLast)) { + if (!m_chainman.ProcessNewBlockHeaders(headers, state, &pindexLast)) { if (state.IsInvalid()) { MaybePunishNodeForBlock(pfrom.GetId(), state, via_compact_block, "invalid header received"); return; @@ -2258,7 +2252,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer, while (pindexWalk && !m_chainman.ActiveChain().Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) && !IsBlockRequested(pindexWalk->GetBlockHash()) && - (!DeploymentActiveAt(*pindexWalk, m_chainparams.GetConsensus(), Consensus::DEPLOYMENT_SEGWIT) || State(pfrom.GetId())->fHaveWitness)) { + (!DeploymentActiveAt(*pindexWalk, m_chainman, Consensus::DEPLOYMENT_SEGWIT) || State(pfrom.GetId())->fHaveWitness)) { // We don't have this block, and it's not yet in flight. vToFetch.push_back(pindexWalk); } @@ -2292,7 +2286,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer, } if (vGetData.size() > 0) { if (!m_ignore_incoming_txs && - nodestate->fSupportsDesiredCmpctVersion && + nodestate->m_provides_cmpctblocks && vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN)) { @@ -2591,7 +2585,7 @@ void PeerManagerImpl::ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv) void PeerManagerImpl::ProcessBlock(CNode& node, const std::shared_ptr<const CBlock>& block, bool force_processing) { bool new_block{false}; - m_chainman.ProcessNewBlock(m_chainparams, block, force_processing, &new_block); + m_chainman.ProcessNewBlock(block, force_processing, &new_block); if (new_block) { node.m_last_block_time = GetTime<std::chrono::seconds>(); } else { @@ -2862,16 +2856,12 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDHEADERS)); } if (pfrom.GetCommonVersion() >= SHORT_IDS_BLOCKS_VERSION) { - // Tell our peer we are willing to provide version 1 or 2 cmpctblocks + // Tell our peer we are willing to provide version 2 cmpctblocks. // However, we do not request new block announcements using // cmpctblock messages. // We send this to non-NODE NETWORK peers as well, because // they may wish to request compact blocks from us - bool fAnnounceUsingCMPCTBLOCK = false; - uint64_t nCMPCTBLOCKVersion = 2; - m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); - nCMPCTBLOCKVersion = 1; - m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); + m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, /*high_bandwidth=*/false, /*version=*/CMPCTBLOCKS_VERSION)); } pfrom.fSuccessfullyConnected = true; return; @@ -2884,26 +2874,20 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, } if (msg_type == NetMsgType::SENDCMPCT) { - bool fAnnounceUsingCMPCTBLOCK = false; - uint64_t nCMPCTBLOCKVersion = 0; - vRecv >> fAnnounceUsingCMPCTBLOCK >> nCMPCTBLOCKVersion; - if (nCMPCTBLOCKVersion == 1 || nCMPCTBLOCKVersion == 2) { - LOCK(cs_main); - // fProvidesHeaderAndIDs is used to "lock in" version of compact blocks we send (fWantsCmpctWitness) - if (!State(pfrom.GetId())->fProvidesHeaderAndIDs) { - State(pfrom.GetId())->fProvidesHeaderAndIDs = true; - State(pfrom.GetId())->fWantsCmpctWitness = nCMPCTBLOCKVersion == 2; - } - if (State(pfrom.GetId())->fWantsCmpctWitness == (nCMPCTBLOCKVersion == 2)) { // ignore later version announces - State(pfrom.GetId())->fPreferHeaderAndIDs = fAnnounceUsingCMPCTBLOCK; - // save whether peer selects us as BIP152 high-bandwidth peer - // (receiving sendcmpct(1) signals high-bandwidth, sendcmpct(0) low-bandwidth) - pfrom.m_bip152_highbandwidth_from = fAnnounceUsingCMPCTBLOCK; - } - if (!State(pfrom.GetId())->fSupportsDesiredCmpctVersion) { - State(pfrom.GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 2); - } - } + bool sendcmpct_hb{false}; + uint64_t sendcmpct_version{0}; + vRecv >> sendcmpct_hb >> sendcmpct_version; + + // Only support compact block relay with witnesses + if (sendcmpct_version != CMPCTBLOCKS_VERSION) return; + + LOCK(cs_main); + CNodeState* nodestate = State(pfrom.GetId()); + nodestate->m_provides_cmpctblocks = true; + nodestate->m_requested_hb_cmpctblocks = sendcmpct_hb; + // save whether peer selects us as BIP152 high-bandwidth peer + // (receiving sendcmpct(1) signals high-bandwidth, sendcmpct(0) low-bandwidth) + pfrom.m_bip152_highbandwidth_from = sendcmpct_hb; return; } @@ -3252,9 +3236,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, // expensive disk reads, because it will require the peer to // actually receive all the data read from disk over the network. LogPrint(BCLog::NET, "Peer %d sent us a getblocktxn for a block > %i deep\n", pfrom.GetId(), MAX_BLOCKTXN_DEPTH); - CInv inv; - WITH_LOCK(cs_main, inv.type = State(pfrom.GetId())->fWantsCmpctWitness ? MSG_WITNESS_BLOCK : MSG_BLOCK); - inv.hash = req.blockhash; + CInv inv{MSG_WITNESS_BLOCK, req.blockhash}; WITH_LOCK(peer->m_getdata_requests_mutex, peer->m_getdata_requests.push_back(inv)); // The message processing loop will go around again (without pausing) and we'll respond then return; @@ -3569,7 +3551,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, const CBlockIndex *pindex = nullptr; BlockValidationState state; - if (!m_chainman.ProcessNewBlockHeaders({cmpctblock.header}, state, m_chainparams, &pindex)) { + if (!m_chainman.ProcessNewBlockHeaders({cmpctblock.header}, state, &pindex)) { if (state.IsInvalid()) { MaybePunishNodeForBlock(pfrom.GetId(), state, /*via_compact_block=*/true, "invalid header via cmpctblock"); return; @@ -3629,12 +3611,6 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, return; } - if (DeploymentActiveAt(*pindex, m_chainparams.GetConsensus(), Consensus::DEPLOYMENT_SEGWIT) && !nodestate->fSupportsDesiredCmpctVersion) { - // Don't bother trying to process compact blocks from v1 peers - // after segwit activates. - return; - } - // We want to be a bit conservative just to be extra careful about DoS // possibilities in compact block processing... if (pindex->nHeight <= m_chainman.ActiveChain().Height() + 2) { @@ -4724,7 +4700,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto) LOCK(peer->m_block_inv_mutex); std::vector<CBlock> vHeaders; bool fRevertToInv = ((!state.fPreferHeaders && - (!state.fPreferHeaderAndIDs || peer->m_blocks_for_headers_relay.size() > 1)) || + (!state.m_requested_hb_cmpctblocks || peer->m_blocks_for_headers_relay.size() > 1)) || peer->m_blocks_for_headers_relay.size() > MAX_BLOCKS_TO_ANNOUNCE); const CBlockIndex *pBestIndex = nullptr; // last header queued for delivery ProcessBlockAvailability(pto->GetId()); // ensure pindexBestKnownBlock is up-to-date @@ -4777,24 +4753,17 @@ bool PeerManagerImpl::SendMessages(CNode* pto) } } if (!fRevertToInv && !vHeaders.empty()) { - if (vHeaders.size() == 1 && state.fPreferHeaderAndIDs) { + if (vHeaders.size() == 1 && state.m_requested_hb_cmpctblocks) { // We only send up to 1 block as header-and-ids, as otherwise // probably means we're doing an initial-ish-sync or they're slow LogPrint(BCLog::NET, "%s sending header-and-ids %s to peer=%d\n", __func__, vHeaders.front().GetHash().ToString(), pto->GetId()); - int nSendFlags = state.fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS; - bool fGotBlockFromCache = false; { LOCK(m_most_recent_block_mutex); if (m_most_recent_block_hash == pBestIndex->GetBlockHash()) { - if (state.fWantsCmpctWitness || !m_most_recent_compact_block_has_witnesses) - m_connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *m_most_recent_compact_block)); - else { - CBlockHeaderAndShortTxIDs cmpctblock(*m_most_recent_block, state.fWantsCmpctWitness); - m_connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock)); - } + m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::CMPCTBLOCK, *m_most_recent_compact_block)); fGotBlockFromCache = true; } } @@ -4802,8 +4771,8 @@ bool PeerManagerImpl::SendMessages(CNode* pto) CBlock block; bool ret = ReadBlockFromDisk(block, pBestIndex, consensusParams); assert(ret); - CBlockHeaderAndShortTxIDs cmpctblock(block, state.fWantsCmpctWitness); - m_connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock)); + CBlockHeaderAndShortTxIDs cmpctblock(block, true); + m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::CMPCTBLOCK, cmpctblock)); } state.pindexBestHeaderSent = pBestIndex; } else if (state.fPreferHeaders) { diff --git a/src/node/miner.cpp b/src/node/miner.cpp index be5d58527b..770ccdbe1a 100644 --- a/src/node/miner.cpp +++ b/src/node/miner.cpp @@ -51,7 +51,7 @@ void RegenerateCommitments(CBlock& block, ChainstateManager& chainman) block.vtx.at(0) = MakeTransactionRef(tx); const CBlockIndex* prev_block = WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock)); - GenerateCoinbaseCommitment(block, prev_block, Params().GetConsensus()); + chainman.GenerateCoinbaseCommitment(block, prev_block); block.hashMerkleRoot = BlockMerkleRoot(block); } @@ -126,7 +126,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc assert(pindexPrev != nullptr); nHeight = pindexPrev->nHeight + 1; - pblock->nVersion = g_versionbitscache.ComputeBlockVersion(pindexPrev, chainparams.GetConsensus()); + pblock->nVersion = m_chainstate.m_chainman.m_versionbitscache.ComputeBlockVersion(pindexPrev, chainparams.GetConsensus()); // -regtest only: allow overriding block.nVersion with // -blockversion=N to test forking scenarios if (chainparams.MineBlocksOnDemand()) { @@ -154,7 +154,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc coinbaseTx.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus()); coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0; pblock->vtx[0] = MakeTransactionRef(std::move(coinbaseTx)); - pblocktemplate->vchCoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, chainparams.GetConsensus()); + pblocktemplate->vchCoinbaseCommitment = m_chainstate.m_chainman.GenerateCoinbaseCommitment(*pblock, pindexPrev); pblocktemplate->vTxFees[0] = -nFees; LogPrintf("CreateNewBlock(): block weight: %u txs: %u fees: %ld sigops %d\n", GetBlockWeight(*pblock), nBlockTx, nFees, nBlockSigOpsCost); diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 846691c0c0..1c8116738d 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -61,7 +61,7 @@ public: //! Return number of connections, default is in- and outbound (total) int getNumConnections(unsigned int flags = CONNECTIONS_ALL) const; int getNumBlocks() const; - uint256 getBestBlockHash(); + uint256 getBestBlockHash() EXCLUSIVE_LOCKS_REQUIRED(!m_cached_tip_mutex); int getHeaderTipHeight() const; int64_t getHeaderTipTime() const; diff --git a/src/random.cpp b/src/random.cpp index ad8568bef0..ec4e44ccc2 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -374,7 +374,7 @@ public: { } - void AddEvent(uint32_t event_info) noexcept + void AddEvent(uint32_t event_info) noexcept EXCLUSIVE_LOCKS_REQUIRED(!m_events_mutex) { LOCK(m_events_mutex); @@ -388,7 +388,7 @@ public: /** * Feed (the hash of) all events added through AddEvent() to hasher. */ - void SeedEvents(CSHA512& hasher) noexcept + void SeedEvents(CSHA512& hasher) noexcept EXCLUSIVE_LOCKS_REQUIRED(!m_events_mutex) { // We use only SHA256 for the events hashing to get the ASM speedups we have for SHA256, // since we want it to be fast as network peers may be able to trigger it repeatedly. @@ -407,7 +407,7 @@ public: * * If this function has never been called with strong_seed = true, false is returned. */ - bool MixExtract(unsigned char* out, size_t num, CSHA512&& hasher, bool strong_seed) noexcept + bool MixExtract(unsigned char* out, size_t num, CSHA512&& hasher, bool strong_seed) noexcept EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) { assert(num <= 32); unsigned char buf[64]; diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 352df4d902..fb79e84c15 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1063,26 +1063,26 @@ static RPCHelpMan verifychain() }; } -static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softforks, const Consensus::Params& params, Consensus::BuriedDeployment dep) +static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softforks, const ChainstateManager& chainman, Consensus::BuriedDeployment dep) { // For buried deployments. - if (!DeploymentEnabled(params, dep)) return; + if (!DeploymentEnabled(chainman, dep)) return; UniValue rv(UniValue::VOBJ); rv.pushKV("type", "buried"); // getdeploymentinfo reports the softfork as active from when the chain height is // one below the activation height - rv.pushKV("active", DeploymentActiveAfter(blockindex, params, dep)); - rv.pushKV("height", params.DeploymentHeight(dep)); + rv.pushKV("active", DeploymentActiveAfter(blockindex, chainman, dep)); + rv.pushKV("height", chainman.GetConsensus().DeploymentHeight(dep)); softforks.pushKV(DeploymentName(dep), rv); } -static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softforks, const Consensus::Params& consensusParams, Consensus::DeploymentPos id) +static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softforks, const ChainstateManager& chainman, Consensus::DeploymentPos id) { // For BIP9 deployments. - if (!DeploymentEnabled(consensusParams, id)) return; + if (!DeploymentEnabled(chainman, id)) return; if (blockindex == nullptr) return; auto get_state_name = [](const ThresholdState state) -> std::string { @@ -1098,29 +1098,29 @@ static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softfo UniValue bip9(UniValue::VOBJ); - const ThresholdState next_state = g_versionbitscache.State(blockindex, consensusParams, id); - const ThresholdState current_state = g_versionbitscache.State(blockindex->pprev, consensusParams, id); + const ThresholdState next_state = chainman.m_versionbitscache.State(blockindex, chainman.GetConsensus(), id); + const ThresholdState current_state = chainman.m_versionbitscache.State(blockindex->pprev, chainman.GetConsensus(), id); const bool has_signal = (ThresholdState::STARTED == current_state || ThresholdState::LOCKED_IN == current_state); // BIP9 parameters if (has_signal) { - bip9.pushKV("bit", consensusParams.vDeployments[id].bit); + bip9.pushKV("bit", chainman.GetConsensus().vDeployments[id].bit); } - bip9.pushKV("start_time", consensusParams.vDeployments[id].nStartTime); - bip9.pushKV("timeout", consensusParams.vDeployments[id].nTimeout); - bip9.pushKV("min_activation_height", consensusParams.vDeployments[id].min_activation_height); + bip9.pushKV("start_time", chainman.GetConsensus().vDeployments[id].nStartTime); + bip9.pushKV("timeout", chainman.GetConsensus().vDeployments[id].nTimeout); + bip9.pushKV("min_activation_height", chainman.GetConsensus().vDeployments[id].min_activation_height); // BIP9 status bip9.pushKV("status", get_state_name(current_state)); - bip9.pushKV("since", g_versionbitscache.StateSinceHeight(blockindex->pprev, consensusParams, id)); + bip9.pushKV("since", chainman.m_versionbitscache.StateSinceHeight(blockindex->pprev, chainman.GetConsensus(), id)); bip9.pushKV("status_next", get_state_name(next_state)); // BIP9 signalling status, if applicable if (has_signal) { UniValue statsUV(UniValue::VOBJ); std::vector<bool> signals; - BIP9Stats statsStruct = g_versionbitscache.Statistics(blockindex, consensusParams, id, &signals); + BIP9Stats statsStruct = chainman.m_versionbitscache.Statistics(blockindex, chainman.GetConsensus(), id, &signals); statsUV.pushKV("period", statsStruct.period); statsUV.pushKV("elapsed", statsStruct.elapsed); statsUV.pushKV("count", statsStruct.count); @@ -1141,7 +1141,7 @@ static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softfo UniValue rv(UniValue::VOBJ); rv.pushKV("type", "bip9"); if (ThresholdState::ACTIVE == next_state) { - rv.pushKV("height", g_versionbitscache.StateSinceHeight(blockindex, consensusParams, id)); + rv.pushKV("height", chainman.m_versionbitscache.StateSinceHeight(blockindex, chainman.GetConsensus(), id)); } rv.pushKV("active", ThresholdState::ACTIVE == next_state); rv.pushKV("bip9", bip9); @@ -1151,7 +1151,7 @@ static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softfo namespace { /* TODO: when -deprecatedrpc=softforks is removed, drop these */ -UniValue DeploymentInfo(const CBlockIndex* tip, const Consensus::Params& consensusParams); +UniValue DeploymentInfo(const CBlockIndex* tip, const ChainstateManager& chainman); extern const std::vector<RPCResult> RPCHelpForDeployment; } @@ -1177,7 +1177,7 @@ RPCHelpMan getblockchaininfo() {RPCResult::Type::STR_HEX, "chainwork", "total amount of work in active chain, in hexadecimal"}, {RPCResult::Type::NUM, "size_on_disk", "the estimated size of the block and undo files on disk"}, {RPCResult::Type::BOOL, "pruned", "if the blocks are subject to pruning"}, - {RPCResult::Type::NUM, "pruneheight", /*optional=*/true, "lowest-height complete block stored (only present if pruning is enabled)"}, + {RPCResult::Type::NUM, "pruneheight", /*optional=*/true, "height of the last block pruned, plus one (only present if pruning is enabled)"}, {RPCResult::Type::BOOL, "automatic_pruning", /*optional=*/true, "whether automatic pruning is enabled (only present if pruning is enabled)"}, {RPCResult::Type::NUM, "prune_target_size", /*optional=*/true, "the target size used by pruning (only present if automatic pruning is enabled)"}, {RPCResult::Type::OBJ_DYN, "softforks", /*optional=*/true, "(DEPRECATED, returned only if config option -deprecatedrpc=softforks is passed) status of softforks", @@ -1226,8 +1226,7 @@ RPCHelpMan getblockchaininfo() } if (IsDeprecatedRPCEnabled("softforks")) { - const Consensus::Params& consensusParams = Params().GetConsensus(); - obj.pushKV("softforks", DeploymentInfo(&tip, consensusParams)); + obj.pushKV("softforks", DeploymentInfo(&tip, chainman)); } obj.pushKV("warnings", GetWarnings(false).original); @@ -1262,16 +1261,16 @@ const std::vector<RPCResult> RPCHelpForDeployment{ }}, }; -UniValue DeploymentInfo(const CBlockIndex* blockindex, const Consensus::Params& consensusParams) +UniValue DeploymentInfo(const CBlockIndex* blockindex, const ChainstateManager& chainman) { UniValue softforks(UniValue::VOBJ); - SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_HEIGHTINCB); - SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_DERSIG); - SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_CLTV); - SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_CSV); - SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_SEGWIT); - SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_TESTDUMMY); - SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_TAPROOT); + SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_HEIGHTINCB); + SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_DERSIG); + SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_CLTV); + SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_CSV); + SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_SEGWIT); + SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_TESTDUMMY); + SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_TAPROOT); return softforks; } } // anon namespace @@ -1310,12 +1309,10 @@ static RPCHelpMan getdeploymentinfo() } } - const Consensus::Params& consensusParams = Params().GetConsensus(); - UniValue deploymentinfo(UniValue::VOBJ); deploymentinfo.pushKV("hash", blockindex->GetBlockHash().ToString()); deploymentinfo.pushKV("height", blockindex->nHeight); - deploymentinfo.pushKV("deployments", DeploymentInfo(blockindex, consensusParams)); + deploymentinfo.pushKV("deployments", DeploymentInfo(blockindex, chainman)); return deploymentinfo; }, }; diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index b552528951..568474fcb9 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -133,7 +133,7 @@ static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t& } std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(block); - if (!chainman.ProcessNewBlock(chainparams, shared_pblock, true, nullptr)) { + if (!chainman.ProcessNewBlock(shared_pblock, true, nullptr)) { throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); } @@ -770,7 +770,7 @@ static RPCHelpMan getblocktemplate() pblock->nNonce = 0; // NOTE: If at some point we support pre-segwit miners post-segwit-activation, this needs to take segwit support into consideration - const bool fPreSegWit = !DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT); + const bool fPreSegWit = !DeploymentActiveAfter(pindexPrev, chainman, Consensus::DEPLOYMENT_SEGWIT); UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal"); @@ -836,7 +836,7 @@ static RPCHelpMan getblocktemplate() UniValue vbavailable(UniValue::VOBJ); for (int j = 0; j < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) { Consensus::DeploymentPos pos = Consensus::DeploymentPos(j); - ThresholdState state = g_versionbitscache.State(pindexPrev, consensusParams, pos); + ThresholdState state = chainman.m_versionbitscache.State(pindexPrev, consensusParams, pos); switch (state) { case ThresholdState::DEFINED: case ThresholdState::FAILED: @@ -844,7 +844,7 @@ static RPCHelpMan getblocktemplate() break; case ThresholdState::LOCKED_IN: // Ensure bit is set in block version - pblock->nVersion |= g_versionbitscache.Mask(consensusParams, pos); + pblock->nVersion |= chainman.m_versionbitscache.Mask(consensusParams, pos); [[fallthrough]]; case ThresholdState::STARTED: { @@ -853,7 +853,7 @@ static RPCHelpMan getblocktemplate() if (setClientRules.find(vbinfo.name) == setClientRules.end()) { if (!vbinfo.gbt_force) { // If the client doesn't support this, don't indicate it in the [default] version - pblock->nVersion &= ~g_versionbitscache.Mask(consensusParams, pos); + pblock->nVersion &= ~chainman.m_versionbitscache.Mask(consensusParams, pos); } } break; @@ -993,14 +993,14 @@ static RPCHelpMan submitblock() LOCK(cs_main); const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock); if (pindex) { - UpdateUncommittedBlockStructures(block, pindex, Params().GetConsensus()); + chainman.UpdateUncommittedBlockStructures(block, pindex); } } bool new_block; auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash()); RegisterSharedValidationInterface(sc); - bool accepted = chainman.ProcessNewBlock(Params(), blockptr, /*force_processing=*/true, /*new_block=*/&new_block); + bool accepted = chainman.ProcessNewBlock(blockptr, /*force_processing=*/true, /*new_block=*/&new_block); UnregisterSharedValidationInterface(sc); if (!new_block && accepted) { return "duplicate"; @@ -1042,7 +1042,7 @@ static RPCHelpMan submitheader() } BlockValidationState state; - chainman.ProcessNewBlockHeaders({h}, state, Params()); + chainman.ProcessNewBlockHeaders({h}, state); if (state.IsValid()) return NullUniValue; if (state.IsError()) { throw JSONRPCError(RPC_VERIFY_ERROR, state.ToString()); diff --git a/src/scheduler.h b/src/scheduler.h index b8245f97ed..749e5442b0 100644 --- a/src/scheduler.h +++ b/src/scheduler.h @@ -46,10 +46,10 @@ public: typedef std::function<void()> Function; /** Call func at/after time t */ - void schedule(Function f, std::chrono::steady_clock::time_point t); + void schedule(Function f, std::chrono::steady_clock::time_point t) EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex); /** Call f once after the delta has passed */ - void scheduleFromNow(Function f, std::chrono::milliseconds delta) + void scheduleFromNow(Function f, std::chrono::milliseconds delta) EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex) { schedule(std::move(f), std::chrono::steady_clock::now() + delta); } @@ -60,29 +60,29 @@ public: * The timing is not exact: Every time f is finished, it is rescheduled to run again after delta. If you need more * accurate scheduling, don't use this method. */ - void scheduleEvery(Function f, std::chrono::milliseconds delta); + void scheduleEvery(Function f, std::chrono::milliseconds delta) EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex); /** * Mock the scheduler to fast forward in time. * Iterates through items on taskQueue and reschedules them * to be delta_seconds sooner. */ - void MockForward(std::chrono::seconds delta_seconds); + void MockForward(std::chrono::seconds delta_seconds) EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex); /** * Services the queue 'forever'. Should be run in a thread. */ - void serviceQueue(); + void serviceQueue() EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex); /** Tell any threads running serviceQueue to stop as soon as the current task is done */ - void stop() + void stop() EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex) { WITH_LOCK(newTaskMutex, stopRequested = true); newTaskScheduled.notify_all(); if (m_service_thread.joinable()) m_service_thread.join(); } /** Tell any threads running serviceQueue to stop when there is no work left to be done */ - void StopWhenDrained() + void StopWhenDrained() EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex) { WITH_LOCK(newTaskMutex, stopWhenEmpty = true); newTaskScheduled.notify_all(); @@ -94,10 +94,11 @@ public: * and first and last task times */ size_t getQueueInfo(std::chrono::steady_clock::time_point& first, - std::chrono::steady_clock::time_point& last) const; + std::chrono::steady_clock::time_point& last) const + EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex); /** Returns true if there are threads actively running in serviceQueue() */ - bool AreThreadsServicingQueue() const; + bool AreThreadsServicingQueue() const EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex); private: mutable Mutex newTaskMutex; @@ -128,8 +129,8 @@ private: std::list<std::function<void()>> m_callbacks_pending GUARDED_BY(m_callbacks_mutex); bool m_are_callbacks_running GUARDED_BY(m_callbacks_mutex) = false; - void MaybeScheduleProcessQueue(); - void ProcessQueue(); + void MaybeScheduleProcessQueue() EXCLUSIVE_LOCKS_REQUIRED(!m_callbacks_mutex); + void ProcessQueue() EXCLUSIVE_LOCKS_REQUIRED(!m_callbacks_mutex); public: explicit SingleThreadedSchedulerClient(CScheduler& scheduler LIFETIMEBOUND) : m_scheduler{scheduler} {} @@ -140,15 +141,15 @@ public: * Practically, this means that callbacks can behave as if they are executed * in order by a single thread. */ - void AddToProcessQueue(std::function<void()> func); + void AddToProcessQueue(std::function<void()> func) EXCLUSIVE_LOCKS_REQUIRED(!m_callbacks_mutex); /** * Processes all remaining queue members on the calling thread, blocking until queue is empty * Must be called after the CScheduler has no remaining processing threads! */ - void EmptyQueue(); + void EmptyQueue() EXCLUSIVE_LOCKS_REQUIRED(!m_callbacks_mutex); - size_t CallbacksPending(); + size_t CallbacksPending() EXCLUSIVE_LOCKS_REQUIRED(!m_callbacks_mutex); }; #endif // BITCOIN_SCHEDULER_H diff --git a/src/sync.h b/src/sync.h index c69b58741b..a175926113 100644 --- a/src/sync.h +++ b/src/sync.h @@ -83,8 +83,6 @@ void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLi inline void DeleteLock(void* cs) {} inline bool LockStackEmpty() { return true; } #endif -#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) -#define AssertLockNotHeld(cs) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs) /** * Template mixin that adds -Wthread-safety locking annotations and lock order @@ -129,7 +127,13 @@ public: using RecursiveMutex = AnnotatedMixin<std::recursive_mutex>; /** Wrapped mutex: supports waiting but not recursive locking */ -typedef AnnotatedMixin<std::mutex> Mutex; +using Mutex = AnnotatedMixin<std::mutex>; + +#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) + +inline void AssertLockNotHeldInline(const char* name, const char* file, int line, Mutex* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) { AssertLockNotHeldInternal(name, file, line, cs); } +inline void AssertLockNotHeldInline(const char* name, const char* file, int line, RecursiveMutex* cs) LOCKS_EXCLUDED(cs) { AssertLockNotHeldInternal(name, file, line, cs); } +#define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) /** Wrapper around std::unique_lock style lock for Mutex. */ template <typename Mutex, typename Base = typename Mutex::UniqueLock> diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp index 82b9617384..ffb9fb55d9 100644 --- a/src/test/blockfilter_index_tests.cpp +++ b/src/test/blockfilter_index_tests.cpp @@ -101,7 +101,7 @@ bool BuildChainTestingSetup::BuildChain(const CBlockIndex* pindex, CBlockHeader header = block->GetBlockHeader(); BlockValidationState state; - if (!Assert(m_node.chainman)->ProcessNewBlockHeaders({header}, state, Params(), &pindex)) { + if (!Assert(m_node.chainman)->ProcessNewBlockHeaders({header}, state, &pindex)) { return false; } } @@ -178,7 +178,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup) uint256 chainA_last_header = last_header; for (size_t i = 0; i < 2; i++) { const auto& block = chainA[i]; - BOOST_REQUIRE(Assert(m_node.chainman)->ProcessNewBlock(Params(), block, true, nullptr)); + BOOST_REQUIRE(Assert(m_node.chainman)->ProcessNewBlock(block, true, nullptr)); } for (size_t i = 0; i < 2; i++) { const auto& block = chainA[i]; @@ -196,7 +196,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup) uint256 chainB_last_header = last_header; for (size_t i = 0; i < 3; i++) { const auto& block = chainB[i]; - BOOST_REQUIRE(Assert(m_node.chainman)->ProcessNewBlock(Params(), block, true, nullptr)); + BOOST_REQUIRE(Assert(m_node.chainman)->ProcessNewBlock(block, true, nullptr)); } for (size_t i = 0; i < 3; i++) { const auto& block = chainB[i]; @@ -227,7 +227,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup) // Reorg back to chain A. for (size_t i = 2; i < 4; i++) { const auto& block = chainA[i]; - BOOST_REQUIRE(Assert(m_node.chainman)->ProcessNewBlock(Params(), block, true, nullptr)); + BOOST_REQUIRE(Assert(m_node.chainman)->ProcessNewBlock(block, true, nullptr)); } // Check that chain A and B blocks can be retrieved. diff --git a/src/test/fuzz/utxo_snapshot.cpp b/src/test/fuzz/utxo_snapshot.cpp index e513f1883c..33496a457e 100644 --- a/src/test/fuzz/utxo_snapshot.cpp +++ b/src/test/fuzz/utxo_snapshot.cpp @@ -58,7 +58,7 @@ FUZZ_TARGET_INIT(utxo_snapshot, initialize_chain) if (fuzzed_data_provider.ConsumeBool()) { for (const auto& block : *g_chain) { BlockValidationState dummy; - bool processed{chainman.ProcessNewBlockHeaders({*block}, dummy, ::Params())}; + bool processed{chainman.ProcessNewBlockHeaders({*block}, dummy)}; Assert(processed); const auto* index{WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(block->GetHash()))}; Assert(index); diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index cafa5710fa..0c3a13c5f8 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -587,7 +587,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) pblock->nNonce = bi.nonce; } std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock); - BOOST_CHECK(Assert(m_node.chainman)->ProcessNewBlock(chainparams, shared_pblock, true, nullptr)); + BOOST_CHECK(Assert(m_node.chainman)->ProcessNewBlock(shared_pblock, true, nullptr)); pblock->hashPrevBlock = pblock->GetHash(); } diff --git a/src/test/util/mining.cpp b/src/test/util/mining.cpp index 5ed8598e8e..52e02c4fa4 100644 --- a/src/test/util/mining.cpp +++ b/src/test/util/mining.cpp @@ -68,7 +68,7 @@ CTxIn MineBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey) assert(block->nNonce); } - bool processed{Assert(node.chainman)->ProcessNewBlock(Params(), block, true, nullptr)}; + bool processed{Assert(node.chainman)->ProcessNewBlock(block, true, nullptr)}; assert(processed); return CTxIn{block->vtx[0]->GetHash(), 0}; diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 2fc71c2a6e..6891629f8e 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -151,6 +151,8 @@ BasicTestingSetup::~BasicTestingSetup() ChainTestingSetup::ChainTestingSetup(const std::string& chainName, const std::vector<const char*>& extra_args) : BasicTestingSetup(chainName, extra_args) { + const CChainParams& chainparams = Params(); + // We have to run a scheduler thread to prevent ActivateBestChain // from blocking due to queue overrun. m_node.scheduler = std::make_unique<CScheduler>(); @@ -162,7 +164,7 @@ ChainTestingSetup::ChainTestingSetup(const std::string& chainName, const std::ve m_cache_sizes = CalculateCacheSizes(m_args); - m_node.chainman = std::make_unique<ChainstateManager>(); + m_node.chainman = std::make_unique<ChainstateManager>(chainparams); m_node.chainman->m_blockman.m_block_tree_db = std::make_unique<CBlockTreeDB>(m_cache_sizes.block_tree_db, true); // Start script-checking threads. Set g_parallel_script_checks to true so they are used. @@ -298,10 +300,9 @@ CBlock TestChain100Setup::CreateAndProcessBlock( chainstate = &Assert(m_node.chainman)->ActiveChainstate(); } - const CChainParams& chainparams = Params(); const CBlock block = this->CreateBlock(txns, scriptPubKey, *chainstate); std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(block); - Assert(m_node.chainman)->ProcessNewBlock(chainparams, shared_pblock, true, nullptr); + Assert(m_node.chainman)->ProcessNewBlock(shared_pblock, true, nullptr); return block; } diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp index c5b1dabcb7..18882929a8 100644 --- a/src/test/validation_block_tests.cpp +++ b/src/test/validation_block_tests.cpp @@ -89,7 +89,7 @@ std::shared_ptr<CBlock> MinerTestingSetup::Block(const uint256& prev_hash) std::shared_ptr<CBlock> MinerTestingSetup::FinalizeBlock(std::shared_ptr<CBlock> pblock) { const CBlockIndex* prev_block{WITH_LOCK(::cs_main, return m_node.chainman->m_blockman.LookupBlockIndex(pblock->hashPrevBlock))}; - GenerateCoinbaseCommitment(*pblock, prev_block, Params().GetConsensus()); + m_node.chainman->GenerateCoinbaseCommitment(*pblock, prev_block); pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); @@ -100,7 +100,7 @@ std::shared_ptr<CBlock> MinerTestingSetup::FinalizeBlock(std::shared_ptr<CBlock> // submit block header, so that miner can get the block height from the // global state and the node has the topology of the chain BlockValidationState ignored; - BOOST_CHECK(Assert(m_node.chainman)->ProcessNewBlockHeaders({pblock->GetBlockHeader()}, ignored, Params())); + BOOST_CHECK(Assert(m_node.chainman)->ProcessNewBlockHeaders({pblock->GetBlockHeader()}, ignored)); return pblock; } @@ -157,7 +157,7 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering) bool ignored; // Connect the genesis block and drain any outstanding events - BOOST_CHECK(Assert(m_node.chainman)->ProcessNewBlock(Params(), std::make_shared<CBlock>(Params().GenesisBlock()), true, &ignored)); + BOOST_CHECK(Assert(m_node.chainman)->ProcessNewBlock(std::make_shared<CBlock>(Params().GenesisBlock()), true, &ignored)); SyncWithValidationInterfaceQueue(); // subscribe to events (this subscriber will validate event ordering) @@ -179,13 +179,13 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering) FastRandomContext insecure; for (int i = 0; i < 1000; i++) { auto block = blocks[insecure.randrange(blocks.size() - 1)]; - Assert(m_node.chainman)->ProcessNewBlock(Params(), block, true, &ignored); + Assert(m_node.chainman)->ProcessNewBlock(block, true, &ignored); } // to make sure that eventually we process the full chain - do it here for (auto block : blocks) { if (block->vtx.size() == 1) { - bool processed = Assert(m_node.chainman)->ProcessNewBlock(Params(), block, true, &ignored); + bool processed = Assert(m_node.chainman)->ProcessNewBlock(block, true, &ignored); assert(processed); } } @@ -224,7 +224,7 @@ BOOST_AUTO_TEST_CASE(mempool_locks_reorg) { bool ignored; auto ProcessBlock = [&](std::shared_ptr<const CBlock> block) -> bool { - return Assert(m_node.chainman)->ProcessNewBlock(Params(), block, /*force_processing=*/true, /*new_block=*/&ignored); + return Assert(m_node.chainman)->ProcessNewBlock(block, /*force_processing=*/true, /*new_block=*/&ignored); }; // Process all mined blocks diff --git a/src/test/validation_chainstate_tests.cpp b/src/test/validation_chainstate_tests.cpp index 2a3990bb7c..e7c7584f1c 100644 --- a/src/test/validation_chainstate_tests.cpp +++ b/src/test/validation_chainstate_tests.cpp @@ -22,7 +22,8 @@ BOOST_FIXTURE_TEST_SUITE(validation_chainstate_tests, TestingSetup) //! BOOST_AUTO_TEST_CASE(validation_chainstate_resize_caches) { - ChainstateManager manager; + const CChainParams& chainparams = Params(); + ChainstateManager manager(chainparams); WITH_LOCK(::cs_main, manager.m_blockman.m_block_tree_db = std::make_unique<CBlockTreeDB>(1 << 20, true)); CTxMemPool mempool; diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp index bf87812a8a..faea0ce7af 100644 --- a/src/test/versionbits_tests.cpp +++ b/src/test/versionbits_tests.cpp @@ -5,7 +5,6 @@ #include <chain.h> #include <chainparams.h> #include <consensus/params.h> -#include <deploymentstatus.h> #include <test/util/setup_common.h> #include <validation.h> #include <versionbits.h> @@ -257,10 +256,10 @@ BOOST_AUTO_TEST_CASE(versionbits_test) } /** Check that ComputeBlockVersion will set the appropriate bit correctly */ -static void check_computeblockversion(const Consensus::Params& params, Consensus::DeploymentPos dep) +static void check_computeblockversion(VersionBitsCache& versionbitscache, const Consensus::Params& params, Consensus::DeploymentPos dep) { - // This implicitly uses g_versionbitscache, so clear it every time - g_versionbitscache.Clear(); + // Clear the cache everytime + versionbitscache.Clear(); int64_t bit = params.vDeployments[dep].bit; int64_t nStartTime = params.vDeployments[dep].nStartTime; @@ -268,7 +267,7 @@ static void check_computeblockversion(const Consensus::Params& params, Consensus int min_activation_height = params.vDeployments[dep].min_activation_height; // should not be any signalling for first block - BOOST_CHECK_EQUAL(g_versionbitscache.ComputeBlockVersion(nullptr, params), VERSIONBITS_TOP_BITS); + BOOST_CHECK_EQUAL(versionbitscache.ComputeBlockVersion(nullptr, params), VERSIONBITS_TOP_BITS); // always/never active deployments shouldn't need to be tested further if (nStartTime == Consensus::BIP9Deployment::ALWAYS_ACTIVE || @@ -288,7 +287,7 @@ static void check_computeblockversion(const Consensus::Params& params, Consensus // Check min_activation_height is on a retarget boundary BOOST_REQUIRE_EQUAL(min_activation_height % params.nMinerConfirmationWindow, 0U); - const uint32_t bitmask{g_versionbitscache.Mask(params, dep)}; + const uint32_t bitmask{versionbitscache.Mask(params, dep)}; BOOST_CHECK_EQUAL(bitmask, uint32_t{1} << bit); // In the first chain, test that the bit is set by CBV until it has failed. @@ -307,9 +306,9 @@ static void check_computeblockversion(const Consensus::Params& params, Consensus // earlier time, so will transition from DEFINED to STARTED at the // end of the first period by mining blocks at nTime == 0 lastBlock = firstChain.Mine(params.nMinerConfirmationWindow - 1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); - BOOST_CHECK_EQUAL(g_versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit), 0); + BOOST_CHECK_EQUAL(versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit), 0); lastBlock = firstChain.Mine(params.nMinerConfirmationWindow, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); - BOOST_CHECK((g_versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit)) != 0); + BOOST_CHECK((versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit)) != 0); // then we'll keep mining at nStartTime... } else { // use a time 1s earlier than start time to check we stay DEFINED @@ -317,28 +316,28 @@ static void check_computeblockversion(const Consensus::Params& params, Consensus // Start generating blocks before nStartTime lastBlock = firstChain.Mine(params.nMinerConfirmationWindow, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); - BOOST_CHECK_EQUAL(g_versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit), 0); + BOOST_CHECK_EQUAL(versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit), 0); // Mine more blocks (4 less than the adjustment period) at the old time, and check that CBV isn't setting the bit yet. for (uint32_t i = 1; i < params.nMinerConfirmationWindow - 4; i++) { lastBlock = firstChain.Mine(params.nMinerConfirmationWindow + i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); - BOOST_CHECK_EQUAL(g_versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit), 0); + BOOST_CHECK_EQUAL(versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit), 0); } // Now mine 5 more blocks at the start time -- MTP should not have passed yet, so // CBV should still not yet set the bit. nTime = nStartTime; for (uint32_t i = params.nMinerConfirmationWindow - 4; i <= params.nMinerConfirmationWindow; i++) { lastBlock = firstChain.Mine(params.nMinerConfirmationWindow + i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); - BOOST_CHECK_EQUAL(g_versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit), 0); + BOOST_CHECK_EQUAL(versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit), 0); } // Next we will advance to the next period and transition to STARTED, } lastBlock = firstChain.Mine(params.nMinerConfirmationWindow * 3, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); // so ComputeBlockVersion should now set the bit, - BOOST_CHECK((g_versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit)) != 0); + BOOST_CHECK((versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit)) != 0); // and should also be using the VERSIONBITS_TOP_BITS. - BOOST_CHECK_EQUAL(g_versionbitscache.ComputeBlockVersion(lastBlock, params) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS); + BOOST_CHECK_EQUAL(versionbitscache.ComputeBlockVersion(lastBlock, params) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS); // Check that ComputeBlockVersion will set the bit until nTimeout nTime += 600; @@ -347,8 +346,8 @@ static void check_computeblockversion(const Consensus::Params& params, Consensus // These blocks are all before nTimeout is reached. while (nTime < nTimeout && blocksToMine > 0) { lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); - BOOST_CHECK((g_versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit)) != 0); - BOOST_CHECK_EQUAL(g_versionbitscache.ComputeBlockVersion(lastBlock, params) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS); + BOOST_CHECK((versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit)) != 0); + BOOST_CHECK_EQUAL(versionbitscache.ComputeBlockVersion(lastBlock, params) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS); blocksToMine--; nTime += 600; nHeight += 1; @@ -362,7 +361,7 @@ static void check_computeblockversion(const Consensus::Params& params, Consensus // finish the last period before we start timing out while (nHeight % params.nMinerConfirmationWindow != 0) { lastBlock = firstChain.Mine(nHeight+1, nTime - 1, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); - BOOST_CHECK((g_versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit)) != 0); + BOOST_CHECK((versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit)) != 0); nHeight += 1; } @@ -370,12 +369,12 @@ static void check_computeblockversion(const Consensus::Params& params, Consensus // the bit until the period transition. for (uint32_t i = 0; i < params.nMinerConfirmationWindow - 1; i++) { lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); - BOOST_CHECK((g_versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit)) != 0); + BOOST_CHECK((versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit)) != 0); nHeight += 1; } // The next block should trigger no longer setting the bit. lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); - BOOST_CHECK_EQUAL(g_versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit), 0); + BOOST_CHECK_EQUAL(versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit), 0); } // On a new chain: @@ -386,34 +385,36 @@ static void check_computeblockversion(const Consensus::Params& params, Consensus // Mine one period worth of blocks, and check that the bit will be on for the // next period. lastBlock = secondChain.Mine(params.nMinerConfirmationWindow, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); - BOOST_CHECK((g_versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit)) != 0); + BOOST_CHECK((versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit)) != 0); // Mine another period worth of blocks, signaling the new bit. lastBlock = secondChain.Mine(params.nMinerConfirmationWindow * 2, nTime, VERSIONBITS_TOP_BITS | (1<<bit)).Tip(); // After one period of setting the bit on each block, it should have locked in. // We keep setting the bit for one more period though, until activation. - BOOST_CHECK((g_versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit)) != 0); + BOOST_CHECK((versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit)) != 0); // Now check that we keep mining the block until the end of this period, and // then stop at the beginning of the next period. lastBlock = secondChain.Mine((params.nMinerConfirmationWindow * 3) - 1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); - BOOST_CHECK((g_versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit)) != 0); + BOOST_CHECK((versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit)) != 0); lastBlock = secondChain.Mine(params.nMinerConfirmationWindow * 3, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); if (lastBlock->nHeight + 1 < min_activation_height) { // check signalling continues while min_activation_height is not reached lastBlock = secondChain.Mine(min_activation_height - 1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); - BOOST_CHECK((g_versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit)) != 0); + BOOST_CHECK((versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit)) != 0); // then reach min_activation_height, which was already REQUIRE'd to start a new period lastBlock = secondChain.Mine(min_activation_height, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); } // Check that we don't signal after activation - BOOST_CHECK_EQUAL(g_versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit), 0); + BOOST_CHECK_EQUAL(versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit), 0); } BOOST_AUTO_TEST_CASE(versionbits_computeblockversion) { + VersionBitsCache vbcache; // don't use chainman versionbitscache since we want custom chain params + // check that any deployment on any chain can conceivably reach both // ACTIVE and FAILED states in roughly the way we expect for (const auto& chain_name : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::SIGNET, CBaseChainParams::REGTEST}) { @@ -426,10 +427,10 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion) // not take precedence over STARTED/LOCKED_IN. So all softforks on // the same bit might overlap, even when non-overlapping start-end // times are picked. - const uint32_t dep_mask{g_versionbitscache.Mask(chainParams->GetConsensus(), dep)}; + const uint32_t dep_mask{vbcache.Mask(chainParams->GetConsensus(), dep)}; BOOST_CHECK(!(chain_all_vbits & dep_mask)); chain_all_vbits |= dep_mask; - check_computeblockversion(chainParams->GetConsensus(), dep); + check_computeblockversion(vbcache, chainParams->GetConsensus(), dep); } } @@ -439,7 +440,7 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion) ArgsManager args; args.ForceSetArg("-vbparams", "testdummy:1199145601:1230767999"); // January 1, 2008 - December 31, 2008 const auto chainParams = CreateChainParams(args, CBaseChainParams::REGTEST); - check_computeblockversion(chainParams->GetConsensus(), Consensus::DEPLOYMENT_TESTDUMMY); + check_computeblockversion(vbcache, chainParams->GetConsensus(), Consensus::DEPLOYMENT_TESTDUMMY); } { @@ -449,7 +450,7 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion) ArgsManager args; args.ForceSetArg("-vbparams", "testdummy:1199145601:1230767999:403200"); // January 1, 2008 - December 31, 2008, min act height 403200 const auto chainParams = CreateChainParams(args, CBaseChainParams::REGTEST); - check_computeblockversion(chainParams->GetConsensus(), Consensus::DEPLOYMENT_TESTDUMMY); + check_computeblockversion(vbcache, chainParams->GetConsensus(), Consensus::DEPLOYMENT_TESTDUMMY); } } diff --git a/src/threadinterrupt.h b/src/threadinterrupt.h index cb9a5fbf8b..992016b4f6 100644 --- a/src/threadinterrupt.h +++ b/src/threadinterrupt.h @@ -21,11 +21,11 @@ class CThreadInterrupt public: CThreadInterrupt(); explicit operator bool() const; - void operator()(); + void operator()() EXCLUSIVE_LOCKS_REQUIRED(!mut); void reset(); - bool sleep_for(std::chrono::milliseconds rel_time); - bool sleep_for(std::chrono::seconds rel_time); - bool sleep_for(std::chrono::minutes rel_time); + bool sleep_for(std::chrono::milliseconds rel_time) EXCLUSIVE_LOCKS_REQUIRED(!mut); + bool sleep_for(std::chrono::seconds rel_time) EXCLUSIVE_LOCKS_REQUIRED(!mut); + bool sleep_for(std::chrono::minutes rel_time) EXCLUSIVE_LOCKS_REQUIRED(!mut); private: std::condition_variable cond; diff --git a/src/validation.cpp b/src/validation.cpp index b5d6a66088..51d77b7945 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -16,7 +16,6 @@ #include <consensus/tx_verify.h> #include <consensus/validation.h> #include <cuckoocache.h> -#include <deploymentstatus.h> #include <flatfile.h> #include <hash.h> #include <logging.h> @@ -262,7 +261,7 @@ bool CheckSequenceLocksAtTip(CBlockIndex* tip, } // Returns the script flags which should be checked for a given block -static unsigned int GetBlockScriptFlags(const CBlockIndex& block_index, const Consensus::Params& chainparams); +static unsigned int GetBlockScriptFlags(const CBlockIndex& block_index, const ChainstateManager& chainman); static void LimitMempoolSize(CTxMemPool& pool, CCoinsViewCache& coins_cache, size_t limit, std::chrono::seconds age) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, pool.cs) @@ -1027,7 +1026,6 @@ bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws) const CTransaction& tx = *ws.m_ptx; const uint256& hash = ws.m_hash; TxValidationState& state = ws.m_state; - const CChainParams& chainparams = args.m_chainparams; // Check again against the current block tip's script verification // flags to cache our script execution flags. This is, of course, @@ -1044,7 +1042,7 @@ bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws) // There is a similar check in CreateNewBlock() to prevent creating // invalid blocks (using TestBlockValidity), however allowing such // transactions into the mempool can be exploited as a DoS attack. - unsigned int currentBlockScriptVerifyFlags{GetBlockScriptFlags(*m_active_chainstate.m_chain.Tip(), chainparams.GetConsensus())}; + unsigned int currentBlockScriptVerifyFlags{GetBlockScriptFlags(*m_active_chainstate.m_chain.Tip(), m_active_chainstate.m_chainman)}; if (!CheckInputsFromMempoolAndCache(tx, state, m_view, m_pool, currentBlockScriptVerifyFlags, ws.m_precomputed_txdata, m_active_chainstate.CoinsTip())) { LogPrintf("BUG! PLEASE REPORT THIS! CheckInputScripts failed against latest-block but not STANDARD flags %s, %s\n", hash.ToString(), state.ToString()); @@ -1457,7 +1455,7 @@ PackageMempoolAcceptResult ProcessNewPackage(CChainState& active_chainstate, CTx assert(std::all_of(package.cbegin(), package.cend(), [](const auto& tx){return tx != nullptr;})); std::vector<COutPoint> coins_to_uncache; - const CChainParams& chainparams = Params(); + const CChainParams& chainparams = active_chainstate.m_params; const auto result = [&]() EXCLUSIVE_LOCKS_REQUIRED(cs_main) { AssertLockHeld(cs_main); if (test_accept) { @@ -1515,7 +1513,7 @@ CChainState::CChainState( std::optional<uint256> from_snapshot_blockhash) : m_mempool(mempool), m_blockman(blockman), - m_params(::Params()), + m_params(chainman.GetParams()), m_chainman(chainman), m_from_snapshot_blockhash(from_snapshot_blockhash) {} @@ -1909,10 +1907,11 @@ void StopScriptCheckWorkerThreads() class WarningBitsConditionChecker : public AbstractThresholdConditionChecker { private: - int bit; + const ChainstateManager& m_chainman; + int m_bit; public: - explicit WarningBitsConditionChecker(int bitIn) : bit(bitIn) {} + explicit WarningBitsConditionChecker(const ChainstateManager& chainman, int bit) : m_chainman{chainman}, m_bit(bit) {} int64_t BeginTime(const Consensus::Params& params) const override { return 0; } int64_t EndTime(const Consensus::Params& params) const override { return std::numeric_limits<int64_t>::max(); } @@ -1923,15 +1922,17 @@ public: { return pindex->nHeight >= params.MinBIP9WarningHeight && ((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && - ((pindex->nVersion >> bit) & 1) != 0 && - ((g_versionbitscache.ComputeBlockVersion(pindex->pprev, params) >> bit) & 1) == 0; + ((pindex->nVersion >> m_bit) & 1) != 0 && + ((m_chainman.m_versionbitscache.ComputeBlockVersion(pindex->pprev, params) >> m_bit) & 1) == 0; } }; static std::array<ThresholdConditionCache, VERSIONBITS_NUM_BITS> warningcache GUARDED_BY(cs_main); -static unsigned int GetBlockScriptFlags(const CBlockIndex& block_index, const Consensus::Params& consensusparams) +static unsigned int GetBlockScriptFlags(const CBlockIndex& block_index, const ChainstateManager& chainman) { + const Consensus::Params& consensusparams = chainman.GetConsensus(); + // BIP16 didn't become active until Apr 1 2012 (on mainnet, and // retroactively applied to testnet) // However, only one historical block violated the P2SH rules (on both @@ -1947,22 +1948,22 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex& block_index, const Co } // Enforce the DERSIG (BIP66) rule - if (DeploymentActiveAt(block_index, consensusparams, Consensus::DEPLOYMENT_DERSIG)) { + if (DeploymentActiveAt(block_index, chainman, Consensus::DEPLOYMENT_DERSIG)) { flags |= SCRIPT_VERIFY_DERSIG; } // Enforce CHECKLOCKTIMEVERIFY (BIP65) - if (DeploymentActiveAt(block_index, consensusparams, Consensus::DEPLOYMENT_CLTV)) { + if (DeploymentActiveAt(block_index, chainman, Consensus::DEPLOYMENT_CLTV)) { flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY; } // Enforce CHECKSEQUENCEVERIFY (BIP112) - if (DeploymentActiveAt(block_index, consensusparams, Consensus::DEPLOYMENT_CSV)) { + if (DeploymentActiveAt(block_index, chainman, Consensus::DEPLOYMENT_CSV)) { flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY; } // Enforce BIP147 NULLDUMMY (activated simultaneously with segwit) - if (DeploymentActiveAt(block_index, consensusparams, Consensus::DEPLOYMENT_SEGWIT)) { + if (DeploymentActiveAt(block_index, chainman, Consensus::DEPLOYMENT_SEGWIT)) { flags |= SCRIPT_VERIFY_NULLDUMMY; } @@ -2153,12 +2154,12 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state, // Enforce BIP68 (sequence locks) int nLockTimeFlags = 0; - if (DeploymentActiveAt(*pindex, m_params.GetConsensus(), Consensus::DEPLOYMENT_CSV)) { + if (DeploymentActiveAt(*pindex, m_chainman, Consensus::DEPLOYMENT_CSV)) { nLockTimeFlags |= LOCKTIME_VERIFY_SEQUENCE; } // Get the script flags for this block - unsigned int flags{GetBlockScriptFlags(*pindex, m_params.GetConsensus())}; + unsigned int flags{GetBlockScriptFlags(*pindex, m_chainman)}; int64_t nTime2 = GetTimeMicros(); nTimeForks += nTime2 - nTime1; LogPrint(BCLog::BENCH, " - Fork checks: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime2 - nTime1), nTimeForks * MICRO, nTimeForks * MILLI / nBlocksTotal); @@ -2454,9 +2455,9 @@ bool CChainState::FlushStateToDisk( full_flush_completed = true; TRACE5(utxocache, flush, (int64_t)(GetTimeMicros() - nNow.count()), // in microseconds (µs) - (u_int32_t)mode, - (u_int64_t)coins_count, - (u_int64_t)coins_mem_usage, + (uint32_t)mode, + (uint64_t)coins_count, + (uint64_t)coins_mem_usage, (bool)fFlushForPrune); } } @@ -2556,7 +2557,7 @@ void CChainState::UpdateTip(const CBlockIndex* pindexNew) if (!this->IsInitialBlockDownload()) { const CBlockIndex* pindex = pindexNew; for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) { - WarningBitsConditionChecker checker(bit); + WarningBitsConditionChecker checker(m_chainman, bit); ThresholdState state = checker.GetStateFor(pindex, m_params.GetConsensus(), warningcache.at(bit)); if (state == ThresholdState::ACTIVE || state == ThresholdState::LOCKED_IN) { const bilingual_str warning = strprintf(_("Unknown new rules activated (versionbit %i)"), bit); @@ -3280,7 +3281,7 @@ void CChainState::ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pi pindexNew->nDataPos = pos.nPos; pindexNew->nUndoPos = 0; pindexNew->nStatus |= BLOCK_HAVE_DATA; - if (DeploymentActiveAt(*pindexNew, m_params.GetConsensus(), Consensus::DEPLOYMENT_SEGWIT)) { + if (DeploymentActiveAt(*pindexNew, m_chainman, Consensus::DEPLOYMENT_SEGWIT)) { pindexNew->nStatus |= BLOCK_OPT_WITNESS; } pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS); @@ -3398,11 +3399,11 @@ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensu return true; } -void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams) +void ChainstateManager::UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPrev) const { int commitpos = GetWitnessCommitmentIndex(block); static const std::vector<unsigned char> nonce(32, 0x00); - if (commitpos != NO_WITNESS_COMMITMENT && DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT) && !block.vtx[0]->HasWitness()) { + if (commitpos != NO_WITNESS_COMMITMENT && DeploymentActiveAfter(pindexPrev, *this, Consensus::DEPLOYMENT_SEGWIT) && !block.vtx[0]->HasWitness()) { CMutableTransaction tx(*block.vtx[0]); tx.vin[0].scriptWitness.stack.resize(1); tx.vin[0].scriptWitness.stack[0] = nonce; @@ -3410,7 +3411,7 @@ void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPr } } -std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams) +std::vector<unsigned char> ChainstateManager::GenerateCoinbaseCommitment(CBlock& block, const CBlockIndex* pindexPrev) const { std::vector<unsigned char> commitment; int commitpos = GetWitnessCommitmentIndex(block); @@ -3433,7 +3434,7 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc tx.vout.push_back(out); block.vtx[0] = MakeTransactionRef(std::move(tx)); } - UpdateUncommittedBlockStructures(block, pindexPrev, consensusParams); + UpdateUncommittedBlockStructures(block, pindexPrev); return commitment; } @@ -3446,14 +3447,14 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc * in ConnectBlock(). * Note that -reindex-chainstate skips the validation that happens here! */ -static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidationState& state, BlockManager& blockman, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) +static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidationState& state, BlockManager& blockman, const ChainstateManager& chainman, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { AssertLockHeld(::cs_main); assert(pindexPrev != nullptr); const int nHeight = pindexPrev->nHeight + 1; // Check proof of work - const Consensus::Params& consensusParams = params.GetConsensus(); + const Consensus::Params& consensusParams = chainman.GetConsensus(); if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams)) return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "bad-diffbits", "incorrect proof of work"); @@ -3462,7 +3463,7 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidatio // Don't accept any forks from the main chain prior to last checkpoint. // GetLastCheckpoint finds the last checkpoint in MapCheckpoints that's in our // BlockIndex(). - const CBlockIndex* pcheckpoint = blockman.GetLastCheckpoint(params.Checkpoints()); + const CBlockIndex* pcheckpoint = blockman.GetLastCheckpoint(chainman.GetParams().Checkpoints()); if (pcheckpoint && nHeight < pcheckpoint->nHeight) { LogPrintf("ERROR: %s: forked chain older than last checkpoint (height %d)\n", __func__, nHeight); return state.Invalid(BlockValidationResult::BLOCK_CHECKPOINT, "bad-fork-prior-to-checkpoint"); @@ -3478,9 +3479,9 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidatio return state.Invalid(BlockValidationResult::BLOCK_TIME_FUTURE, "time-too-new", "block timestamp too far in the future"); // Reject blocks with outdated version - if ((block.nVersion < 2 && DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_HEIGHTINCB)) || - (block.nVersion < 3 && DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_DERSIG)) || - (block.nVersion < 4 && DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_CLTV))) { + if ((block.nVersion < 2 && DeploymentActiveAfter(pindexPrev, chainman, Consensus::DEPLOYMENT_HEIGHTINCB)) || + (block.nVersion < 3 && DeploymentActiveAfter(pindexPrev, chainman, Consensus::DEPLOYMENT_DERSIG)) || + (block.nVersion < 4 && DeploymentActiveAfter(pindexPrev, chainman, Consensus::DEPLOYMENT_CLTV))) { return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, strprintf("bad-version(0x%08x)", block.nVersion), strprintf("rejected nVersion=0x%08x block", block.nVersion)); } @@ -3494,13 +3495,13 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidatio * in ConnectBlock(). * Note that -reindex-chainstate skips the validation that happens here! */ -static bool ContextualCheckBlock(const CBlock& block, BlockValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev) +static bool ContextualCheckBlock(const CBlock& block, BlockValidationState& state, const ChainstateManager& chainman, const CBlockIndex* pindexPrev) { const int nHeight = pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1; // Enforce BIP113 (Median Time Past). int nLockTimeFlags = 0; - if (DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_CSV)) { + if (DeploymentActiveAfter(pindexPrev, chainman, Consensus::DEPLOYMENT_CSV)) { assert(pindexPrev != nullptr); nLockTimeFlags |= LOCKTIME_MEDIAN_TIME_PAST; } @@ -3517,7 +3518,7 @@ static bool ContextualCheckBlock(const CBlock& block, BlockValidationState& stat } // Enforce rule that the coinbase starts with serialized block height - if (DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_HEIGHTINCB)) + if (DeploymentActiveAfter(pindexPrev, chainman, Consensus::DEPLOYMENT_HEIGHTINCB)) { CScript expect = CScript() << nHeight; if (block.vtx[0]->vin[0].scriptSig.size() < expect.size() || @@ -3535,7 +3536,7 @@ static bool ContextualCheckBlock(const CBlock& block, BlockValidationState& stat // {0xaa, 0x21, 0xa9, 0xed}, and the following 32 bytes are SHA256^2(witness root, witness reserved value). In case there are // multiple, the last one is used. bool fHaveWitness = false; - if (DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT)) { + if (DeploymentActiveAfter(pindexPrev, chainman, Consensus::DEPLOYMENT_SEGWIT)) { int commitpos = GetWitnessCommitmentIndex(block); if (commitpos != NO_WITNESS_COMMITMENT) { bool malleated = false; @@ -3576,13 +3577,13 @@ static bool ContextualCheckBlock(const CBlock& block, BlockValidationState& stat return true; } -bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex) +bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValidationState& state, CBlockIndex** ppindex) { AssertLockHeld(cs_main); // Check for duplicate uint256 hash = block.GetHash(); BlockMap::iterator miSelf{m_blockman.m_block_index.find(hash)}; - if (hash != chainparams.GetConsensus().hashGenesisBlock) { + if (hash != GetConsensus().hashGenesisBlock) { if (miSelf != m_blockman.m_block_index.end()) { // Block header is already known. CBlockIndex* pindex = &(miSelf->second); @@ -3595,7 +3596,7 @@ bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValida return true; } - if (!CheckBlockHeader(block, state, chainparams.GetConsensus())) { + if (!CheckBlockHeader(block, state, GetConsensus())) { LogPrint(BCLog::VALIDATION, "%s: Consensus::CheckBlockHeader: %s, %s\n", __func__, hash.ToString(), state.ToString()); return false; } @@ -3612,7 +3613,7 @@ bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValida LogPrint(BCLog::VALIDATION, "%s: %s prev block invalid\n", __func__, hash.ToString()); return state.Invalid(BlockValidationResult::BLOCK_INVALID_PREV, "bad-prevblk"); } - if (!ContextualCheckBlockHeader(block, state, m_blockman, chainparams, pindexPrev, GetAdjustedTime())) { + if (!ContextualCheckBlockHeader(block, state, m_blockman, *this, pindexPrev, GetAdjustedTime())) { LogPrint(BCLog::VALIDATION, "%s: Consensus::ContextualCheckBlockHeader: %s, %s\n", __func__, hash.ToString(), state.ToString()); return false; } @@ -3665,14 +3666,14 @@ bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValida } // Exposed wrapper for AcceptBlockHeader -bool ChainstateManager::ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, BlockValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex) +bool ChainstateManager::ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, BlockValidationState& state, const CBlockIndex** ppindex) { AssertLockNotHeld(cs_main); { LOCK(cs_main); for (const CBlockHeader& header : headers) { CBlockIndex *pindex = nullptr; // Use a temp pindex instead of ppindex to avoid a const_cast - bool accepted{AcceptBlockHeader(header, state, chainparams, &pindex)}; + bool accepted{AcceptBlockHeader(header, state, &pindex)}; ActiveChainstate().CheckBlockIndex(); if (!accepted) { @@ -3686,7 +3687,7 @@ bool ChainstateManager::ProcessNewBlockHeaders(const std::vector<CBlockHeader>& if (NotifyHeaderTip(ActiveChainstate())) { if (ActiveChainstate().IsInitialBlockDownload() && ppindex && *ppindex) { const CBlockIndex& last_accepted{**ppindex}; - const int64_t blocks_left{(GetTime() - last_accepted.GetBlockTime()) / chainparams.GetConsensus().nPowTargetSpacing}; + const int64_t blocks_left{(GetTime() - last_accepted.GetBlockTime()) / GetConsensus().nPowTargetSpacing}; const double progress{100.0 * last_accepted.nHeight / (last_accepted.nHeight + blocks_left)}; LogPrintf("Synchronizing blockheaders, height: %d (~%.2f%%)\n", last_accepted.nHeight, progress); } @@ -3705,7 +3706,7 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, Block CBlockIndex *pindexDummy = nullptr; CBlockIndex *&pindex = ppindex ? *ppindex : pindexDummy; - bool accepted_header{m_chainman.AcceptBlockHeader(block, state, m_params, &pindex)}; + bool accepted_header{m_chainman.AcceptBlockHeader(block, state, &pindex)}; CheckBlockIndex(); if (!accepted_header) @@ -3745,7 +3746,7 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, Block } if (!CheckBlock(block, state, m_params.GetConsensus()) || - !ContextualCheckBlock(block, state, m_params.GetConsensus(), pindex->pprev)) { + !ContextualCheckBlock(block, state, m_chainman, pindex->pprev)) { if (state.IsInvalid() && state.GetResult() != BlockValidationResult::BLOCK_MUTATED) { pindex->nStatus |= BLOCK_FAILED_VALID; m_blockman.m_dirty_blockindex.insert(pindex); @@ -3778,7 +3779,7 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, Block return true; } -bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock>& block, bool force_processing, bool* new_block) +bool ChainstateManager::ProcessNewBlock(const std::shared_ptr<const CBlock>& block, bool force_processing, bool* new_block) { AssertLockNotHeld(cs_main); @@ -3796,7 +3797,7 @@ bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const s // malleability that cause CheckBlock() to fail; see e.g. CVE-2012-2459 and // https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-February/016697.html. Because CheckBlock() is // not very expensive, the anti-DoS benefits of caching failure (of a definitely-invalid block) are not substantial. - bool ret = CheckBlock(*block, state, chainparams.GetConsensus()); + bool ret = CheckBlock(*block, state, GetConsensus()); if (ret) { // Store to disk ret = ActiveChainstate().AcceptBlock(block, state, &pindex, force_processing, nullptr, new_block); @@ -3849,11 +3850,11 @@ bool TestBlockValidity(BlockValidationState& state, indexDummy.phashBlock = &block_hash; // NOTE: CheckBlockHeader is called by CheckBlock - if (!ContextualCheckBlockHeader(block, state, chainstate.m_blockman, chainparams, pindexPrev, GetAdjustedTime())) + if (!ContextualCheckBlockHeader(block, state, chainstate.m_blockman, chainstate.m_chainman, pindexPrev, GetAdjustedTime())) return error("%s: Consensus::ContextualCheckBlockHeader: %s", __func__, state.ToString()); if (!CheckBlock(block, state, chainparams.GetConsensus(), fCheckPOW, fCheckMerkleRoot)) return error("%s: Consensus::CheckBlock: %s", __func__, state.ToString()); - if (!ContextualCheckBlock(block, state, chainparams.GetConsensus(), pindexPrev)) + if (!ContextualCheckBlock(block, state, chainstate.m_chainman, pindexPrev)) return error("%s: Consensus::ContextualCheckBlock: %s", __func__, state.ToString()); if (!chainstate.ConnectBlock(block, state, &indexDummy, viewNew, true)) { return false; @@ -4133,7 +4134,7 @@ bool CChainState::NeedsRedownload() const // At and above m_params.SegwitHeight, segwit consensus rules must be validated CBlockIndex* block{m_chain.Tip()}; - while (block != nullptr && DeploymentActiveAt(*block, m_params.GetConsensus(), Consensus::DEPLOYMENT_SEGWIT)) { + while (block != nullptr && DeploymentActiveAt(*block, m_chainman, Consensus::DEPLOYMENT_SEGWIT)) { if (!(block->nStatus & BLOCK_OPT_WITNESS)) { // block is insufficiently validated for a segwit client return true; @@ -4993,7 +4994,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot( } int base_height = snapshot_start_block->nHeight; - auto maybe_au_data = ExpectedAssumeutxo(base_height, ::Params()); + auto maybe_au_data = ExpectedAssumeutxo(base_height, GetParams()); if (!maybe_au_data) { LogPrintf("[snapshot] assumeutxo height in snapshot metadata not recognized " /* Continued */ @@ -5147,7 +5148,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot( // Fake BLOCK_OPT_WITNESS so that CChainState::NeedsRedownload() // won't ask to rewind the entire assumed-valid chain on startup. - if (DeploymentActiveAt(*index, ::Params().GetConsensus(), Consensus::DEPLOYMENT_SEGWIT)) { + if (DeploymentActiveAt(*index, *this, Consensus::DEPLOYMENT_SEGWIT)) { index->nStatus |= BLOCK_OPT_WITNESS; } @@ -5216,9 +5217,9 @@ ChainstateManager::~ChainstateManager() { LOCK(::cs_main); - // TODO: The version bits cache and warning cache should probably become - // non-globals - g_versionbitscache.Clear(); + m_versionbitscache.Clear(); + + // TODO: The warning cache should probably become non-global for (auto& i : warningcache) { i.clear(); } diff --git a/src/validation.h b/src/validation.h index 42e41502f9..04745a6e36 100644 --- a/src/validation.h +++ b/src/validation.h @@ -13,7 +13,9 @@ #include <arith_uint256.h> #include <attributes.h> #include <chain.h> +#include <chainparams.h> #include <consensus/amount.h> +#include <deploymentstatus.h> #include <fs.h> #include <node/blockstorage.h> #include <policy/feerate.h> @@ -26,6 +28,7 @@ #include <util/check.h> #include <util/hasher.h> #include <util/translation.h> +#include <versionbits.h> #include <atomic> #include <map> @@ -40,7 +43,6 @@ class CChainState; class CBlockTreeDB; -class CChainParams; class CTxMemPool; class ChainstateManager; struct ChainTxData; @@ -51,6 +53,9 @@ struct AssumeutxoData; namespace node { class SnapshotMetadata; } // namespace node +namespace Consensus { +struct Params; +} // namespace Consensus /** Default for -minrelaytxfee, minimum relay fee for transactions */ static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 1000; @@ -359,12 +364,6 @@ bool TestBlockValidity(BlockValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true) EXCLUSIVE_LOCKS_REQUIRED(cs_main); -/** Update uncommitted block structures (currently: only the witness reserved value). This is safe for submitted blocks. */ -void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams); - -/** Produce the necessary coinbase commitment for a block (modifies the hash, don't call for mined blocks). */ -std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams); - /** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */ class CVerifyDB { public: @@ -495,6 +494,7 @@ public: node::BlockManager& m_blockman; /** Chain parameters for this chainstate */ + /* TODO: replace with m_chainman.GetParams() */ const CChainParams& m_params; //! The chainstate manager that owns this chainstate. The reference is @@ -834,6 +834,8 @@ private: CBlockIndex* m_best_invalid GUARDED_BY(::cs_main){nullptr}; + const CChainParams& m_chainparams; + //! Internal helper for ActivateSnapshot(). [[nodiscard]] bool PopulateAndValidateSnapshot( CChainState& snapshot_chainstate, @@ -847,11 +849,15 @@ private: bool AcceptBlockHeader( const CBlockHeader& block, BlockValidationState& state, - const CChainParams& chainparams, CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); friend CChainState; public: + explicit ChainstateManager(const CChainParams& chainparams) : m_chainparams{chainparams} { } + + const CChainParams& GetParams() const { return m_chainparams; } + const Consensus::Params& GetConsensus() const { return m_chainparams.GetConsensus(); } + std::thread m_load_block; //! A single BlockManager instance is shared across each constructed //! chainstate to avoid duplicating block metadata. @@ -932,6 +938,11 @@ public: return m_blockman.m_block_index; } + /** + * Track versionbit status + */ + mutable VersionBitsCache m_versionbitscache; + //! @returns true if a snapshot-based chainstate is in use. Also implies //! that a background validation chainstate is also in use. bool IsSnapshotActive() const; @@ -960,7 +971,7 @@ public: * @param[out] new_block A boolean which is set to indicate if the block was first received via this call * @returns If the block was processed, independently of block validity */ - bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock>& block, bool force_processing, bool* new_block) LOCKS_EXCLUDED(cs_main); + bool ProcessNewBlock(const std::shared_ptr<const CBlock>& block, bool force_processing, bool* new_block) LOCKS_EXCLUDED(cs_main); /** * Process incoming block headers. @@ -970,10 +981,9 @@ public: * * @param[in] block The block headers themselves * @param[out] state This may be set to an Error state if any error occurred processing them - * @param[in] chainparams The params for the chain we want to connect to * @param[out] ppindex If set, the pointer will be set to point to the last new block index object for the given headers */ - bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, BlockValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex = nullptr) LOCKS_EXCLUDED(cs_main); + bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, BlockValidationState& state, const CBlockIndex** ppindex = nullptr) LOCKS_EXCLUDED(cs_main); /** * Try to add a transaction to the memory pool. @@ -991,9 +1001,34 @@ public: //! ResizeCoinsCaches() as needed. void MaybeRebalanceCaches() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + /** Update uncommitted block structures (currently: only the witness reserved value). This is safe for submitted blocks. */ + void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPrev) const; + + /** Produce the necessary coinbase commitment for a block (modifies the hash, don't call for mined blocks). */ + std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBlockIndex* pindexPrev) const; + ~ChainstateManager(); }; +/** Deployment* info via ChainstateManager */ +template<typename DEP> +bool DeploymentActiveAfter(const CBlockIndex* pindexPrev, const ChainstateManager& chainman, DEP dep) +{ + return DeploymentActiveAfter(pindexPrev, chainman.GetConsensus(), dep, chainman.m_versionbitscache); +} + +template<typename DEP> +bool DeploymentActiveAt(const CBlockIndex& index, const ChainstateManager& chainman, DEP dep) +{ + return DeploymentActiveAt(index, chainman.GetConsensus(), dep, chainman.m_versionbitscache); +} + +template<typename DEP> +bool DeploymentEnabled(const ChainstateManager& chainman, DEP dep) +{ + return DeploymentEnabled(chainman.GetConsensus(), dep); +} + using FopenFn = std::function<FILE*(const fs::path&, const char*)>; /** Dump the mempool to disk. */ diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index edc4633c01..fffab39cc1 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -16,14 +16,16 @@ #include <unordered_map> #include <utility> -//! The MainSignalsInstance manages a list of shared_ptr<CValidationInterface> -//! callbacks. -//! -//! A std::unordered_map is used to track what callbacks are currently -//! registered, and a std::list is to used to store the callbacks that are -//! currently registered as well as any callbacks that are just unregistered -//! and about to be deleted when they are done executing. -struct MainSignalsInstance { +/** + * MainSignalsImpl manages a list of shared_ptr<CValidationInterface> callbacks. + * + * A std::unordered_map is used to track what callbacks are currently + * registered, and a std::list is used to store the callbacks that are + * currently registered as well as any callbacks that are just unregistered + * and about to be deleted when they are done executing. + */ +class MainSignalsImpl +{ private: Mutex m_mutex; //! List entries consist of a callback pointer and reference count. The @@ -40,9 +42,9 @@ public: // our own queue here :( SingleThreadedSchedulerClient m_schedulerClient; - explicit MainSignalsInstance(CScheduler& scheduler LIFETIMEBOUND) : m_schedulerClient(scheduler) {} + explicit MainSignalsImpl(CScheduler& scheduler LIFETIMEBOUND) : m_schedulerClient(scheduler) {} - void Register(std::shared_ptr<CValidationInterface> callbacks) + void Register(std::shared_ptr<CValidationInterface> callbacks) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) { LOCK(m_mutex); auto inserted = m_map.emplace(callbacks.get(), m_list.end()); @@ -50,7 +52,7 @@ public: inserted.first->second->callbacks = std::move(callbacks); } - void Unregister(CValidationInterface* callbacks) + void Unregister(CValidationInterface* callbacks) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) { LOCK(m_mutex); auto it = m_map.find(callbacks); @@ -64,7 +66,7 @@ public: //! map entry. After this call, the list may still contain callbacks that //! are currently executing, but it will be cleared when they are done //! executing. - void Clear() + void Clear() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) { LOCK(m_mutex); for (const auto& entry : m_map) { @@ -73,7 +75,7 @@ public: m_map.clear(); } - template<typename F> void Iterate(F&& f) + template<typename F> void Iterate(F&& f) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) { WAIT_LOCK(m_mutex, lock); for (auto it = m_list.begin(); it != m_list.end();) { @@ -92,7 +94,7 @@ static CMainSignals g_signals; void CMainSignals::RegisterBackgroundSignalScheduler(CScheduler& scheduler) { assert(!m_internals); - m_internals = std::make_unique<MainSignalsInstance>(scheduler); + m_internals = std::make_unique<MainSignalsImpl>(scheduler); } void CMainSignals::UnregisterBackgroundSignalScheduler() diff --git a/src/validationinterface.h b/src/validationinterface.h index ac62f8b467..a929a3d56b 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -17,9 +17,7 @@ class BlockValidationState; class CBlock; class CBlockIndex; struct CBlockLocator; -class CConnman; class CValidationInterface; -class uint256; class CScheduler; enum class MemPoolRemovalReason; @@ -177,10 +175,10 @@ protected: friend class ValidationInterfaceTest; }; -struct MainSignalsInstance; +class MainSignalsImpl; class CMainSignals { private: - std::unique_ptr<MainSignalsInstance> m_internals; + std::unique_ptr<MainSignalsImpl> m_internals; friend void ::RegisterSharedValidationInterface(std::shared_ptr<CValidationInterface>); friend void ::UnregisterValidationInterface(CValidationInterface*); diff --git a/src/versionbits.h b/src/versionbits.h index 1b3fa11e61..9f7ee1b48e 100644 --- a/src/versionbits.h +++ b/src/versionbits.h @@ -92,16 +92,16 @@ public: static uint32_t Mask(const Consensus::Params& params, Consensus::DeploymentPos pos); /** Get the BIP9 state for a given deployment for the block after pindexPrev. */ - ThresholdState State(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos); + ThresholdState State(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); /** Get the block height at which the BIP9 deployment switched into the state for the block after pindexPrev. */ - int StateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos); + int StateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); /** Determine what nVersion a new block should use */ - int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params); + int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); - void Clear(); + void Clear() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); }; #endif // BITCOIN_VERSIONBITS_H diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp index 1aa0339445..f8230f7a1d 100644 --- a/src/wallet/bdb.cpp +++ b/src/wallet/bdb.cpp @@ -99,7 +99,7 @@ void BerkeleyEnvironment::Close() if (ret != 0) LogPrintf("BerkeleyEnvironment::Close: Error %d closing database environment: %s\n", ret, DbEnv::strerror(ret)); if (!fMockDb) - DbEnv((u_int32_t)0).remove(strPath.c_str(), 0); + DbEnv((uint32_t)0).remove(strPath.c_str(), 0); if (error_file) fclose(error_file); @@ -248,7 +248,7 @@ const void* BerkeleyBatch::SafeDbt::get_data() const return m_dbt.get_data(); } -u_int32_t BerkeleyBatch::SafeDbt::get_size() const +uint32_t BerkeleyBatch::SafeDbt::get_size() const { return m_dbt.get_size(); } diff --git a/src/wallet/bdb.h b/src/wallet/bdb.h index 1c99e1f9af..ddab85521b 100644 --- a/src/wallet/bdb.h +++ b/src/wallet/bdb.h @@ -34,7 +34,7 @@ struct bilingual_str; namespace wallet { struct WalletDatabaseFileId { - u_int8_t value[DB_FILE_ID_LEN]; + uint8_t value[DB_FILE_ID_LEN]; bool operator==(const WalletDatabaseFileId& rhs) const; }; @@ -182,7 +182,7 @@ class BerkeleyBatch : public DatabaseBatch // delegate to Dbt const void* get_data() const; - u_int32_t get_size() const; + uint32_t get_size() const; // conversion operator to access the underlying Dbt operator Dbt*(); |