diff options
46 files changed, 399 insertions, 419 deletions
diff --git a/contrib/qos/tc.sh b/contrib/qos/tc.sh index 8408545a21..1cde19efd1 100644 --- a/contrib/qos/tc.sh +++ b/contrib/qos/tc.sh @@ -16,7 +16,7 @@ LOCALNET_V4="192.168.0.0/16" #defines the IPv6 address space for which you wish to disable rate limiting LOCALNET_V6="fe80::/10" -#delete existing rules +#delete existing rules ('Error: Cannot delete qdisc with handle of zero.' means there weren't any.) tc qdisc del dev ${IF} root #add root class diff --git a/doc/release-notes-18077.md b/doc/release-notes-18077.md deleted file mode 100644 index 4034a4c19c..0000000000 --- a/doc/release-notes-18077.md +++ /dev/null @@ -1,10 +0,0 @@ -P2P and network changes ------------------------ - -- Added NAT-PMP port mapping support via [`libnatpmp`](https://miniupnp.tuxfamily.org/libnatpmp.html) - -Command-line options --------------------- - -- The `-natpmp` option has been added to use NAT-PMP to map the listening port. If both UPnP -and NAT-PMP are enabled, a successful allocation from UPnP prevails over one from NAT-PMP. diff --git a/doc/release-notes-18466.md b/doc/release-notes-18466.md deleted file mode 100644 index e46d5064a3..0000000000 --- a/doc/release-notes-18466.md +++ /dev/null @@ -1,10 +0,0 @@ -Low-level RPC changes ---------------------- - -- Error codes have been updated to be more accurate for the following error cases (#18466): - - `signmessage` now returns RPC_INVALID_ADDRESS_OR_KEY (-5) if the - passed address is invalid. Previously returned RPC_TYPE_ERROR (-3). - - `verifymessage` now returns RPC_INVALID_ADDRESS_OR_KEY (-5) if the - passed address is invalid. Previously returned RPC_TYPE_ERROR (-3). - - `verifymessage` now returns RPC_TYPE_ERROR (-3) if the passed signature - is malformed. Previously returned RPC_INVALID_ADDRESS_OR_KEY (-5). diff --git a/doc/release-notes-19776.md b/doc/release-notes-19776.md deleted file mode 100644 index 5553c5a7bd..0000000000 --- a/doc/release-notes-19776.md +++ /dev/null @@ -1,9 +0,0 @@ -Updated RPCs ------------- - -- The `getpeerinfo` RPC returns two new boolean fields, `bip152_hb_to` and - `bip152_hb_from`, that respectively indicate whether we selected a peer to be - in compact blocks high-bandwidth mode or whether a peer selected us as a - compact blocks high-bandwidth peer. High-bandwidth peers send new block - announcements via a `cmpctblock` message rather than the usual inv/headers - announcements. See BIP 152 for more details. (#19776) diff --git a/doc/release-notes-20861.md b/doc/release-notes-20861.md deleted file mode 100644 index 5c68e4ab0c..0000000000 --- a/doc/release-notes-20861.md +++ /dev/null @@ -1,13 +0,0 @@ -Updated RPCs ------------- - -- Due to [BIP 350](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki) - being implemented, behavior for all RPCs that accept addresses is changed when - a native witness version 1 (or higher) is passed. These now require a Bech32m - encoding instead of a Bech32 one, and Bech32m encoding will be used for such - addresses in RPC output as well. No version 1 addresses should be created - for mainnet until consensus rules are adopted that give them meaning - (e.g. through [BIP 341](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki)). - Once that happens, Bech32m is expected to be used for them, so this shouldn't - affect any production systems, but may be observed on other networks where such - addresses already have meaning (like signet). diff --git a/doc/release-notes.md b/doc/release-notes.md index e46380b38f..334dfa80a4 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -59,8 +59,30 @@ Notable changes P2P and network changes ----------------------- +- Added NAT-PMP port mapping support via + [`libnatpmp`](https://miniupnp.tuxfamily.org/libnatpmp.html). (#18077) + Updated RPCs ------------ + +- Due to [BIP 350](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki) + being implemented, behavior for all RPCs that accept addresses is changed when + a native witness version 1 (or higher) is passed. These now require a Bech32m + encoding instead of a Bech32 one, and Bech32m encoding will be used for such + addresses in RPC output as well. No version 1 addresses should be created + for mainnet until consensus rules are adopted that give them meaning + (e.g. through [BIP 341](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki)). + Once that happens, Bech32m is expected to be used for them, so this shouldn't + affect any production systems, but may be observed on other networks where such + addresses already have meaning (like signet). (#20861) + +- The `getpeerinfo` RPC returns two new boolean fields, `bip152_hb_to` and + `bip152_hb_from`, that respectively indicate whether we selected a peer to be + in compact blocks high-bandwidth mode or whether a peer selected us as a + compact blocks high-bandwidth peer. High-bandwidth peers send new block + announcements via a `cmpctblock` message rather than the usual inv/headers + announcements. See BIP 152 for more details. (#19776) + - `getpeerinfo` no longer returns the following fields: `addnode`, `banscore`, and `whitelisted`, which were previously deprecated in 0.21. Instead of `addnode`, the `connection_type` field returns manual. Instead of @@ -72,8 +94,8 @@ Updated RPCs `/rest/getutxos`, `/rest/block` deprecated the following fields (which are no longer returned in the responses by default): `addresses`, `reqSigs`. The `-deprecatedrpc=addresses` flag must be passed for these fields to be - included in the RPC response. This flag/option will be available until v23, at which - point the deprecation will be removed entirely. Note that these fields are attributes of + included in the RPC response. This flag/option will be available only for this major release, after which + the deprecation will be removed entirely. Note that these fields are attributes of the `scriptPubKey` object returned in the RPC response. However, in the response of `decodescript` these fields are top-level attributes, and included again as attributes of the `scriptPubKey` object. (#20286) @@ -93,6 +115,10 @@ Build System New settings ------------ +- The `-natpmp` option has been added to use NAT-PMP to map the listening port. + If both UPnP and NAT-PMP are enabled, a successful allocation from UPnP + prevails over one from NAT-PMP. (#18077) + Updated settings ---------------- @@ -110,6 +136,9 @@ Wallet The RPC returns public versions of all imported descriptors, including their timestamp and flags. For ranged descriptors, it also returns the range boundaries and the next index to generate addresses from. (#20226) +- The `bumpfee` RPC is not available with wallets that have private keys + disabled. `psbtbumpfee` can be used instead. (#20891) + GUI changes ----------- @@ -118,11 +147,20 @@ Low-level changes RPC --- + - The RPC server can process a limited number of simultaneous RPC requests. - Previously, if this limit was exceeded, `bitcoind` would respond with + Previously, if this limit was exceeded, the RPC server would respond with [status code 500 (`HTTP_INTERNAL_SERVER_ERROR`)](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#5xx_server_errors). Now it returns status code 503 (`HTTP_SERVICE_UNAVAILABLE`). (#18335) +- Error codes have been updated to be more accurate for the following error cases (#18466): + - `signmessage` now returns RPC_INVALID_ADDRESS_OR_KEY (-5) if the + passed address is invalid. Previously returned RPC_TYPE_ERROR (-3). + - `verifymessage` now returns RPC_INVALID_ADDRESS_OR_KEY (-5) if the + passed address is invalid. Previously returned RPC_TYPE_ERROR (-3). + - `verifymessage` now returns RPC_TYPE_ERROR (-3) if the passed signature + is malformed. Previously returned RPC_INVALID_ADDRESS_OR_KEY (-5). + Tests ----- diff --git a/src/Makefile.am b/src/Makefile.am index 9903c2e9b3..4e09c86ebd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -243,7 +243,6 @@ BITCOIN_CORE_H = \ util/moneystr.h \ util/rbf.h \ util/readwritefile.h \ - util/ref.h \ util/settings.h \ util/sock.h \ util/spanparsing.h \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index e30f3985b9..570f011f7a 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -112,7 +112,6 @@ BITCOIN_TESTS =\ test/prevector_tests.cpp \ test/raii_event_tests.cpp \ test/random_tests.cpp \ - test/ref_tests.cpp \ test/reverselock_tests.cpp \ test/rpc_tests.cpp \ test/sanity_tests.cpp \ diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 1b4ca3e9a8..80ab69c131 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -16,7 +16,7 @@ #include <node/ui_interface.h> #include <noui.h> #include <shutdown.h> -#include <util/ref.h> +#include <util/check.h> #include <util/strencodings.h> #include <util/system.h> #include <util/threadnames.h> @@ -24,6 +24,7 @@ #include <util/translation.h> #include <util/url.h> +#include <any> #include <functional> #include <optional> @@ -142,7 +143,7 @@ static bool AppInit(int argc, char* argv[]) // end, which is interpreted as failure to start. TokenPipeEnd daemon_ep; #endif - util::Ref context{node}; + std::any context{&node}; try { if (!CheckDataDirOption()) { diff --git a/src/httprpc.cpp b/src/httprpc.cpp index 867ddb090e..16ab38e0b2 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -144,7 +144,7 @@ static bool RPCAuthorized(const std::string& strAuth, std::string& strAuthUserna return multiUserAuthorized(strUserPass); } -static bool HTTPReq_JSONRPC(const util::Ref& context, HTTPRequest* req) +static bool HTTPReq_JSONRPC(const std::any& context, HTTPRequest* req) { // JSONRPC handles only POST if (req->GetRequestMethod() != HTTPRequest::POST) { @@ -288,7 +288,7 @@ static bool InitRPCAuthentication() return true; } -bool StartHTTPRPC(const util::Ref& context) +bool StartHTTPRPC(const std::any& context) { LogPrint(BCLog::RPC, "Starting HTTP RPC server\n"); if (!InitRPCAuthentication()) diff --git a/src/httprpc.h b/src/httprpc.h index 97af6f7bb1..5a3b990646 100644 --- a/src/httprpc.h +++ b/src/httprpc.h @@ -5,14 +5,12 @@ #ifndef BITCOIN_HTTPRPC_H #define BITCOIN_HTTPRPC_H -namespace util { -class Ref; -} // namespace util +#include <any> /** Start HTTP RPC subsystem. * Precondition; HTTP and RPC has been started. */ -bool StartHTTPRPC(const util::Ref& context); +bool StartHTTPRPC(const std::any& context); /** Interrupt HTTP RPC subsystem. */ void InterruptHTTPRPC(); @@ -24,7 +22,7 @@ void StopHTTPRPC(); /** Start HTTP REST subsystem. * Precondition; HTTP and RPC has been started. */ -void StartREST(const util::Ref& context); +void StartREST(const std::any& context); /** Interrupt RPC REST subsystem. */ void InterruptREST(); diff --git a/src/init.cpp b/src/init.cpp index 8b1f531b81..17b216573f 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -788,7 +788,7 @@ static bool InitSanityCheck() return true; } -static bool AppInitServers(const util::Ref& context, NodeContext& node) +static bool AppInitServers(const std::any& context, NodeContext& node) { const ArgsManager& args = *Assert(node.args); RPCServer::OnStarted(&OnRPCStarted); @@ -1277,7 +1277,7 @@ bool AppInitInterfaces(NodeContext& node) return true; } -bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) +bool AppInitMain(const std::any& context, NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) { const ArgsManager& args = *Assert(node.args); const CChainParams& chainparams = Params(); diff --git a/src/init.h b/src/init.h index 34bca09dd1..5d01d4c1ac 100644 --- a/src/init.h +++ b/src/init.h @@ -6,6 +6,7 @@ #ifndef BITCOIN_INIT_H #define BITCOIN_INIT_H +#include <any> #include <memory> #include <string> @@ -22,9 +23,6 @@ struct BlockAndHeaderTipInfo; namespace boost { class thread_group; } // namespace boost -namespace util { -class Ref; -} // namespace util /** Interrupt threads */ void Interrupt(NodeContext& node); @@ -66,7 +64,7 @@ bool AppInitInterfaces(NodeContext& node); * @note This should only be done after daemonization. Call Shutdown() if this function fails. * @pre Parameters should be parsed and config file should be read, AppInitLockDataDirectory should have been called. */ -bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info = nullptr); +bool AppInitMain(const std::any& context, NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info = nullptr); /** * Register all arguments with the ArgsManager diff --git a/src/miner.cpp b/src/miner.cpp index fe7a54c052..8a9406f810 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -55,9 +55,10 @@ BlockAssembler::Options::Options() { nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT; } -BlockAssembler::BlockAssembler(const CTxMemPool& mempool, const CChainParams& params, const Options& options) +BlockAssembler::BlockAssembler(CChainState& chainstate, const CTxMemPool& mempool, const CChainParams& params, const Options& options) : chainparams(params), - m_mempool(mempool) + m_mempool(mempool), + m_chainstate(chainstate) { blockMinFeeRate = options.blockMinFeeRate; // Limit weight to between 4K and MAX_BLOCK_WEIGHT-4K for sanity: @@ -79,8 +80,8 @@ static BlockAssembler::Options DefaultOptions() return options; } -BlockAssembler::BlockAssembler(const CTxMemPool& mempool, const CChainParams& params) - : BlockAssembler(mempool, params, DefaultOptions()) {} +BlockAssembler::BlockAssembler(CChainState& chainstate, const CTxMemPool& mempool, const CChainParams& params) + : BlockAssembler(chainstate, mempool, params, DefaultOptions()) {} void BlockAssembler::resetBlock() { @@ -96,7 +97,7 @@ void BlockAssembler::resetBlock() nFees = 0; } -std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(CChainState& chainstate, const CScript& scriptPubKeyIn) +std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn) { int64_t nTimeStart = GetTimeMicros(); @@ -114,8 +115,8 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(CChainState& chai pblocktemplate->vTxSigOpsCost.push_back(-1); // updated at end LOCK2(cs_main, m_mempool.cs); - assert(std::addressof(*::ChainActive().Tip()) == std::addressof(*chainstate.m_chain.Tip())); - CBlockIndex* pindexPrev = chainstate.m_chain.Tip(); + assert(std::addressof(*::ChainActive().Tip()) == std::addressof(*m_chainstate.m_chain.Tip())); + CBlockIndex* pindexPrev = m_chainstate.m_chain.Tip(); assert(pindexPrev != nullptr); nHeight = pindexPrev->nHeight + 1; @@ -174,8 +175,8 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(CChainState& chai pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]); BlockValidationState state; - assert(std::addressof(::ChainstateActive()) == std::addressof(chainstate)); - if (!TestBlockValidity(state, chainparams, chainstate, *pblock, pindexPrev, false, false)) { + assert(std::addressof(::ChainstateActive()) == std::addressof(m_chainstate)); + if (!TestBlockValidity(state, chainparams, m_chainstate, *pblock, pindexPrev, false, false)) { throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, state.ToString())); } int64_t nTime2 = GetTimeMicros(); diff --git a/src/miner.h b/src/miner.h index 023635814c..c400c90f6c 100644 --- a/src/miner.h +++ b/src/miner.h @@ -146,6 +146,7 @@ private: int64_t nLockTimeCutoff; const CChainParams& chainparams; const CTxMemPool& m_mempool; + CChainState& m_chainstate; public: struct Options { @@ -154,11 +155,11 @@ public: CFeeRate blockMinFeeRate; }; - explicit BlockAssembler(const CTxMemPool& mempool, const CChainParams& params); - explicit BlockAssembler(const CTxMemPool& mempool, const CChainParams& params, const Options& options); + explicit BlockAssembler(CChainState& chainstate, const CTxMemPool& mempool, const CChainParams& params); + explicit BlockAssembler(CChainState& chainstate, const CTxMemPool& mempool, const CChainParams& params, const Options& options); /** Construct a new block template with coinbase to scriptPubKeyIn */ - std::unique_ptr<CBlockTemplate> CreateNewBlock(CChainState& chainstate, const CScript& scriptPubKeyIn); + std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn); inline static std::optional<int64_t> m_last_block_num_txs{}; inline static std::optional<int64_t> m_last_block_weight{}; @@ -201,6 +202,7 @@ private: void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce); int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev); +// TODO just accept a CBlockIndex* /** Update an old GenerateCoinbaseCommitment from CreateNewBlock after the block txs have changed */ void RegenerateCommitments(CBlock& block, BlockManager& blockman); diff --git a/src/net.cpp b/src/net.cpp index 1dcb141421..c43c53795e 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1255,9 +1255,10 @@ void CConnman::NotifyNumConnectionsChanged() } } -bool CConnman::RunInactivityChecks(const CNode& node) const +bool CConnman::ShouldRunInactivityChecks(const CNode& node, std::optional<int64_t> now_in) const { - return GetSystemTimeInSeconds() > node.nTimeConnected + m_peer_connect_timeout; + const int64_t now = now_in ? now_in.value() : GetSystemTimeInSeconds(); + return node.nTimeConnected + m_peer_connect_timeout < now; } bool CConnman::InactivityCheck(const CNode& node) const @@ -1266,6 +1267,8 @@ bool CConnman::InactivityCheck(const CNode& node) const // use setmocktime in the tests). int64_t now = GetSystemTimeInSeconds(); + if (!ShouldRunInactivityChecks(node, now)) return false; + if (node.nLastRecv == 0 || node.nLastSend == 0) { LogPrint(BCLog::NET, "socket no message in first %i seconds, %d %d peer=%d\n", m_peer_connect_timeout, node.nLastRecv != 0, node.nLastSend != 0, node.GetId()); return true; @@ -1562,7 +1565,7 @@ void CConnman::SocketHandler() if (bytes_sent) RecordBytesSent(bytes_sent); } - if (RunInactivityChecks(*pnode) && InactivityCheck(*pnode)) pnode->fDisconnect = true; + if (InactivityCheck(*pnode)) pnode->fDisconnect = true; } { LOCK(cs_vNodes); @@ -549,8 +549,9 @@ public: std::vector<CAddress> vAddrToSend; std::unique_ptr<CRollingBloomFilter> m_addr_known{nullptr}; bool fGetAddr{false}; - std::chrono::microseconds m_next_addr_send GUARDED_BY(cs_sendProcessing){0}; - std::chrono::microseconds m_next_local_addr_send GUARDED_BY(cs_sendProcessing){0}; + Mutex m_addr_send_times_mutex; + std::chrono::microseconds m_next_addr_send GUARDED_BY(m_addr_send_times_mutex){0}; + std::chrono::microseconds m_next_local_addr_send GUARDED_BY(m_addr_send_times_mutex){0}; struct TxRelay { mutable RecursiveMutex cs_filter; @@ -1017,8 +1018,8 @@ public: void SetAsmap(std::vector<bool> asmap) { addrman.m_asmap = std::move(asmap); } - /** Return true if the peer has been connected for long enough to do inactivity checks. */ - bool RunInactivityChecks(const CNode& node) const; + /** Return true if we should disconnect the peer for failing an inactivity check. */ + bool ShouldRunInactivityChecks(const CNode& node, std::optional<int64_t> now=std::nullopt) const; private: struct ListenSocket { diff --git a/src/net_processing.cpp b/src/net_processing.cpp index e4054968c0..4108de2c8a 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -33,6 +33,7 @@ #include <util/system.h> #include <validation.h> +#include <algorithm> #include <memory> #include <optional> #include <typeinfo> @@ -317,8 +318,13 @@ private: void PushNodeVersion(CNode& pnode, int64_t nTime); /** Send a ping message every PING_INTERVAL or if requested via RPC. May - * mark the peer to be disconnected if a ping has timed out. */ - void MaybeSendPing(CNode& node_to, Peer& peer); + * mark the peer to be disconnected if a ping has timed out. + * We use mockable time for ping timeouts, so setmocktime may cause pings + * to time out. */ + void MaybeSendPing(CNode& node_to, Peer& peer, std::chrono::microseconds now); + + /** Send `addr` messages on a regular schedule. */ + void MaybeSendAddr(CNode& node, std::chrono::microseconds current_time); const CChainParams& m_chainparams; CConnman& m_connman; @@ -476,19 +482,70 @@ private: /** Offset into vExtraTxnForCompact to insert the next tx */ size_t vExtraTxnForCompactIt GUARDED_BY(g_cs_orphans) = 0; + /** Check whether the last unknown block a peer advertised is not yet known. */ void ProcessBlockAvailability(NodeId nodeid) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + /** Update tracking information about which blocks a peer is assumed to have. */ void UpdateBlockAvailability(NodeId nodeid, const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main); bool CanDirectFetch() EXCLUSIVE_LOCKS_REQUIRED(cs_main); + + /** + * To prevent fingerprinting attacks, only send blocks/headers outside of + * the active chain if they are no more than a month older (both in time, + * and in best equivalent proof of work) than the best header chain we know + * about and we fully-validated them at some point. + */ bool BlockRequestAllowed(const CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); bool AlreadyHaveBlock(const uint256& block_hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main); void ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& inv); + + /** + * Validation logic for compact filters request handling. + * + * May disconnect from the peer in the case of a bad request. + * + * @param[in] peer The peer that we received the request from + * @param[in] filter_type The filter type the request is for. Must be basic filters. + * @param[in] start_height The start height for the request + * @param[in] stop_hash The stop_hash for the request + * @param[in] max_height_diff The maximum number of items permitted to request, as specified in BIP 157 + * @param[out] stop_index The CBlockIndex for the stop_hash block, if the request can be serviced. + * @param[out] filter_index The filter index, if the request can be serviced. + * @return True if the request can be serviced. + */ bool PrepareBlockFilterRequest(CNode& peer, BlockFilterType filter_type, uint32_t start_height, const uint256& stop_hash, uint32_t max_height_diff, const CBlockIndex*& stop_index, BlockFilterIndex*& filter_index); + + /** + * Handle a cfilters request. + * + * May disconnect from the peer in the case of a bad request. + * + * @param[in] peer The peer that we received the request from + * @param[in] vRecv The raw message received + */ void ProcessGetCFilters(CNode& peer, CDataStream& vRecv); + + /** + * Handle a cfheaders request. + * + * May disconnect from the peer in the case of a bad request. + * + * @param[in] peer The peer that we received the request from + * @param[in] vRecv The raw message received + */ void ProcessGetCFHeaders(CNode& peer, CDataStream& vRecv); + + /** + * Handle a getcfcheckpt request. + * + * May disconnect from the peer in the case of a bad request. + * + * @param[in] peer The peer that we received the request from + * @param[in] vRecv The raw message received + */ void ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv); }; } // namespace @@ -742,7 +799,6 @@ static bool PeerHasHeader(CNodeState *state, const CBlockIndex *pindex) EXCLUSIV return false; } -/** Check whether the last unknown block a peer advertised is not yet known. */ void PeerManagerImpl::ProcessBlockAvailability(NodeId nodeid) { CNodeState *state = State(nodeid); assert(state != nullptr); @@ -758,7 +814,6 @@ void PeerManagerImpl::ProcessBlockAvailability(NodeId nodeid) { } } -/** Update tracking information about which blocks a peer is assumed to have. */ void PeerManagerImpl::UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) { CNodeState *state = State(nodeid); assert(state != nullptr); @@ -1185,16 +1240,6 @@ bool PeerManagerImpl::MaybePunishNodeForTx(NodeId nodeid, const TxValidationStat return false; } - -////////////////////////////////////////////////////////////////////////////// -// -// blockchain -> download logic notification -// - -// To prevent fingerprinting attacks, only send blocks/headers outside of the -// active chain if they are no more than a month older (both in time, and in -// best equivalent proof of work) than the best header chain we know about and -// we fully-validated them at some point. bool PeerManagerImpl::BlockRequestAllowed(const CBlockIndex* pindex) { AssertLockHeld(cs_main); @@ -2095,20 +2140,6 @@ void PeerManagerImpl::ProcessOrphanTx(std::set<uint256>& orphan_work_set) m_mempool.check(m_chainman.ActiveChainstate()); } -/** - * Validation logic for compact filters request handling. - * - * May disconnect from the peer in the case of a bad request. - * - * @param[in] peer The peer that we received the request from - * @param[in] filter_type The filter type the request is for. Must be basic filters. - * @param[in] start_height The start height for the request - * @param[in] stop_hash The stop_hash for the request - * @param[in] max_height_diff The maximum number of items permitted to request, as specified in BIP 157 - * @param[out] stop_index The CBlockIndex for the stop_hash block, if the request can be serviced. - * @param[out] filter_index The filter index, if the request can be serviced. - * @return True if the request can be serviced. - */ bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& peer, BlockFilterType filter_type, uint32_t start_height, const uint256& stop_hash, uint32_t max_height_diff, @@ -2162,14 +2193,6 @@ bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& peer, return true; } -/** - * Handle a cfilters request. - * - * May disconnect from the peer in the case of a bad request. - * - * @param[in] peer The peer that we received the request from - * @param[in] vRecv The raw message received - */ void PeerManagerImpl::ProcessGetCFilters(CNode& peer, CDataStream& vRecv) { uint8_t filter_type_ser; @@ -2201,14 +2224,6 @@ void PeerManagerImpl::ProcessGetCFilters(CNode& peer, CDataStream& vRecv) } } -/** - * Handle a cfheaders request. - * - * May disconnect from the peer in the case of a bad request. - * - * @param[in] peer The peer that we received the request from - * @param[in] vRecv The raw message received - */ void PeerManagerImpl::ProcessGetCFHeaders(CNode& peer, CDataStream& vRecv) { uint8_t filter_type_ser; @@ -2253,14 +2268,6 @@ void PeerManagerImpl::ProcessGetCFHeaders(CNode& peer, CDataStream& vRecv) m_connman.PushMessage(&peer, std::move(msg)); } -/** - * Handle a getcfcheckpt request. - * - * May disconnect from the peer in the case of a bad request. - * - * @param[in] peer The peer that we received the request from - * @param[in] vRecv The raw message received - */ void PeerManagerImpl::ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv) { uint8_t filter_type_ser; @@ -4100,13 +4107,9 @@ void PeerManagerImpl::CheckForStaleTipAndEvictPeers() } } -void PeerManagerImpl::MaybeSendPing(CNode& node_to, Peer& peer) +void PeerManagerImpl::MaybeSendPing(CNode& node_to, Peer& peer, std::chrono::microseconds now) { - // Use mockable time for ping timeouts. - // This means that setmocktime may cause pings to time out. - auto now = GetTime<std::chrono::microseconds>(); - - if (m_connman.RunInactivityChecks(node_to) && peer.m_ping_nonce_sent && + if (m_connman.ShouldRunInactivityChecks(node_to) && peer.m_ping_nonce_sent && now > peer.m_ping_start.load() + std::chrono::seconds{TIMEOUT_INTERVAL}) { LogPrint(BCLog::NET, "ping timeout: %fs peer=%d\n", 0.000001 * count_microseconds(now - peer.m_ping_start.load()), peer.m_id); node_to.fDisconnect = true; @@ -4144,6 +4147,75 @@ void PeerManagerImpl::MaybeSendPing(CNode& node_to, Peer& peer) } } +void PeerManagerImpl::MaybeSendAddr(CNode& node, std::chrono::microseconds current_time) +{ + // Nothing to do for non-address-relay peers + if (!node.RelayAddrsWithConn()) return; + + assert(node.m_addr_known); + + LOCK(node.m_addr_send_times_mutex); + // Periodically advertise our local address to the peer. + if (fListen && !m_chainman.ActiveChainstate().IsInitialBlockDownload() && + node.m_next_local_addr_send < current_time) { + // If we've sent before, clear the bloom filter for the peer, so that our + // self-announcement will actually go out. + // This might be unnecessary if the bloom filter has already rolled + // over since our last self-announcement, but there is only a small + // bandwidth cost that we can incur by doing this (which happens + // once a day on average). + if (node.m_next_local_addr_send != 0us) { + node.m_addr_known->reset(); + } + if (std::optional<CAddress> local_addr = GetLocalAddrForPeer(&node)) { + FastRandomContext insecure_rand; + node.PushAddress(*local_addr, insecure_rand); + } + node.m_next_local_addr_send = PoissonNextSend(current_time, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL); + } + + // We sent an `addr` message to this peer recently. Nothing more to do. + if (current_time <= node.m_next_addr_send) return; + + node.m_next_addr_send = PoissonNextSend(current_time, AVG_ADDRESS_BROADCAST_INTERVAL); + + if (!Assume(node.vAddrToSend.size() <= MAX_ADDR_TO_SEND)) { + // Should be impossible since we always check size before adding to + // vAddrToSend. Recover by trimming the vector. + node.vAddrToSend.resize(MAX_ADDR_TO_SEND); + } + + // Remove addr records that the peer already knows about, and add new + // addrs to the m_addr_known filter on the same pass. + auto addr_already_known = [&node](const CAddress& addr) { + bool ret = node.m_addr_known->contains(addr.GetKey()); + if (!ret) node.m_addr_known->insert(addr.GetKey()); + return ret; + }; + node.vAddrToSend.erase(std::remove_if(node.vAddrToSend.begin(), node.vAddrToSend.end(), addr_already_known), + node.vAddrToSend.end()); + + // No addr messages to send + if (node.vAddrToSend.empty()) return; + + const char* msg_type; + int make_flags; + if (node.m_wants_addrv2) { + msg_type = NetMsgType::ADDRV2; + make_flags = ADDRV2_FORMAT; + } else { + msg_type = NetMsgType::ADDR; + make_flags = 0; + } + m_connman.PushMessage(&node, CNetMsgMaker(node.GetCommonVersion()).Make(make_flags, msg_type, node.vAddrToSend)); + node.vAddrToSend.clear(); + + // we only send the big addr message once + if (node.vAddrToSend.capacity() > 40) { + node.vAddrToSend.shrink_to_fit(); + } +} + namespace { class CompareInvMempoolOrder { @@ -4182,79 +4254,20 @@ bool PeerManagerImpl::SendMessages(CNode* pto) // If we get here, the outgoing message serialization version is set and can't change. const CNetMsgMaker msgMaker(pto->GetCommonVersion()); - MaybeSendPing(*pto, *peer); + const auto current_time = GetTime<std::chrono::microseconds>(); + + MaybeSendPing(*pto, *peer, current_time); // MaybeSendPing may have marked peer for disconnection if (pto->fDisconnect) return true; + MaybeSendAddr(*pto, current_time); + { LOCK(cs_main); CNodeState &state = *State(pto->GetId()); - // Address refresh broadcast - auto current_time = GetTime<std::chrono::microseconds>(); - - if (fListen && pto->RelayAddrsWithConn() && - !m_chainman.ActiveChainstate().IsInitialBlockDownload() && - pto->m_next_local_addr_send < current_time) { - // If we've sent before, clear the bloom filter for the peer, so that our - // self-announcement will actually go out. - // This might be unnecessary if the bloom filter has already rolled - // over since our last self-announcement, but there is only a small - // bandwidth cost that we can incur by doing this (which happens - // once a day on average). - if (pto->m_next_local_addr_send != 0us) { - pto->m_addr_known->reset(); - } - if (std::optional<CAddress> local_addr = GetLocalAddrForPeer(pto)) { - FastRandomContext insecure_rand; - pto->PushAddress(*local_addr, insecure_rand); - } - pto->m_next_local_addr_send = PoissonNextSend(current_time, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL); - } - - // - // Message: addr - // - if (pto->RelayAddrsWithConn() && pto->m_next_addr_send < current_time) { - pto->m_next_addr_send = PoissonNextSend(current_time, AVG_ADDRESS_BROADCAST_INTERVAL); - std::vector<CAddress> vAddr; - vAddr.reserve(pto->vAddrToSend.size()); - assert(pto->m_addr_known); - - const char* msg_type; - int make_flags; - if (pto->m_wants_addrv2) { - msg_type = NetMsgType::ADDRV2; - make_flags = ADDRV2_FORMAT; - } else { - msg_type = NetMsgType::ADDR; - make_flags = 0; - } - - for (const CAddress& addr : pto->vAddrToSend) - { - if (!pto->m_addr_known->contains(addr.GetKey())) - { - pto->m_addr_known->insert(addr.GetKey()); - vAddr.push_back(addr); - // receiver rejects addr messages larger than MAX_ADDR_TO_SEND - if (vAddr.size() >= MAX_ADDR_TO_SEND) - { - m_connman.PushMessage(pto, msgMaker.Make(make_flags, msg_type, vAddr)); - vAddr.clear(); - } - } - } - pto->vAddrToSend.clear(); - if (!vAddr.empty()) - m_connman.PushMessage(pto, msgMaker.Make(make_flags, msg_type, vAddr)); - // we only send the big addr message once - if (pto->vAddrToSend.capacity() > 40) - pto->vAddrToSend.shrink_to_fit(); - } - // Start block sync if (pindexBestHeader == nullptr) pindexBestHeader = m_chainman.ActiveChain().Tip(); @@ -4489,7 +4502,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto) vInv.clear(); } } - pto->m_tx_relay->m_last_mempool_req = GetTime<std::chrono::seconds>(); + pto->m_tx_relay->m_last_mempool_req = std::chrono::duration_cast<std::chrono::seconds>(current_time); } // Determine transactions to relay @@ -4577,7 +4590,6 @@ bool PeerManagerImpl::SendMessages(CNode* pto) m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); // Detect whether we're stalling - current_time = GetTime<std::chrono::microseconds>(); if (state.m_stalling_since.count() && state.m_stalling_since < current_time - BLOCK_STALLING_TIMEOUT) { // Stalling only triggers when the block download window cannot move. During normal steady state, // the download window should be much larger than the to-be-downloaded set of blocks, so disconnection diff --git a/src/node/coin.cpp b/src/node/coin.cpp index 263dcff657..23d4fa2aae 100644 --- a/src/node/coin.cpp +++ b/src/node/coin.cpp @@ -11,6 +11,7 @@ void FindCoins(const NodeContext& node, std::map<COutPoint, Coin>& coins) { assert(node.mempool); + assert(node.chainman); LOCK2(cs_main, node.mempool->cs); assert(std::addressof(::ChainstateActive()) == std::addressof(node.chainman->ActiveChainstate())); CCoinsViewCache& chain_view = node.chainman->ActiveChainstate().CoinsTip(); diff --git a/src/node/coinstats.h b/src/node/coinstats.h index 83f228aa7e..975651dcc4 100644 --- a/src/node/coinstats.h +++ b/src/node/coinstats.h @@ -8,11 +8,11 @@ #include <amount.h> #include <uint256.h> -#include <validation.h> #include <cstdint> #include <functional> +class BlockManager; class CCoinsView; enum class CoinStatsHashType { diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index 50c8c29175..7ad02f81dc 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -38,7 +38,6 @@ #include <uint256.h> #include <univalue.h> #include <util/check.h> -#include <util/ref.h> #include <util/system.h> #include <util/translation.h> #include <validation.h> @@ -49,6 +48,7 @@ #include <config/bitcoin-config.h> #endif +#include <any> #include <memory> #include <optional> #include <utility> @@ -65,6 +65,8 @@ namespace node { namespace { class NodeImpl : public Node { +private: + ChainstateManager& chainman() { return *Assert(m_context->chainman); } public: explicit NodeImpl(NodeContext* context) { setContext(context); } void initLogging() override { InitLogging(*Assert(m_context->args)); } @@ -183,21 +185,28 @@ public: int getNumBlocks() override { LOCK(::cs_main); - assert(std::addressof(::ChainActive()) == std::addressof(m_context->chainman->ActiveChain())); - return m_context->chainman->ActiveChain().Height(); + assert(std::addressof(::ChainActive()) == std::addressof(chainman().ActiveChain())); + return chainman().ActiveChain().Height(); } uint256 getBestBlockHash() override { - assert(std::addressof(::ChainActive()) == std::addressof(m_context->chainman->ActiveChain())); - const CBlockIndex* tip = WITH_LOCK(::cs_main, return m_context->chainman->ActiveChain().Tip()); + const CBlockIndex* tip; + { + // TODO: Temporary scope to check correctness of refactored code. + // Should be removed manually after merge of + // https://github.com/bitcoin/bitcoin/pull/20158 + LOCK(cs_main); + assert(std::addressof(::ChainActive()) == std::addressof(chainman().ActiveChain())); + tip = chainman().ActiveChain().Tip(); + } return tip ? tip->GetBlockHash() : Params().GenesisBlock().GetHash(); } int64_t getLastBlockTime() override { LOCK(::cs_main); - assert(std::addressof(::ChainActive()) == std::addressof(m_context->chainman->ActiveChain())); - if (m_context->chainman->ActiveChain().Tip()) { - return m_context->chainman->ActiveChain().Tip()->GetBlockTime(); + assert(std::addressof(::ChainActive()) == std::addressof(chainman().ActiveChain())); + if (chainman().ActiveChain().Tip()) { + return chainman().ActiveChain().Tip()->GetBlockTime(); } return Params().GenesisBlock().GetBlockTime(); // Genesis block's time of current network } @@ -206,14 +215,22 @@ public: const CBlockIndex* tip; { LOCK(::cs_main); - assert(std::addressof(::ChainActive()) == std::addressof(m_context->chainman->ActiveChain())); - tip = m_context->chainman->ActiveChain().Tip(); + assert(std::addressof(::ChainActive()) == std::addressof(chainman().ActiveChain())); + tip = chainman().ActiveChain().Tip(); } return GuessVerificationProgress(Params().TxData(), tip); } bool isInitialBlockDownload() override { - assert(std::addressof(::ChainstateActive()) == std::addressof(m_context->chainman->ActiveChainstate())); - return m_context->chainman->ActiveChainstate().IsInitialBlockDownload(); + const CChainState* active_chainstate; + { + // TODO: Temporary scope to check correctness of refactored code. + // Should be removed manually after merge of + // https://github.com/bitcoin/bitcoin/pull/20158 + LOCK(::cs_main); + active_chainstate = &m_context->chainman->ActiveChainstate(); + assert(std::addressof(::ChainstateActive()) == std::addressof(*active_chainstate)); + } + return active_chainstate->IsInitialBlockDownload(); } bool getReindex() override { return ::fReindex; } bool getImporting() override { return ::fImporting; } @@ -239,8 +256,8 @@ public: bool getUnspentOutput(const COutPoint& output, Coin& coin) override { LOCK(::cs_main); - assert(std::addressof(::ChainstateActive()) == std::addressof(m_context->chainman->ActiveChainstate())); - return m_context->chainman->ActiveChainstate().CoinsTip().GetCoin(output, coin); + assert(std::addressof(::ChainstateActive()) == std::addressof(chainman().ActiveChainstate())); + return chainman().ActiveChainstate().CoinsTip().GetCoin(output, coin); } WalletClient& walletClient() override { @@ -298,13 +315,13 @@ public: { m_context = context; if (context) { - m_context_ref.Set(*context); + m_context_ref = context; } else { - m_context_ref.Clear(); + m_context_ref.reset(); } } NodeContext* m_context{nullptr}; - util::Ref m_context_ref; + std::any m_context_ref; }; bool FillBlock(const CBlockIndex* index, const FoundBlock& block, UniqueLock<RecursiveMutex>& lock, const CChain& active) @@ -414,6 +431,8 @@ public: class ChainImpl : public Chain { +private: + ChainstateManager& chainman() { return *Assert(m_node.chainman); } public: explicit ChainImpl(NodeContext& node) : m_node(node) {} std::optional<int> getHeight() override @@ -450,8 +469,8 @@ public: bool checkFinalTx(const CTransaction& tx) override { LOCK(cs_main); - assert(std::addressof(::ChainActive()) == std::addressof(m_node.chainman->ActiveChain())); - return CheckFinalTx(m_node.chainman->ActiveChain().Tip(), tx); + assert(std::addressof(::ChainActive()) == std::addressof(chainman().ActiveChain())); + return CheckFinalTx(chainman().ActiveChain().Tip(), tx); } std::optional<int> findLocatorFork(const CBlockLocator& locator) override { @@ -516,8 +535,8 @@ public: double guessVerificationProgress(const uint256& block_hash) override { LOCK(cs_main); - assert(std::addressof(g_chainman) == std::addressof(*m_node.chainman)); - return GuessVerificationProgress(Params().TxData(), m_node.chainman->m_blockman.LookupBlockIndex(block_hash)); + assert(std::addressof(g_chainman.m_blockman) == std::addressof(chainman().m_blockman)); + return GuessVerificationProgress(Params().TxData(), chainman().m_blockman.LookupBlockIndex(block_hash)); } bool hasBlocks(const uint256& block_hash, int min_height, std::optional<int> max_height) override { @@ -529,8 +548,8 @@ public: // used to limit the range, and passing min_height that's too low or // max_height that's too high will not crash or change the result. LOCK(::cs_main); - assert(std::addressof(g_chainman) == std::addressof(*m_node.chainman)); - if (CBlockIndex* block = m_node.chainman->m_blockman.LookupBlockIndex(block_hash)) { + assert(std::addressof(g_chainman.m_blockman) == std::addressof(chainman().m_blockman)); + if (CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash)) { if (max_height && block->nHeight >= *max_height) block = block->GetAncestor(*max_height); for (; block->nStatus & BLOCK_HAVE_DATA; block = block->pprev) { // Check pprev to not segfault if min_height is too low @@ -621,8 +640,16 @@ public: } bool isReadyToBroadcast() override { return !::fImporting && !::fReindex && !isInitialBlockDownload(); } bool isInitialBlockDownload() override { - assert(std::addressof(::ChainstateActive()) == std::addressof(m_node.chainman->ActiveChainstate())); - return m_node.chainman->ActiveChainstate().IsInitialBlockDownload(); + const CChainState* active_chainstate; + { + // TODO: Temporary scope to check correctness of refactored code. + // Should be removed manually after merge of + // https://github.com/bitcoin/bitcoin/pull/20158 + LOCK(::cs_main); + active_chainstate = &chainman().ActiveChainstate(); + assert(std::addressof(::ChainstateActive()) == std::addressof(*active_chainstate)); + } + return active_chainstate->IsInitialBlockDownload(); } bool shutdownRequested() override { return ShutdownRequested(); } int64_t getAdjustedTime() override { return GetAdjustedTime(); } diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp index f47e85aceb..691b2791d7 100644 --- a/src/node/transaction.cpp +++ b/src/node/transaction.cpp @@ -38,6 +38,7 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t bool callback_set = false; { // cs_main scope + assert(node.chainman); LOCK(cs_main); assert(std::addressof(::ChainstateActive()) == std::addressof(node.chainman->ActiveChainstate())); // If the transaction is already confirmed in the chain, don't do anything diff --git a/src/rest.cpp b/src/rest.cpp index 71426a4dc4..aa97470ca7 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -18,10 +18,12 @@ #include <sync.h> #include <txmempool.h> #include <util/check.h> -#include <util/ref.h> +#include <util/system.h> #include <validation.h> #include <version.h> +#include <any> + #include <boost/algorithm/string.hpp> #include <univalue.h> @@ -73,10 +75,10 @@ static bool RESTERR(HTTPRequest* req, enum HTTPStatusCode status, std::string me * context is not found. * @returns Pointer to the node context or nullptr if not found. */ -static NodeContext* GetNodeContext(const util::Ref& context, HTTPRequest* req) +static NodeContext* GetNodeContext(const std::any& context, HTTPRequest* req) { - NodeContext* node = context.Has<NodeContext>() ? &context.Get<NodeContext>() : nullptr; - if (!node) { + auto node_context = util::AnyPtr<NodeContext>(context); + if (!node_context) { RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, strprintf("%s:%d (%s)\n" "Internal bug detected: Node context not found!\n" @@ -84,7 +86,7 @@ static NodeContext* GetNodeContext(const util::Ref& context, HTTPRequest* req) __FILE__, __LINE__, __func__, PACKAGE_BUGREPORT)); return nullptr; } - return node; + return node_context; } /** @@ -94,14 +96,14 @@ static NodeContext* GetNodeContext(const util::Ref& context, HTTPRequest* req) * context mempool is not found. * @returns Pointer to the mempool or nullptr if no mempool found. */ -static CTxMemPool* GetMemPool(const util::Ref& context, HTTPRequest* req) +static CTxMemPool* GetMemPool(const std::any& context, HTTPRequest* req) { - NodeContext* node = context.Has<NodeContext>() ? &context.Get<NodeContext>() : nullptr; - if (!node || !node->mempool) { + auto node_context = util::AnyPtr<NodeContext>(context); + if (!node_context || !node_context->mempool) { RESTERR(req, HTTP_NOT_FOUND, "Mempool disabled or instance not found"); return nullptr; } - return node->mempool.get(); + return node_context->mempool.get(); } static RetFormat ParseDataFormat(std::string& param, const std::string& strReq) @@ -151,7 +153,7 @@ static bool CheckWarmup(HTTPRequest* req) return true; } -static bool rest_headers(const util::Ref& context, +static bool rest_headers(const std::any& context, HTTPRequest* req, const std::string& strURIPart) { @@ -293,12 +295,12 @@ static bool rest_block(HTTPRequest* req, } } -static bool rest_block_extended(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart) +static bool rest_block_extended(const std::any& context, HTTPRequest* req, const std::string& strURIPart) { return rest_block(req, strURIPart, true); } -static bool rest_block_notxdetails(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart) +static bool rest_block_notxdetails(const std::any& context, HTTPRequest* req, const std::string& strURIPart) { return rest_block(req, strURIPart, false); } @@ -306,7 +308,7 @@ static bool rest_block_notxdetails(const util::Ref& context, HTTPRequest* req, c // A bit of a hack - dependency on a function defined in rpc/blockchain.cpp RPCHelpMan getblockchaininfo(); -static bool rest_chaininfo(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart) +static bool rest_chaininfo(const std::any& context, HTTPRequest* req, const std::string& strURIPart) { if (!CheckWarmup(req)) return false; @@ -329,7 +331,7 @@ static bool rest_chaininfo(const util::Ref& context, HTTPRequest* req, const std } } -static bool rest_mempool_info(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart) +static bool rest_mempool_info(const std::any& context, HTTPRequest* req, const std::string& strURIPart) { if (!CheckWarmup(req)) return false; @@ -353,7 +355,7 @@ static bool rest_mempool_info(const util::Ref& context, HTTPRequest* req, const } } -static bool rest_mempool_contents(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart) +static bool rest_mempool_contents(const std::any& context, HTTPRequest* req, const std::string& strURIPart) { if (!CheckWarmup(req)) return false; const CTxMemPool* mempool = GetMemPool(context, req); @@ -376,7 +378,7 @@ static bool rest_mempool_contents(const util::Ref& context, HTTPRequest* req, co } } -static bool rest_tx(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart) +static bool rest_tx(const std::any& context, HTTPRequest* req, const std::string& strURIPart) { if (!CheckWarmup(req)) return false; @@ -435,7 +437,7 @@ static bool rest_tx(const util::Ref& context, HTTPRequest* req, const std::strin } } -static bool rest_getutxos(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart) +static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std::string& strURIPart) { if (!CheckWarmup(req)) return false; @@ -621,7 +623,7 @@ static bool rest_getutxos(const util::Ref& context, HTTPRequest* req, const std: } } -static bool rest_blockhash_by_height(const util::Ref& context, HTTPRequest* req, +static bool rest_blockhash_by_height(const std::any& context, HTTPRequest* req, const std::string& str_uri_part) { if (!CheckWarmup(req)) return false; @@ -669,7 +671,7 @@ static bool rest_blockhash_by_height(const util::Ref& context, HTTPRequest* req, static const struct { const char* prefix; - bool (*handler)(const util::Ref& context, HTTPRequest* req, const std::string& strReq); + bool (*handler)(const std::any& context, HTTPRequest* req, const std::string& strReq); } uri_prefixes[] = { {"/rest/tx/", rest_tx}, {"/rest/block/notxdetails/", rest_block_notxdetails}, @@ -682,7 +684,7 @@ static const struct { {"/rest/blockhashbyheight/", rest_blockhash_by_height}, }; -void StartREST(const util::Ref& context) +void StartREST(const std::any& context) { for (const auto& up : uri_prefixes) { auto handler = [&context, up](HTTPRequest* req, const std::string& prefix) { return up.handler(context, req, prefix); }; diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index f0ad141fa9..e1501d7254 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -30,7 +30,6 @@ #include <txdb.h> #include <txmempool.h> #include <undo.h> -#include <util/ref.h> #include <util/strencodings.h> #include <util/system.h> #include <util/translation.h> @@ -56,15 +55,16 @@ static Mutex cs_blockchange; static std::condition_variable cond_blockchange; static CUpdatedBlock latestblock GUARDED_BY(cs_blockchange); -NodeContext& EnsureNodeContext(const util::Ref& context) +NodeContext& EnsureNodeContext(const std::any& context) { - if (!context.Has<NodeContext>()) { + auto node_context = util::AnyPtr<NodeContext>(context); + if (!node_context) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Node context not found"); } - return context.Get<NodeContext>(); + return *node_context; } -CTxMemPool& EnsureMemPool(const util::Ref& context) +CTxMemPool& EnsureMemPool(const std::any& context) { const NodeContext& node = EnsureNodeContext(context); if (!node.mempool) { @@ -73,7 +73,7 @@ CTxMemPool& EnsureMemPool(const util::Ref& context) return *node.mempool; } -ChainstateManager& EnsureChainman(const util::Ref& context) +ChainstateManager& EnsureChainman(const std::any& context) { const NodeContext& node = EnsureNodeContext(context); if (!node.chainman) { @@ -82,7 +82,7 @@ ChainstateManager& EnsureChainman(const util::Ref& context) return *node.chainman; } -CBlockPolicyEstimator& EnsureFeeEstimator(const util::Ref& context) +CBlockPolicyEstimator& EnsureFeeEstimator(const std::any& context) { NodeContext& node = EnsureNodeContext(context); if (!node.fee_estimator) { @@ -1669,9 +1669,9 @@ static RPCHelpMan getchaintxstats() {RPCResult::Type::STR_HEX, "window_final_block_hash", "The hash of the final block in the window"}, {RPCResult::Type::NUM, "window_final_block_height", "The height of the final block in the window."}, {RPCResult::Type::NUM, "window_block_count", "Size of the window in number of blocks"}, - {RPCResult::Type::NUM, "window_tx_count", "The number of transactions in the window. Only returned if \"window_block_count\" is > 0"}, - {RPCResult::Type::NUM, "window_interval", "The elapsed time in the window in seconds. Only returned if \"window_block_count\" is > 0"}, - {RPCResult::Type::NUM, "txrate", "The average rate of transactions per second in the window. Only returned if \"window_interval\" is > 0"}, + {RPCResult::Type::NUM, "window_tx_count", /* optional */ true, "The number of transactions in the window. Only returned if \"window_block_count\" is > 0"}, + {RPCResult::Type::NUM, "window_interval", /* optional */ true, "The elapsed time in the window in seconds. Only returned if \"window_block_count\" is > 0"}, + {RPCResult::Type::NUM, "txrate", /* optional */ true, "The average rate of transactions per second in the window. Only returned if \"window_interval\" is > 0"}, }}, RPCExamples{ HelpExampleCli("getchaintxstats", "") diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h index e719dfc702..cd04c9a10f 100644 --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -10,6 +10,7 @@ #include <streams.h> #include <sync.h> +#include <any> #include <stdint.h> #include <vector> @@ -23,9 +24,6 @@ class CTxMemPool; class ChainstateManager; class UniValue; struct NodeContext; -namespace util { -class Ref; -} // namespace util static constexpr int NUM_GETBLOCKSTATS_PERCENTILES = 5; @@ -58,10 +56,10 @@ void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0, const CTxUndo* txundo = nullptr); -NodeContext& EnsureNodeContext(const util::Ref& context); -CTxMemPool& EnsureMemPool(const util::Ref& context); -ChainstateManager& EnsureChainman(const util::Ref& context); -CBlockPolicyEstimator& EnsureFeeEstimator(const util::Ref& context); +NodeContext& EnsureNodeContext(const std::any& context); +CTxMemPool& EnsureMemPool(const std::any& context); +ChainstateManager& EnsureChainman(const std::any& context); +CBlockPolicyEstimator& EnsureFeeEstimator(const std::any& context); /** * Helper to create UTXO snapshots given a chainstate and a file handle. diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index fd780ba782..72ad0df199 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -150,7 +150,7 @@ static UniValue generateBlocks(ChainstateManager& chainman, const CTxMemPool& me UniValue blockHashes(UniValue::VARR); while (nHeight < nHeightEnd && !ShutdownRequested()) { - std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(mempool, Params()).CreateNewBlock(::ChainstateActive(), coinbase_script)); + std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(chainman.ActiveChainstate(), mempool, Params()).CreateNewBlock(coinbase_script)); if (!pblocktemplate.get()) throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); CBlock *pblock = &pblocktemplate->block; @@ -358,7 +358,7 @@ static RPCHelpMan generateblock() LOCK(cs_main); CTxMemPool empty_mempool; - std::unique_ptr<CBlockTemplate> blocktemplate(BlockAssembler(empty_mempool, chainparams).CreateNewBlock(::ChainstateActive(), coinbase_script)); + std::unique_ptr<CBlockTemplate> blocktemplate(BlockAssembler(::ChainstateActive(), empty_mempool, chainparams).CreateNewBlock(coinbase_script)); if (!blocktemplate) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); } @@ -748,7 +748,7 @@ static RPCHelpMan getblocktemplate() // Create new block CScript scriptDummy = CScript() << OP_TRUE; - pblocktemplate = BlockAssembler(mempool, Params()).CreateNewBlock(::ChainstateActive(), scriptDummy); + pblocktemplate = BlockAssembler(::ChainstateActive(), mempool, Params()).CreateNewBlock(scriptDummy); if (!pblocktemplate) throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 143be1274e..1df5c51718 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -17,7 +17,6 @@ #include <script/descriptor.h> #include <util/check.h> #include <util/message.h> // For MessageSign(), MessageVerify() -#include <util/ref.h> #include <util/strencodings.h> #include <util/system.h> @@ -391,8 +390,9 @@ static RPCHelpMan setmocktime() throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Mocktime can not be negative: %s.", time)); } SetMockTime(time); - if (request.context.Has<NodeContext>()) { - for (const auto& chain_client : request.context.Get<NodeContext>().chain_clients) { + auto node_context = util::AnyPtr<NodeContext>(request.context); + if (node_context) { + for (const auto& chain_client : node_context->chain_clients) { chain_client->setMockTime(time); } } @@ -424,11 +424,11 @@ static RPCHelpMan mockscheduler() throw std::runtime_error("delta_time must be between 1 and 3600 seconds (1 hr)"); } + auto node_context = util::AnyPtr<NodeContext>(request.context); // protect against null pointer dereference - CHECK_NONFATAL(request.context.Has<NodeContext>()); - NodeContext& node = request.context.Get<NodeContext>(); - CHECK_NONFATAL(node.scheduler); - node.scheduler->MockForward(std::chrono::seconds(delta_seconds)); + CHECK_NONFATAL(node_context); + CHECK_NONFATAL(node_context->scheduler); + node_context->scheduler->MockForward(std::chrono::seconds(delta_seconds)); return NullUniValue; }, diff --git a/src/rpc/request.h b/src/rpc/request.h index 27d06f3c92..e1569673f6 100644 --- a/src/rpc/request.h +++ b/src/rpc/request.h @@ -6,14 +6,11 @@ #ifndef BITCOIN_RPC_REQUEST_H #define BITCOIN_RPC_REQUEST_H +#include <any> #include <string> #include <univalue.h> -namespace util { -class Ref; -} // namespace util - UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id); UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id); std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id); @@ -38,14 +35,14 @@ public: std::string URI; std::string authUser; std::string peerAddr; - const util::Ref& context; + const std::any& context; - explicit JSONRPCRequest(const util::Ref& context) : id(NullUniValue), params(NullUniValue), context(context) {} + explicit JSONRPCRequest(const std::any& context) : id(NullUniValue), params(NullUniValue), context(context) {} //! Initializes request information from another request object and the //! given context. The implementation should be updated if any members are //! added or removed above. - JSONRPCRequest(const JSONRPCRequest& other, const util::Ref& context) + JSONRPCRequest(const JSONRPCRequest& other, const std::any& context) : id(other.id), strMethod(other.strMethod), params(other.params), mode(other.mode), URI(other.URI), authUser(other.authUser), peerAddr(other.peerAddr), context(context) { diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 39938f4eb9..2f05c8842f 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -87,7 +87,7 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest& vCommands.push_back(make_pair(entry.second.front()->category + entry.first, entry.second.front())); sort(vCommands.begin(), vCommands.end()); - JSONRPCRequest jreq(helpreq); + JSONRPCRequest jreq = helpreq; jreq.mode = JSONRPCRequest::GET_HELP; jreq.params = UniValue(); @@ -494,7 +494,7 @@ std::vector<std::string> CRPCTable::listCommands() const UniValue CRPCTable::dumpArgMap(const JSONRPCRequest& args_request) const { - JSONRPCRequest request(args_request); + JSONRPCRequest request = args_request; request.mode = JSONRPCRequest::GET_ARGS; UniValue ret{UniValue::VARR}; diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp index 04da10715f..9903ba75cb 100644 --- a/src/test/blockfilter_index_tests.cpp +++ b/src/test/blockfilter_index_tests.cpp @@ -62,7 +62,7 @@ CBlock BuildChainTestingSetup::CreateBlock(const CBlockIndex* prev, const CScript& scriptPubKey) { const CChainParams& chainparams = Params(); - std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(*m_node.mempool, chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey); + std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(::ChainstateActive(), *m_node.mempool, chainparams).CreateNewBlock(scriptPubKey); CBlock& block = pblocktemplate->block; block.hashPrevBlock = prev->GetBlockHash(); block.nTime = prev->nTime + 1; diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 9acd17c463..9ba004cc38 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -44,7 +44,7 @@ BlockAssembler MinerTestingSetup::AssemblerForTest(const CChainParams& params) options.nBlockMaxWeight = MAX_BLOCK_WEIGHT; options.blockMinFeeRate = blockMinFeeRate; - return BlockAssembler(*m_node.mempool, params, options); + return BlockAssembler(::ChainstateActive(), *m_node.mempool, params, options); } constexpr static struct { @@ -122,7 +122,7 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co uint256 hashHighFeeTx = tx.GetHash(); m_node.mempool->addUnchecked(entry.Fee(50000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); - std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey); + std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 4U); BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashParentTx); BOOST_CHECK(pblocktemplate->block.vtx[2]->GetHash() == hashHighFeeTx); @@ -143,7 +143,7 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co tx.vout[0].nValue = 5000000000LL - 1000 - 50000 - feeToUse; uint256 hashLowFeeTx = tx.GetHash(); m_node.mempool->addUnchecked(entry.Fee(feeToUse).FromTx(tx)); - pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey); + pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); // Verify that the free tx and the low fee tx didn't get selected for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) { BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashFreeTx); @@ -157,7 +157,7 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co tx.vout[0].nValue -= 2; // Now we should be just over the min relay fee hashLowFeeTx = tx.GetHash(); m_node.mempool->addUnchecked(entry.Fee(feeToUse+2).FromTx(tx)); - pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey); + pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 6U); BOOST_CHECK(pblocktemplate->block.vtx[4]->GetHash() == hashFreeTx); BOOST_CHECK(pblocktemplate->block.vtx[5]->GetHash() == hashLowFeeTx); @@ -179,7 +179,7 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse; uint256 hashLowFeeTx2 = tx.GetHash(); m_node.mempool->addUnchecked(entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx)); - pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey); + pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); // Verify that this tx isn't selected. for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) { @@ -192,7 +192,7 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co tx.vin[0].prevout.n = 1; tx.vout[0].nValue = 100000000 - 10000; // 10k satoshi fee m_node.mempool->addUnchecked(entry.Fee(10000).FromTx(tx)); - pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey); + pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 9U); BOOST_CHECK(pblocktemplate->block.vtx[8]->GetHash() == hashLowFeeTx2); } @@ -215,7 +215,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) fCheckpointsEnabled = false; // Simple block creation, nothing special yet: - BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey)); + BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); // We can't make transactions until we have inputs // Therefore, load 110 blocks :) @@ -252,7 +252,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) LOCK(m_node.mempool->cs); // Just to make sure we can still make simple blocks - BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey)); + BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); const CAmount BLOCKSUBSIDY = 50*COIN; const CAmount LOWFEE = CENT; @@ -277,7 +277,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[0].prevout.hash = hash; } - BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey), std::runtime_error, HasReason("bad-blk-sigops")); + BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-blk-sigops")); m_node.mempool->clear(); tx.vin[0].prevout.hash = txFirst[0]->GetHash(); @@ -291,7 +291,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).SigOpsCost(80).FromTx(tx)); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey)); + BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); m_node.mempool->clear(); // block size > limit @@ -311,13 +311,13 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey)); + BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); m_node.mempool->clear(); // orphan in *m_node.mempool, template creation fails hash = tx.GetHash(); m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx)); - BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); + BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); m_node.mempool->clear(); // child with higher feerate than parent @@ -334,7 +334,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue = tx.vout[0].nValue+BLOCKSUBSIDY-HIGHERFEE; //First txn output + fresh coinbase - new txn fee hash = tx.GetHash(); m_node.mempool->addUnchecked(entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); - BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey)); + BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); m_node.mempool->clear(); // coinbase in *m_node.mempool, template creation fails @@ -346,7 +346,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) // give it a fee so it'll get mined m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); // Should throw bad-cb-multiple - BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey), std::runtime_error, HasReason("bad-cb-multiple")); + BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-cb-multiple")); m_node.mempool->clear(); // double spend txn pair in *m_node.mempool, template creation fails @@ -359,7 +359,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].scriptPubKey = CScript() << OP_2; hash = tx.GetHash(); m_node.mempool->addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); - BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); + BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); m_node.mempool->clear(); // subsidy changing @@ -375,7 +375,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) next->BuildSkip(); ::ChainActive().SetTip(next); } - BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey)); + BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); // Extend to a 210000-long block chain. while (::ChainActive().Tip()->nHeight < 210000) { CBlockIndex* prev = ::ChainActive().Tip(); @@ -387,7 +387,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) next->BuildSkip(); ::ChainActive().SetTip(next); } - BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey)); + BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); // invalid p2sh txn in *m_node.mempool, template creation fails tx.vin[0].prevout.hash = txFirst[0]->GetHash(); @@ -404,7 +404,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) hash = tx.GetHash(); m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); // Should throw block-validation-failed - BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey), std::runtime_error, HasReason("block-validation-failed")); + BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("block-validation-failed")); m_node.mempool->clear(); // Delete the dummy blocks again. @@ -492,7 +492,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | 1; BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks fail - BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey)); + BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); // None of the of the absolute height/time locked tx should have made // it into the template because we still check IsFinalTx in CreateNewBlock, @@ -505,7 +505,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) ::ChainActive().Tip()->nHeight++; SetMockTime(::ChainActive().Tip()->GetMedianTimePast() + 1); - BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey)); + BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5U); ::ChainActive().Tip()->nHeight--; diff --git a/src/test/ref_tests.cpp b/src/test/ref_tests.cpp deleted file mode 100644 index 0ec0799fbc..0000000000 --- a/src/test/ref_tests.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2020 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include <util/ref.h> - -#include <boost/test/unit_test.hpp> - -BOOST_AUTO_TEST_SUITE(ref_tests) - -BOOST_AUTO_TEST_CASE(ref_test) -{ - util::Ref ref; - BOOST_CHECK(!ref.Has<int>()); - BOOST_CHECK_THROW(ref.Get<int>(), NonFatalCheckError); - int value = 5; - ref.Set(value); - BOOST_CHECK(ref.Has<int>()); - BOOST_CHECK_EQUAL(ref.Get<int>(), 5); - ++ref.Get<int>(); - BOOST_CHECK_EQUAL(ref.Get<int>(), 6); - BOOST_CHECK_EQUAL(value, 6); - ++value; - BOOST_CHECK_EQUAL(value, 7); - BOOST_CHECK_EQUAL(ref.Get<int>(), 7); - BOOST_CHECK(!ref.Has<bool>()); - BOOST_CHECK_THROW(ref.Get<bool>(), NonFatalCheckError); - ref.Clear(); - BOOST_CHECK(!ref.Has<int>()); - BOOST_CHECK_THROW(ref.Get<int>(), NonFatalCheckError); -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 2e0fc7e48f..67e70b3bc3 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -10,9 +10,10 @@ #include <interfaces/chain.h> #include <node/context.h> #include <test/util/setup_common.h> -#include <util/ref.h> #include <util/time.h> +#include <any> + #include <boost/algorithm/string.hpp> #include <boost/test/unit_test.hpp> @@ -32,7 +33,7 @@ UniValue RPCTestingSetup::CallRPC(std::string args) boost::split(vArgs, args, boost::is_any_of(" \t")); std::string strMethod = vArgs[0]; vArgs.erase(vArgs.begin()); - util::Ref context{m_node}; + std::any context{&m_node}; JSONRPCRequest request(context); request.strMethod = strMethod; request.params = RPCConvertValues(strMethod, vArgs); diff --git a/src/test/util/mining.cpp b/src/test/util/mining.cpp index ba1edba0ae..3fc3329da2 100644 --- a/src/test/util/mining.cpp +++ b/src/test/util/mining.cpp @@ -41,8 +41,8 @@ CTxIn MineBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey) std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey) { auto block = std::make_shared<CBlock>( - BlockAssembler{*Assert(node.mempool), Params()} - .CreateNewBlock(::ChainstateActive(), coinbase_scriptPubKey) + BlockAssembler{::ChainstateActive(), *Assert(node.mempool), Params()} + .CreateNewBlock(coinbase_scriptPubKey) ->block); LOCK(cs_main); diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index bfb3466dcf..f7800aefca 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -247,7 +247,7 @@ CBlock TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransa { const CChainParams& chainparams = Params(); CTxMemPool empty_pool; - CBlock block = BlockAssembler(empty_pool, chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey)->block; + CBlock block = BlockAssembler(::ChainstateActive(), empty_pool, chainparams).CreateNewBlock(scriptPubKey)->block; Assert(block.vtx.size() == 1); for (const CMutableTransaction& tx : txns) { diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp index f3fc83078f..552be0a2da 100644 --- a/src/test/validation_block_tests.cpp +++ b/src/test/validation_block_tests.cpp @@ -63,7 +63,7 @@ std::shared_ptr<CBlock> MinerTestingSetup::Block(const uint256& prev_hash) static int i = 0; static uint64_t time = Params().GenesisBlock().nTime; - auto ptemplate = BlockAssembler(*m_node.mempool, Params()).CreateNewBlock(::ChainstateActive(), CScript{} << i++ << OP_TRUE); + auto ptemplate = BlockAssembler(m_node.chainman->ActiveChainstate(), *m_node.mempool, Params()).CreateNewBlock(CScript{} << i++ << OP_TRUE); auto pblock = std::make_shared<CBlock>(ptemplate->block); pblock->hashPrevBlock = prev_hash; pblock->nTime = ++time; @@ -325,7 +325,7 @@ BOOST_AUTO_TEST_CASE(witness_commitment_index) { CScript pubKey; pubKey << 1 << OP_TRUE; - auto ptemplate = BlockAssembler(*m_node.mempool, Params()).CreateNewBlock(::ChainstateActive(), pubKey); + auto ptemplate = BlockAssembler(m_node.chainman->ActiveChainstate(), *m_node.mempool, Params()).CreateNewBlock(pubKey); CBlock pblock = ptemplate->block; CTxOut witness; diff --git a/src/util/ref.h b/src/util/ref.h deleted file mode 100644 index 9685ea9fec..0000000000 --- a/src/util/ref.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2020 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_UTIL_REF_H -#define BITCOIN_UTIL_REF_H - -#include <util/check.h> - -#include <typeindex> - -namespace util { - -/** - * Type-safe dynamic reference. - * - * This implements a small subset of the functionality in C++17's std::any - * class, and can be dropped when the project updates to C++17 - * (https://github.com/bitcoin/bitcoin/issues/16684) - */ -class Ref -{ -public: - Ref() = default; - template<typename T> Ref(T& value) { Set(value); } - template<typename T> T& Get() const { CHECK_NONFATAL(Has<T>()); return *static_cast<T*>(m_value); } - template<typename T> void Set(T& value) { m_value = &value; m_type = std::type_index(typeid(T)); } - template<typename T> bool Has() const { return m_value && m_type == std::type_index(typeid(T)); } - void Clear() { m_value = nullptr; m_type = std::type_index(typeid(void)); } - -private: - void* m_value = nullptr; - std::type_index m_type = std::type_index(typeid(void)); -}; - -} // namespace util - -#endif // BITCOIN_UTIL_REF_H diff --git a/src/util/system.h b/src/util/system.h index 291f3f5541..29657e56e2 100644 --- a/src/util/system.h +++ b/src/util/system.h @@ -25,6 +25,7 @@ #include <util/threadnames.h> #include <util/time.h> +#include <any> #include <exception> #include <map> #include <optional> @@ -500,6 +501,18 @@ inline void insert(std::set<TsetT>& dst, const Tsrc& src) { dst.insert(src.begin(), src.end()); } +/** + * Helper function to access the contained object of a std::any instance. + * Returns a pointer to the object if passed instance has a value and the type + * matches, nullptr otherwise. + */ +template<typename T> +T* AnyPtr(const std::any& any) noexcept +{ + T* const* ptr = std::any_cast<T*>(&any); + return ptr ? *ptr : nullptr; +} + #ifdef WIN32 class WinCmdLineArgs { diff --git a/src/validation.cpp b/src/validation.cpp index d0cb81b1f1..19363c0efb 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -169,7 +169,7 @@ namespace { std::set<int> setDirtyFileInfo; } // anon namespace -CBlockIndex* BlockManager::LookupBlockIndex(const uint256& hash) +CBlockIndex* BlockManager::LookupBlockIndex(const uint256& hash) const { AssertLockHeld(cs_main); assert(std::addressof(g_chainman.BlockIndex()) == std::addressof(m_block_index)); diff --git a/src/validation.h b/src/validation.h index 2ff5f4ac87..21e63947fa 100644 --- a/src/validation.h +++ b/src/validation.h @@ -457,7 +457,7 @@ public: const CChainParams& chainparams, CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); - CBlockIndex* LookupBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + CBlockIndex* LookupBlockIndex(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_main); /** Find the last common block between the parameter chain and a locator. */ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator) EXCLUSIVE_LOCKS_REQUIRED(cs_main); diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index ada586119a..da5b84ce83 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -15,7 +15,6 @@ #include <sync.h> #include <uint256.h> #include <util/check.h> -#include <util/ref.h> #include <util/system.h> #include <util/ui_change_type.h> #include <wallet/context.h> @@ -515,7 +514,7 @@ public: { for (const CRPCCommand& command : GetWalletRPCCommands()) { m_rpc_commands.emplace_back(command.category, command.name, [this, &command](const JSONRPCRequest& request, UniValue& result, bool last_handler) { - return command.actor({request, m_context}, result, last_handler); + return command.actor({request, &m_context}, result, last_handler); }, command.argNames, command.unique_id); m_rpc_handlers.emplace_back(m_context.chain->handleRpc(m_rpc_commands.back())); } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index e70bbafde0..df26f039a0 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -22,7 +22,6 @@ #include <util/fees.h> #include <util/message.h> // For MessageSign() #include <util/moneystr.h> -#include <util/ref.h> #include <util/string.h> #include <util/system.h> #include <util/translation.h> @@ -124,12 +123,13 @@ void EnsureWalletIsUnlocked(const CWallet& wallet) } } -WalletContext& EnsureWalletContext(const util::Ref& context) +WalletContext& EnsureWalletContext(const std::any& context) { - if (!context.Has<WalletContext>()) { + auto wallet_context = util::AnyPtr<WalletContext>(context); + if (!wallet_context) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet context not found"); } - return context.Get<WalletContext>(); + return *wallet_context; } // also_create should only be set to true only when the RPC is expected to add things to a blank wallet and make it no longer blank @@ -3379,7 +3379,7 @@ RPCHelpMan signrawtransactionwithwallet() static RPCHelpMan bumpfee_helper(std::string method_name) { - bool want_psbt = method_name == "psbtbumpfee"; + const bool want_psbt = method_name == "psbtbumpfee"; const std::string incremental_fee{CFeeRate(DEFAULT_INCREMENTAL_RELAY_FEE).ToString(FeeEstimateMode::SAT_VB)}; return RPCHelpMan{method_name, @@ -3413,14 +3413,14 @@ static RPCHelpMan bumpfee_helper(std::string method_name) "still be replaceable in practice, for example if it has unconfirmed ancestors which\n" "are replaceable).\n"}, {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n" - " \"" + FeeModes("\"\n\"") + "\""}, + "\"" + FeeModes("\"\n\"") + "\""}, }, "options"}, }, RPCResult{ RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>( { - {RPCResult::Type::STR, "psbt", "The base64-encoded unsigned PSBT of the new transaction." + std::string(want_psbt ? "" : " Only returned when wallet private keys are disabled. (DEPRECATED)")}, + {RPCResult::Type::STR, "psbt", "The base64-encoded unsigned PSBT of the new transaction."}, }, want_psbt ? std::vector<RPCResult>{} : std::vector<RPCResult>{{RPCResult::Type::STR_HEX, "txid", "The id of the new transaction. Only returned when wallet private keys are enabled."}} ), @@ -3437,7 +3437,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name) "\nBump the fee, get the new transaction\'s" + std::string(want_psbt ? "psbt" : "txid") + "\n" + HelpExampleCli(method_name, "<txid>") }, - [want_psbt](const RPCHelpMan& self, const JSONRPCRequest& request) mutable -> UniValue + [want_psbt](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request); if (!pwallet) return NullUniValue; diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h index b82fe1ec76..8b88ffe8ed 100644 --- a/src/wallet/rpcwallet.h +++ b/src/wallet/rpcwallet.h @@ -7,6 +7,7 @@ #include <span.h> +#include <any> #include <memory> #include <string> #include <vector> @@ -31,7 +32,7 @@ Span<const CRPCCommand> GetWalletRPCCommands(); std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request); void EnsureWalletIsUnlocked(const CWallet&); -WalletContext& EnsureWalletContext(const util::Ref& context); +WalletContext& EnsureWalletContext(const std::any& context); LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create = false); RPCHelpMan getaddressinfo(); diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 30cc452065..ba2e17d62a 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -4,6 +4,7 @@ #include <wallet/wallet.h> +#include <any> #include <future> #include <memory> #include <stdint.h> @@ -15,7 +16,6 @@ #include <rpc/server.h> #include <test/util/logging.h> #include <test/util/setup_common.h> -#include <util/ref.h> #include <util/translation.h> #include <validation.h> #include <wallet/coincontrol.h> @@ -213,7 +213,7 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup) key.pushKV("timestamp", newTip->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1); key.pushKV("internal", UniValue(true)); keys.push_back(key); - util::Ref context; + std::any context; JSONRPCRequest request(context); request.params.setArray(); request.params.push_back(keys); @@ -265,7 +265,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) AddWallet(wallet); wallet->SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash()); } - util::Ref context; + std::any context; JSONRPCRequest request(context); request.params.setArray(); request.params.push_back(backup_file); @@ -281,7 +281,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) LOCK(wallet->cs_wallet); wallet->SetupLegacyScriptPubKeyMan(); - util::Ref context; + std::any context; JSONRPCRequest request(context); request.params.setArray(); request.params.push_back(backup_file); diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py index bdbfa5aed1..c7981d31dc 100755 --- a/test/functional/feature_nulldummy.py +++ b/test/functional/feature_nulldummy.py @@ -6,11 +6,11 @@ Connect to a single node. Generate 2 blocks (save the coinbases for later). -Generate 427 more blocks. -[Policy/Consensus] Check that NULLDUMMY compliant transactions are accepted in the 430th block. +Generate COINBASE_MATURITY (CB) more blocks to ensure the coinbases are mature. +[Policy/Consensus] Check that NULLDUMMY compliant transactions are accepted in block CB + 3. [Policy] Check that non-NULLDUMMY transactions are rejected before activation. -[Consensus] Check that the new NULLDUMMY rules are not enforced on the 431st block. -[Policy/Consensus] Check that the new NULLDUMMY rules are enforced on the 432nd block. +[Consensus] Check that the new NULLDUMMY rules are not enforced on block CB + 4. +[Policy/Consensus] Check that the new NULLDUMMY rules are enforced on block CB + 5. """ import time @@ -20,13 +20,14 @@ from test_framework.script import CScript from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, assert_raises_rpc_error +COINBASE_MATURITY = 100 NULLDUMMY_ERROR = "non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero)" def trueDummy(tx): scriptSig = CScript(tx.vin[0].scriptSig) newscript = [] for i in scriptSig: - if (len(newscript) == 0): + if len(newscript) == 0: assert len(i) == 0 newscript.append(b'\x51') else: @@ -37,13 +38,13 @@ def trueDummy(tx): class NULLDUMMYTest(BitcoinTestFramework): def set_test_params(self): - # Need two nodes only so GBT doesn't complain that it's not connected + # Need two nodes so GBT (getblocktemplate) doesn't complain that it's not connected. self.num_nodes = 2 self.setup_clean_chain = True # This script tests NULLDUMMY activation, which is part of the 'segwit' deployment, so we go through # normal segwit activation here (and don't use the default always-on behaviour). self.extra_args = [[ - '-segwitheight=432', + f'-segwitheight={COINBASE_MATURITY + 5}', '-addresstype=legacy', ]] * 2 @@ -64,16 +65,16 @@ class NULLDUMMYTest(BitcoinTestFramework): wmulti.importaddress(self.ms_address) wmulti.importaddress(self.wit_ms_address) - self.coinbase_blocks = self.nodes[0].generate(2) # Block 2 + self.coinbase_blocks = self.nodes[0].generate(2) # block height = 2 coinbase_txid = [] for i in self.coinbase_blocks: coinbase_txid.append(self.nodes[0].getblock(i)['tx'][0]) - self.nodes[0].generate(427) # Block 429 + self.nodes[0].generate(COINBASE_MATURITY) # block height = COINBASE_MATURITY + 2 self.lastblockhash = self.nodes[0].getbestblockhash() - self.lastblockheight = 429 - self.lastblocktime = int(time.time()) + 429 + self.lastblockheight = COINBASE_MATURITY + 2 + self.lastblocktime = int(time.time()) + self.lastblockheight - self.log.info("Test 1: NULLDUMMY compliant base transactions should be accepted to mempool and mined before activation [430]") + self.log.info(f"Test 1: NULLDUMMY compliant base transactions should be accepted to mempool and mined before activation [{COINBASE_MATURITY + 3}]") test1txs = [create_transaction(self.nodes[0], coinbase_txid[0], self.ms_address, amount=49)] txid1 = self.nodes[0].sendrawtransaction(test1txs[0].serialize_with_witness().hex(), 0) test1txs.append(create_transaction(self.nodes[0], txid1, self.ms_address, amount=48)) @@ -87,7 +88,7 @@ class NULLDUMMYTest(BitcoinTestFramework): trueDummy(test2tx) assert_raises_rpc_error(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, test2tx.serialize_with_witness().hex(), 0) - self.log.info("Test 3: Non-NULLDUMMY base transactions should be accepted in a block before activation [431]") + self.log.info(f"Test 3: Non-NULLDUMMY base transactions should be accepted in a block before activation [{COINBASE_MATURITY + 4}]") self.block_submit(self.nodes[0], [test2tx], False, True) self.log.info("Test 4: Non-NULLDUMMY base multisig transaction is invalid after activation") @@ -104,7 +105,7 @@ class NULLDUMMYTest(BitcoinTestFramework): assert_raises_rpc_error(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, test5tx.serialize_with_witness().hex(), 0) self.block_submit(self.nodes[0], [test5tx], True) - self.log.info("Test 6: NULLDUMMY compliant base/witness transactions should be accepted to mempool and in block after activation [432]") + self.log.info(f"Test 6: NULLDUMMY compliant base/witness transactions should be accepted to mempool and in block after activation [{COINBASE_MATURITY + 5}]") for i in test6txs: self.nodes[0].sendrawtransaction(i.serialize_with_witness().hex(), 0) self.block_submit(self.nodes[0], test6txs, True, True) @@ -130,5 +131,6 @@ class NULLDUMMYTest(BitcoinTestFramework): else: assert_equal(node.getbestblockhash(), self.lastblockhash) + if __name__ == '__main__': NULLDUMMYTest().main() diff --git a/test/lint/extended-lint-cppcheck.sh b/test/lint/extended-lint-cppcheck.sh index b2ed811cda..0ab6aad50c 100755 --- a/test/lint/extended-lint-cppcheck.sh +++ b/test/lint/extended-lint-cppcheck.sh @@ -57,7 +57,6 @@ IGNORED_WARNINGS=( "src/test/checkqueue_tests.cpp:.* Struct 'UniqueCheck' has a constructor with 1 argument that is not explicit." "src/test/fuzz/util.h:.* Class 'FuzzedFileProvider' has a constructor with 1 argument that is not explicit." "src/test/fuzz/util.h:.* Class 'FuzzedAutoFileProvider' has a constructor with 1 argument that is not explicit." - "src/util/ref.h:.* Class 'Ref' has a constructor with 1 argument that is not explicit." "src/wallet/db.h:.* Class 'BerkeleyEnvironment' has a constructor with 1 argument that is not explicit." ) |