From d5ccebda102ef2bdf0901e4fe2641b2ce0ed4558 Mon Sep 17 00:00:00 2001 From: PastaPastaPasta <6443210+PastaPastaPasta@users.noreply.github.com> Date: Wed, 29 Mar 2023 07:32:24 -0500 Subject: [PATCH 01/35] log: add a log for invalid mnauth (#5271) ## Issue being fixed or feature implemented We are seeing lots of "invalid mnauth" on testnet.. We should be logging this anyhow ## What was done? Add some logging the the mnauth sig isn't valid ## How Has This Been Tested? make check ## Breaking Changes None ## Checklist: - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have made corresponding changes to the documentation **For repository code-owners and collaborators only** - [x] I have assigned this pull request to a milestone --- src/evo/mnauth.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/evo/mnauth.cpp b/src/evo/mnauth.cpp index d7527a55cb8d..d0122bf9fd43 100644 --- a/src/evo/mnauth.cpp +++ b/src/evo/mnauth.cpp @@ -87,6 +87,7 @@ void CMNAuth::ProcessMessage(CNode& peer, CConnman& connman, std::string_view ms if (!mnauth.sig.IsValid()) { Misbehaving(peer.GetId(), 100, "invalid mnauth signature"); + LogPrint(BCLog::NET_NETCONN, "CMNAuth::ProcessMessage -- invalid mnauth for protx=%s with sig=%s\n", mnauth.proRegTxHash.ToString(), mnauth.sig.ToString()); return; } From 7f520f5c954fa91764592b36b1e3a472cd7dd8a5 Mon Sep 17 00:00:00 2001 From: Odysseas Gabrielides Date: Wed, 29 Mar 2023 15:34:19 +0300 Subject: [PATCH 02/35] log: Add logs when send qgetdata (#5275) ## Issue being fixed or feature implemented ## What was done? Added logs with requested parameters (`llmqType`, `quorumHash`, `proRegTx`) when sending `qgetdata` for better troubleshooting. ## How Has This Been Tested? ## Breaking Changes ## Checklist: - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have made corresponding changes to the documentation **For repository code-owners and collaborators only** - [x] I have assigned this pull request to a milestone --- src/llmq/quorums.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/llmq/quorums.cpp b/src/llmq/quorums.cpp index dedf7a4263dd..cfcf66366822 100644 --- a/src/llmq/quorums.cpp +++ b/src/llmq/quorums.cpp @@ -478,6 +478,8 @@ bool CQuorumManager::RequestQuorumData(CNode* pfrom, Consensus::LLMQType llmqTyp LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- Already requested\n", __func__); return false; } + LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- sending QGETDATA quorumHash[%s] llmqType[%d] proRegTx[%s]\n", __func__, key.quorumHash.ToString(), + ToUnderlying(key.llmqType), key.proRegTx.ToString()); CNetMsgMaker msgMaker(pfrom->GetSendVersion()); connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::QGETDATA, it.first->second)); From 5456be67800007cd2654ab3961cf506905317029 Mon Sep 17 00:00:00 2001 From: Odysseas Gabrielides Date: Wed, 29 Mar 2023 19:23:45 +0300 Subject: [PATCH 03/35] feat(rpc): Added RPC cleardiscouraged (#5273) ## Issue being fixed or feature implemented ## What was done? Added RPC `cleardiscouraged` which clears internally the list of discouraged peers. Note: Implementation of a `listdiscouraged` RPC is not possible because the internal data structure used for discouraged peers is a Bloom filter. ## How Has This Been Tested? ## Breaking Changes ## Checklist: - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have added or updated relevant unit/integration/functional/e2e tests - [x] I have made corresponding changes to the documentation **For repository code-owners and collaborators only** - [x] I have assigned this pull request to a milestone --- doc/release-notes-5273.md | 5 +++++ src/banman.cpp | 10 ++++++++++ src/banman.h | 1 + src/rpc/net.cpp | 22 ++++++++++++++++++++++ 4 files changed, 38 insertions(+) create mode 100644 doc/release-notes-5273.md diff --git a/doc/release-notes-5273.md b/doc/release-notes-5273.md new file mode 100644 index 000000000000..16bd0c88dcef --- /dev/null +++ b/doc/release-notes-5273.md @@ -0,0 +1,5 @@ +Added RPCs +-------- + +- `cleardiscouraged` clears all the already discouraged peers. + diff --git a/src/banman.cpp b/src/banman.cpp index 48973e9c4a97..807ad19faa0a 100644 --- a/src/banman.cpp +++ b/src/banman.cpp @@ -68,6 +68,16 @@ void BanMan::ClearBanned() if (m_client_interface) m_client_interface->BannedListChanged(); } +void BanMan::ClearDiscouraged() +{ + { + LOCK(m_cs_banned); + m_discouraged.reset(); + m_is_dirty = true; + } + if (m_client_interface) m_client_interface->BannedListChanged(); +} + bool BanMan::IsDiscouraged(const CNetAddr& net_addr) { LOCK(m_cs_banned); diff --git a/src/banman.h b/src/banman.h index 6b972c84e28e..ca46677e3ee4 100644 --- a/src/banman.h +++ b/src/banman.h @@ -63,6 +63,7 @@ class BanMan void Ban(const CSubNet& sub_net, int64_t ban_time_offset = 0, bool since_unix_epoch = false); void Discourage(const CNetAddr& net_addr); void ClearBanned(); + void ClearDiscouraged(); //! Return whether net_addr is banned bool IsBanned(const CNetAddr& net_addr); diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index eca3d2179c6f..8db4721c1922 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -736,6 +736,27 @@ static UniValue clearbanned(const JSONRPCRequest& request) return NullUniValue; } +static UniValue cleardiscouraged(const JSONRPCRequest& request) +{ + RPCHelpMan{"cleardiscouraged", + "\nClear all discouraged nodes.\n", + {}, + RPCResult{RPCResult::Type::NONE, "", ""}, + RPCExamples{ + HelpExampleCli("cleardiscouraged", "") + + HelpExampleRpc("cleardiscouraged", "") + }, + }.Check(request); + NodeContext& node = EnsureNodeContext(request.context); + if (!node.banman) { + throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded"); + } + + node.banman->ClearDiscouraged(); + + return NullUniValue; +} + static UniValue setnetworkactive(const JSONRPCRequest& request) { RPCHelpMan{"setnetworkactive", @@ -825,6 +846,7 @@ static const CRPCCommand commands[] = { "network", "setban", &setban, {"subnet", "command", "bantime", "absolute"} }, { "network", "listbanned", &listbanned, {} }, { "network", "clearbanned", &clearbanned, {} }, + { "network", "cleardiscouraged", &cleardiscouraged, {} }, { "network", "setnetworkactive", &setnetworkactive, {"state"} }, { "network", "getnodeaddresses", &getnodeaddresses, {"count"} }, }; From 376f78d8aac121f5fcae976bbd7fefbe75d5dbe8 Mon Sep 17 00:00:00 2001 From: PastaPastaPasta <6443210+PastaPastaPasta@users.noreply.github.com> Date: Wed, 29 Mar 2023 11:24:16 -0500 Subject: [PATCH 04/35] format: fix indentation (#5277) ## Issue being fixed or feature implemented Indentation was wrong ## What was done? ## How Has This Been Tested? ## Breaking Changes ## Checklist: - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have made corresponding changes to the documentation **For repository code-owners and collaborators only** - [x] I have assigned this pull request to a milestone --- src/net.cpp | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 1dd7e4495f80..51bf6c3c0f20 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2534,31 +2534,31 @@ void CConnman::ThreadOpenMasternodeConnections() } const auto& addr2 = dmn->pdmnState->addr; if (connectedNodes.count(addr2) && !connectedProRegTxHashes.count(proRegTxHash)) { - // we probably connected to it before it became a masternode - // or maybe we are still waiting for mnauth - (void)ForNode(addr2, [&](CNode* pnode) { - if (pnode->nTimeFirstMessageReceived != 0 && GetSystemTimeInSeconds() - pnode->nTimeFirstMessageReceived > 5) { - // clearly not expecting mnauth to take that long even if it wasn't the first message - // we received (as it should normally), disconnect - LogPrint(BCLog::NET_NETCONN, "CConnman::%s -- dropping non-mnauth connection to %s, service=%s\n", _func_, proRegTxHash.ToString(), addr2.ToString(false)); - pnode->fDisconnect = true; - return true; - } - return false; - }); - // either way - it's not ready, skip it for now - continue; - } - if (!connectedNodes.count(addr2) && !IsMasternodeOrDisconnectRequested(addr2) && !connectedProRegTxHashes.count(proRegTxHash)) { - int64_t lastAttempt = mmetaman.GetMetaInfo(dmn->proTxHash)->GetLastOutboundAttempt(); - // back off trying connecting to an address if we already tried recently - if (nANow - lastAttempt < chainParams.LLMQConnectionRetryTimeout()) { - continue; + // we probably connected to it before it became a masternode + // or maybe we are still waiting for mnauth + (void)ForNode(addr2, [&](CNode* pnode) { + if (pnode->nTimeFirstMessageReceived != 0 && GetSystemTimeInSeconds() - pnode->nTimeFirstMessageReceived > 5) { + // clearly not expecting mnauth to take that long even if it wasn't the first message + // we received (as it should normally), disconnect + LogPrint(BCLog::NET_NETCONN, "CConnman::%s -- dropping non-mnauth connection to %s, service=%s\n", _func_, proRegTxHash.ToString(), addr2.ToString(false)); + pnode->fDisconnect = true; + return true; } - ret.emplace_back(dmn); + return false; + }); + // either way - it's not ready, skip it for now + continue; + } + if (!connectedNodes.count(addr2) && !IsMasternodeOrDisconnectRequested(addr2) && !connectedProRegTxHashes.count(proRegTxHash)) { + int64_t lastAttempt = mmetaman.GetMetaInfo(dmn->proTxHash)->GetLastOutboundAttempt(); + // back off trying connecting to an address if we already tried recently + if (nANow - lastAttempt < chainParams.LLMQConnectionRetryTimeout()) { + continue; } + ret.emplace_back(dmn); } } + } return ret; }; From 238e585f9d7fe71d0f5b576758d8359806cbd7fa Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Thu, 2 Feb 2023 16:25:52 +0700 Subject: [PATCH 05/35] Merge #15718: docs: Improve netaddress comments 303372c41a8d5c58a46cf9ed595e30e67bd0bc99 docs: Improve netaddress comments (Carl Dong) Pull request description: Improves comments for `netaddress`, making them available to Doxygen. I think this is worthwhile because a lot of the code require some context (e.g., A lot of the things that we do to fit hostnames and tor addresses into `CNetAddr` is non-obvious, and documenting it is beneficial). ACKs for commit 303372: Tree-SHA512: 2a35784a01ed8ec5fdbe111a540192d31bde16afa96e4be97b0385daf290fc7469a66d7cb8905a70b920fad6a0e7400ca4e5da082d6e4af1d1aaccc0e8297720 --- src/netaddress.cpp | 62 ++++++++++++++++++++++++++++++++++++++++++++-- src/netaddress.h | 12 ++++++--- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/netaddress.cpp b/src/netaddress.cpp index bb4ba3095c8f..ce3a3745d6be 100644 --- a/src/netaddress.cpp +++ b/src/netaddress.cpp @@ -420,6 +420,16 @@ bool CNetAddr::IsLocal() const return false; } +/** + * @returns Whether or not this network address is a valid address that @a could + * be used to refer to an actual host. + * + * @note A valid address may or may not be publicly routable on the global + * internet. As in, the set of valid addresses is a superset of the set of + * publicly routable addresses. + * + * @see CNetAddr::IsRoutable() + */ bool CNetAddr::IsValid() const { // unspecified IPv6 address (::/128) @@ -450,6 +460,15 @@ bool CNetAddr::IsValid() const return true; } +/** + * @returns Whether or not this network address is publicly routable on the + * global internet. + * + * @note A routable address is always valid. As in, the set of routable addresses + * is a subset of the set of valid addresses. + * + * @see CNetAddr::IsValid() + */ bool CNetAddr::IsRoutable() const { if (!IsValid()) @@ -588,6 +607,16 @@ bool operator<(const CNetAddr& a, const CNetAddr& b) return std::tie(a.m_net, a.m_addr) < std::tie(b.m_net, b.m_addr); } +/** + * Try to get our IPv4 address. + * + * @param[out] pipv4Addr The in_addr struct to which to copy. + * + * @returns Whether or not the operation was successful, in particular, whether + * or not our address was an IPv4 address. + * + * @see CNetAddr::IsIPv4() + */ bool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const { if (!IsIPv4()) @@ -597,6 +626,16 @@ bool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const return true; } +/** + * Try to get our IPv6 (or CJDNS) address. + * + * @param[out] pipv6Addr The in6_addr struct to which to copy. + * + * @returns Whether or not the operation was successful, in particular, whether + * or not our address was an IPv6 address. + * + * @see CNetAddr::IsIPv6() + */ bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const { if (!IsIPv6()) { @@ -887,6 +926,18 @@ bool operator<(const CService& a, const CService& b) return static_cast(a) < static_cast(b) || (static_cast(a) == static_cast(b) && a.port < b.port); } +/** + * Obtain the IPv4/6 socket address this represents. + * + * @param[out] paddr The obtained socket address. + * @param[in,out] addrlen The size, in bytes, of the address structure pointed + * to by paddr. The value that's pointed to by this + * parameter might change after calling this function if + * the size of the corresponding address structure + * changed. + * + * @returns Whether or not the operation was successful. + */ bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const { if (IsIPv4()) { @@ -917,11 +968,14 @@ bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const return false; } +/** + * @returns An identifier unique to this service's address and port number. + */ std::vector CService::GetKey() const { auto key = GetAddrBytes(); - key.push_back(port / 0x100); - key.push_back(port & 0x0FF); + key.push_back(port / 0x100); // most significant byte of our port + key.push_back(port & 0x0FF); // least significant byte of our port return key; } @@ -1041,6 +1095,10 @@ CSubNet::CSubNet(const CNetAddr& addr) : CSubNet() network = addr; } +/** + * @returns True if this subnet is valid, the specified address is valid, and + * the specified address belongs in this subnet. + */ bool CSubNet::Match(const CNetAddr &addr) const { if (!valid || !addr.IsValid() || network.m_net != addr.m_net) diff --git a/src/netaddress.h b/src/netaddress.h index d25d63f65666..c771f760e340 100644 --- a/src/netaddress.h +++ b/src/netaddress.h @@ -153,12 +153,16 @@ class CNetAddr void SetRaw(Network network, const uint8_t *data); public: - /** - * Transform an arbitrary string into a non-routable ipv6 address. - * Useful for mapping resolved addresses back to their source. - */ bool SetInternal(const std::string& name); + /** + * Parse a Tor or I2P address and set this object to it. + * @param[in] addr Address to parse, for example + * pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion or + * ukeu3k5oycgaauneqgtnvselmt4yemvoilkln7jpvamvfx7dnkdq.b32.i2p. + * @returns Whether the operation was successful. + * @see CNetAddr::IsTor(), CNetAddr::IsI2P() + */ bool SetSpecial(const std::string &strName); // for Tor addresses bool IsBindAny() const; // INADDR_ANY equivalent bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0) From 57e3060ec8d8c16786a1cbaa0521cc4ccfbb3930 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Tue, 2 Jul 2019 17:20:58 -0400 Subject: [PATCH 06/35] Merge #16250: signrawtransactionwithkey: report error when missing redeemScript/witnessScript 01174596e69568c434198a86f54cb9ea6740e6c2 signrawtransactionwithkey: report error when missing redeemScript/witnessScript param (Anthony Towns) Pull request description: Adding support for "witnessScript" as an alternative to "redeemScript" when using "signrawtransactionwithkey" meant that the `RPCTypeCheckObj()` call in `SignTransaction` can't error out just because either parameter is missing -- it's only a problem if both are missing, which isn't a state `RPCTypeCheckObj()` tests for. This results in the regression described in #16249. This patch adds some code to test for this case and give a similar error, namely: error code: -8 error message: Missing redeemScript/witnessScript Fixes: #16249 ACKs for top commit: meshcollider: utACK https://github.com/bitcoin/bitcoin/pull/16250/commits/01174596e69568c434198a86f54cb9ea6740e6c2 promag: ACK 01174596e. Could also write test without `dict`/`del`: Tree-SHA512: cf51346b7dea551b7f18f2a93c2a336a293b2535c62c03a5263cd2be8c58cf0cc302891da659c167e88ad1a68a756472c3c07e99f71627c61d32886fc5a3a353 --- src/rpc/rawtransaction_util.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp index 9f22f0555a01..7c7823c5c119 100644 --- a/src/rpc/rawtransaction_util.cpp +++ b/src/rpc/rawtransaction_util.cpp @@ -207,6 +207,9 @@ void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keyst throw JSONRPCError(RPC_INVALID_PARAMETER, "redeemScript does not match scriptPubKey"); } } + if (rs.isNull()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Missing redeemScript"); + } } } } From 914946301c504edf76eb54cfa1e0fb1bc6a1c71e Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 3 Jul 2019 14:06:45 +0200 Subject: [PATCH 07/35] Merge #14734: fix an undefined behavior in uint::SetHex 0f459d868d85053f1cc066ea9099793f88cbd655 fix an undefined behavior in uint::SetHex (Kaz Wesley) Pull request description: Decrementing psz beyond the beginning of the string is UB, even though the out-of-bounds pointer is never dereferenced. I don't think any clang sanitizer covers this, so I don't see any way a test could catch the original behavior. ACKs for top commit: promag: utACK 0f459d8. l2a5b1: utACK 0f459d868d85053f1cc066ea9099793f88cbd655 Tree-SHA512: 388223254ea6e955f643d2ebdf74d15a3d494e9f0597d9f05987ebb708d7a1cc06ce64bd25d447d75b5f5561bdae9630dcf25adb7bd75f7a382298b95d127162 --- src/uint256.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/uint256.cpp b/src/uint256.cpp index 696a7081dd8d..8c89e896824c 100644 --- a/src/uint256.cpp +++ b/src/uint256.cpp @@ -40,16 +40,15 @@ void base_blob::SetHex(const char* psz) psz += 2; // hex string to uint - const char* pbegin = psz; - while (::HexDigit(*psz) != -1) - psz++; - psz--; + size_t digits = 0; + while (::HexDigit(psz[digits]) != -1) + digits++; unsigned char* p1 = (unsigned char*)m_data; unsigned char* pend = p1 + WIDTH; - while (psz >= pbegin && p1 < pend) { - *p1 = ::HexDigit(*psz--); - if (psz >= pbegin) { - *p1 |= ((unsigned char)::HexDigit(*psz--) << 4); + while (digits > 0 && p1 < pend) { + *p1 = ::HexDigit(psz[--digits]); + if (digits > 0) { + *p1 |= ((unsigned char)::HexDigit(psz[--digits]) << 4); p1++; } } From 13ac152c9b13db0c61ad1ca291a3b7303ae18199 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 3 Jul 2019 14:49:07 +0200 Subject: [PATCH 08/35] Merge #16325: rpc: Clarify that block count means height excl genesis fab0c820fa4c0c3227eec85c64310a3bf938a149 rpc: Clarify that block count means height excl genesis (MarcoFalke) Pull request description: There is a common misconception that the block count returned by the blockchain rpcs includes the genesis block. See for example the discussion in https://github.com/bitcoin/bitcoin/pull/16292#issuecomment-506303256. However, it really returns the height, which is `0` for the genesis block. So clarify that and also remove the misleading "longest blockchain" comment. Finally, fix the wallet test that incorrectly used this rpc. ACKs for top commit: instagibbs: utACK https://github.com/bitcoin/bitcoin/pull/16325/commits/fab0c820fa4c0c3227eec85c64310a3bf938a149 promag: ACK fab0c82, sorry for the misconception. Tree-SHA512: 0d087cbb628d3866352bca6420402f392e6a997e579941701a408a7fca355d84645045661f39b022e4479cc07f85a6cddaa9095b6fd9911b245692482420a5e4 --- src/rpc/blockchain.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 67a3ba564cc9..71ea21b39de1 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -49,10 +48,11 @@ #include -#include -#include #include +#include +#include + struct CUpdatedBlock { uint256 hash; From 4459e60acc868d3b04eef744c986449daaa00616 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 8 Jul 2019 13:19:39 +0200 Subject: [PATCH 09/35] Merge #16352: build: prune dbus from depends e8fabd9253400a7c3fe45b34bc572eb00ff5522d build: prune dbus from depends (fanquake) Pull request description: Since #8210 (59d063d07660d6e8d53ed8aa1eb8b0747ea6767c), we've been passing `-dbus-runtime` when configuring Qt. ``` qtbase-opensource-src-5.9.7 $ ./configure -h | grep -i dbus -no-dbus ............. Do not build the Qt D-Bus module -dbus-linked ......... Build Qt D-Bus and link to libdbus-1 [auto] -dbus-runtime ........ Build Qt D-Bus and dynamically load libdbus-1 [no] ``` This means we don't actually seem to be using the `D-Bus` we build in depends. This was pointed out by theuni at the time, [here](https://github.com/bitcoin/bitcoin/pull/7993#issuecomment-223114395) and [here](https://github.com/bitcoin/bitcoin/pull/8210#issuecomment-226930545), but was never followed up. dongcarl also bought it up as part of #16150. I've tested building and running `bitcoin-qt` using depends on Debian. Needs further testing. ACKs for top commit: laanwj: code review ACK e8fabd9253400a7c3fe45b34bc572eb00ff5522d Tree-SHA512: 164e6e52b6f97c04aef42bd185e2a157bc1a42103840f9404c5a795749f45a8c2c35f35873395a3a56398b3cd5955496b90d9c885d929b434c9bc871695abe20 --- depends/packages/dbus.mk | 27 --------------------------- depends/packages/packages.mk | 2 +- doc/dependencies.md | 1 - 3 files changed, 1 insertion(+), 29 deletions(-) delete mode 100644 depends/packages/dbus.mk diff --git a/depends/packages/dbus.mk b/depends/packages/dbus.mk deleted file mode 100644 index ad10b0fdd7fb..000000000000 --- a/depends/packages/dbus.mk +++ /dev/null @@ -1,27 +0,0 @@ -package=dbus -$(package)_version=1.10.18 -$(package)_download_path=https://dbus.freedesktop.org/releases/dbus -$(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=6049ddd5f3f3e2618f615f1faeda0a115104423a7996b7aa73e2f36e38cc514a -$(package)_dependencies=expat - -define $(package)_set_vars - $(package)_config_opts=--disable-tests --disable-doxygen-docs --disable-xml-docs --disable-shared --without-x -endef - -define $(package)_config_cmds - $($(package)_autoconf) -endef - -define $(package)_build_cmds - $(MAKE) -C dbus libdbus-1.la -endef - -define $(package)_stage_cmds - $(MAKE) -C dbus DESTDIR=$($(package)_staging_dir) install-libLTLIBRARIES install-dbusincludeHEADERS install-nodist_dbusarchincludeHEADERS && \ - $(MAKE) DESTDIR=$($(package)_staging_dir) install-pkgconfigDATA -endef - -define $(package)_postprocess_cmds - rm lib/*.la -endef diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index 1b9ecd32cb6d..3452a9359c96 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -1,6 +1,6 @@ packages:=boost libevent gmp backtrace -qt_linux_packages:=qt expat dbus libxcb xcb_proto libXau xproto freetype fontconfig libxkbcommon +qt_linux_packages:=qt expat libxcb xcb_proto libXau xproto freetype fontconfig libxkbcommon qrencode_linux_packages = qrencode qrencode_android_packages = qrencode diff --git a/doc/dependencies.md b/doc/dependencies.md index cc74b0f4edc7..8869b93fee97 100644 --- a/doc/dependencies.md +++ b/doc/dependencies.md @@ -8,7 +8,6 @@ These are the dependencies currently used by Dash Core. You can find instruction | Berkeley DB | [4.8.30](https://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html) | 4.8.x | No | | | | Boost | [1.73.0](https://www.boost.org/users/download/) | [1.64.0](https://github.com/bitcoin/bitcoin/pull/22320) | No | | | | Clang[ \* ](#note1) | | [5.0+](https://releases.llvm.org/download.html) (C++17 support) | | | | -| D-Bus | [1.10.18](https://cgit.freedesktop.org/dbus/dbus/tree/NEWS?h=dbus-1.10) | | No | Yes | | | Expat | [2.2.7](https://libexpat.github.io/) | | No | Yes | | | fontconfig | [2.12.1](https://www.freedesktop.org/software/fontconfig/release/) | | No | Yes | | | FreeType | [2.7.1](https://download.savannah.gnu.org/releases/freetype) | | No | | [Yes](https://github.com/dashpay/dash/blob/develop/depends/packages/qt.mk) (Android only) | From 906dd71de0ed6f74e88e719a52eeaa99f78f0883 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 8 Jul 2019 20:03:25 +0200 Subject: [PATCH 10/35] Merge #16267: bench: Benchmark blockToJSON 91509ffe247b0eacbf84214c7c9c3f8a0012f2eb bench: Benchmark blockToJSON (Kirill Fomichev) Pull request description: Related: - "getblock performance issue on verbosity" https://github.com/bitcoin/bitcoin/issues/15925 - "refactor: Avoid UniValue copy constructor" #15974 ACKs for top commit: laanwj: ACK 91509ffe247b0eacbf84214c7c9c3f8a0012f2eb Tree-SHA512: e70b12cb31921c7527bde334f52f39776da698b6bbdb196079a8b68478c67585a5bd7bed7403f65166bd604f7ed60778c53dc064d743bb8368318a1283d1073e --- src/Makefile.bench.include | 1 + src/bench/rpc_blockchain.cpp | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 src/bench/rpc_blockchain.cpp diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index db47baaffaf5..6171a0381a54 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -39,6 +39,7 @@ bench_bench_dash_SOURCES = \ bench/mempool_stress.cpp \ bench/nanobench.h \ bench/nanobench.cpp \ + bench/rpc_blockchain.cpp \ bench/rpc_mempool.cpp \ bench/util_time.cpp \ bench/base58.cpp \ diff --git a/src/bench/rpc_blockchain.cpp b/src/bench/rpc_blockchain.cpp new file mode 100644 index 000000000000..3cf8947b9964 --- /dev/null +++ b/src/bench/rpc_blockchain.cpp @@ -0,0 +1,35 @@ +// Copyright (c) 2016-2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +static void BlockToJsonVerbose(benchmark::Bench& bench) { + CDataStream stream(benchmark::data::block813851, SER_NETWORK, PROTOCOL_VERSION); + char a = '\0'; + stream.write(&a, 1); // Prevent compaction + + CBlock block; + stream >> block; + + CBlockIndex blockindex; + const uint256 blockHash = block.GetHash(); + blockindex.phashBlock = &blockHash; + blockindex.nBits = 403014710; + + bench.run([&] { + (void)blockToJSON(block, &blockindex, &blockindex, *llmq::chainLocksHandler, *llmq::quorumInstantSendManager, /*verbose*/ true); + }); +} + +BENCHMARK(BlockToJsonVerbose); From ddd8e2f45bf19dbbb3169dcf419ab3bb7d626d55 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 12 Jul 2019 21:17:01 +0200 Subject: [PATCH 11/35] Merge #16334: test: rpc_users: Also test rpcauth.py with password. e263a343d4b6a2622df6bb734cd9d51a0d20a663 test: rpc_users: Make variable names more clear. (Carl Dong) 830dc2dd0fccb7f3ec49ff7233a188d92c541e7e test: rpc_users: Also test rpcauth.py with specified password. (Carl Dong) c73d871799982ca29c29cef90e1a78814cf34019 test: rpc_users: Add function for testing auth params. (Carl Dong) 604e2a997ff26202dd0fa1932d60dc14cc53ac6d test: rpc_users: Add function for auth'd requests. (Carl Dong) Pull request description: Fixes #14758 First two commits are tidy-ups which I feel are worthwhile as they are very straightforward, cut down the file by 50%, and made the final diff more minimal. Happy to squash after review. ACKs for top commit: laanwj: ACK e263a343d4b6a2622df6bb734cd9d51a0d20a663 Tree-SHA512: aa75c48570a87060238932d4c68e17234e158077f6195fb4917367e1ecc565e3cd8dd0ae51f9159ddd3d03742739680391bc1246454302db22d4a608c0633e80 --- test/functional/rpc_users.py | 178 ++++++++--------------------------- 1 file changed, 39 insertions(+), 139 deletions(-) diff --git a/test/functional/rpc_users.py b/test/functional/rpc_users.py index 22c8885b8dc5..76d66b2a2a79 100755 --- a/test/functional/rpc_users.py +++ b/test/functional/rpc_users.py @@ -20,6 +20,17 @@ import configparser import sys +def call_with_auth(node, user, password): + url = urllib.parse.urlparse(node.url) + headers = {"Authorization": "Basic " + str_to_b64str('{}:{}'.format(user, password))} + + conn = http.client.HTTPConnection(url.hostname, url.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + resp = conn.getresponse() + conn.close() + return resp + class HTTPBasicsTest(BitcoinTestFramework): def set_test_params(self): @@ -29,15 +40,24 @@ def set_test_params(self): def setup_chain(self): super().setup_chain() #Append rpcauth to dash.conf before initialization + self.rtpassword = "cA773lm788buwYe4g4WT+05pKyNruVKjQ25x3n0DQcM=" rpcauth = "rpcauth=rt:93648e835a54c573682c2eb19f882535$7681e9c5b74bdd85e78166031d2058e1069b3ed7ed967c93fc63abba06f31144" - rpcauth2 = "rpcauth=rt2:f8607b1a88861fac29dfccf9b52ff9f$ff36a0c23c8c62b4846112e50fa888416e94c17bfd4c42f88fd8f55ec6a3137e" - rpcuser = "rpcuser=rpcuser💻" - rpcpassword = "rpcpassword=rpcpassword🔑" - self.user = ''.join(SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(10)) + self.rpcuser = "rpcuser💻" + self.rpcpassword = "rpcpassword🔑" + config = configparser.ConfigParser() config.read_file(open(self.options.configfile)) gen_rpcauth = config['environment']['RPCAUTH'] + + # Generate RPCAUTH with specified password + self.rt2password = "8/F3uMDw4KSEbw96U3CA1C4X05dkHDN2BPFjTgZW4KI=" + p = subprocess.Popen([sys.executable, gen_rpcauth, 'rt2', self.rt2password], stdout=subprocess.PIPE, universal_newlines=True) + lines = p.stdout.read().splitlines() + rpcauth2 = lines[1] + + # Generate RPCAUTH without specifying password + self.user = ''.join(SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(10)) p = subprocess.Popen([sys.executable, gen_rpcauth, self.user], stdout=subprocess.PIPE, universal_newlines=True) lines = p.stdout.read().splitlines() rpcauth3 = lines[1] @@ -48,155 +68,35 @@ def setup_chain(self): f.write(rpcauth2 + "\n") f.write(rpcauth3 + "\n") with open(os.path.join(get_datadir_path(self.options.tmpdir, 1), "dash.conf"), 'a', encoding='utf8') as f: - f.write(rpcuser + "\n") - f.write(rpcpassword + "\n") + f.write("rpcuser={}\n".format(self.rpcuser)) + f.write("rpcpassword={}\n".format(self.rpcpassword)) - def run_test(self): - self.log.info('Check correctness of the rpcauth config option') - url = urllib.parse.urlparse(self.nodes[0].url) - - #Old authpair - authpair = url.username + ':' + url.password - - #New authpair generated via share/rpcauth tool - password = "cA773lm788buwYe4g4WT+05pKyNruVKjQ25x3n0DQcM=" - - #Second authpair with different username - password2 = "8/F3uMDw4KSEbw96U3CA1C4X05dkHDN2BPFjTgZW4KI=" - authpairnew = "rt:"+password - - self.log.info('Correct...') - headers = {"Authorization": "Basic " + str_to_b64str(authpair)} - - conn = http.client.HTTPConnection(url.hostname, url.port) - conn.connect() - conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) - resp = conn.getresponse() - assert_equal(resp.status, 200) - conn.close() - - #Use new authpair to confirm both work + def test_auth(self, node, user, password): self.log.info('Correct...') - headers = {"Authorization": "Basic " + str_to_b64str(authpairnew)} - - conn = http.client.HTTPConnection(url.hostname, url.port) - conn.connect() - conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) - resp = conn.getresponse() - assert_equal(resp.status, 200) - conn.close() + assert_equal(200, call_with_auth(node, user, password).status) - #Wrong login name with rt's password self.log.info('Wrong...') - authpairnew = "rtwrong:"+password - headers = {"Authorization": "Basic " + str_to_b64str(authpairnew)} + assert_equal(401, call_with_auth(node, user, password+'wrong').status) - conn = http.client.HTTPConnection(url.hostname, url.port) - conn.connect() - conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) - resp = conn.getresponse() - assert_equal(resp.status, 401) - conn.close() - - #Wrong password for rt self.log.info('Wrong...') - authpairnew = "rt:"+password+"wrong" - headers = {"Authorization": "Basic " + str_to_b64str(authpairnew)} - - conn = http.client.HTTPConnection(url.hostname, url.port) - conn.connect() - conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) - resp = conn.getresponse() - assert_equal(resp.status, 401) - conn.close() + assert_equal(401, call_with_auth(node, user+'wrong', password).status) - #Correct for rt2 - self.log.info('Correct...') - authpairnew = "rt2:"+password2 - headers = {"Authorization": "Basic " + str_to_b64str(authpairnew)} - - conn = http.client.HTTPConnection(url.hostname, url.port) - conn.connect() - conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) - resp = conn.getresponse() - assert_equal(resp.status, 200) - conn.close() - - #Wrong password for rt2 self.log.info('Wrong...') - authpairnew = "rt2:"+password2+"wrong" - headers = {"Authorization": "Basic " + str_to_b64str(authpairnew)} - - conn = http.client.HTTPConnection(url.hostname, url.port) - conn.connect() - conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) - resp = conn.getresponse() - assert_equal(resp.status, 401) - conn.close() - - #Correct for randomly generated user - self.log.info('Correct...') - authpairnew = self.user+":"+self.password - headers = {"Authorization": "Basic " + str_to_b64str(authpairnew)} - - conn = http.client.HTTPConnection(url.hostname, url.port) - conn.connect() - conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) - resp = conn.getresponse() - assert_equal(resp.status, 200) - conn.close() + assert_equal(401, call_with_auth(node, user+'wrong', password+'wrong').status) - #Wrong password for randomly generated user - self.log.info('Wrong...') - authpairnew = self.user+":"+self.password+"Wrong" - headers = {"Authorization": "Basic " + str_to_b64str(authpairnew)} + def run_test(self): + self.log.info('Check correctness of the rpcauth config option') + url = urllib.parse.urlparse(self.nodes[0].url) - conn = http.client.HTTPConnection(url.hostname, url.port) - conn.connect() - conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) - resp = conn.getresponse() - assert_equal(resp.status, 401) - conn.close() + self.test_auth(self.nodes[0], url.username, url.password) + self.test_auth(self.nodes[0], 'rt', self.rtpassword) + self.test_auth(self.nodes[0], 'rt2', self.rt2password) + self.test_auth(self.nodes[0], self.user, self.password) self.log.info('Check correctness of the rpcuser/rpcpassword config options') url = urllib.parse.urlparse(self.nodes[1].url) - # rpcuser and rpcpassword authpair - self.log.info('Correct...') - rpcuserauthpair = "rpcuser💻:rpcpassword🔑" - - headers = {"Authorization": "Basic " + str_to_b64str(rpcuserauthpair)} - - conn = http.client.HTTPConnection(url.hostname, url.port) - conn.connect() - conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) - resp = conn.getresponse() - assert_equal(resp.status, 200) - conn.close() - - #Wrong login name with rpcuser's password - rpcuserauthpair = "rpcuserwrong:rpcpassword" - headers = {"Authorization": "Basic " + str_to_b64str(rpcuserauthpair)} - - conn = http.client.HTTPConnection(url.hostname, url.port) - conn.connect() - conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) - resp = conn.getresponse() - assert_equal(resp.status, 401) - conn.close() - - #Wrong password for rpcuser - self.log.info('Wrong...') - rpcuserauthpair = "rpcuser:rpcpasswordwrong" - headers = {"Authorization": "Basic " + str_to_b64str(rpcuserauthpair)} - - conn = http.client.HTTPConnection(url.hostname, url.port) - conn.connect() - conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) - resp = conn.getresponse() - assert_equal(resp.status, 401) - conn.close() - + self.test_auth(self.nodes[1], self.rpcuser, self.rpcpassword) init_error = 'Error: Unable to start HTTP server. See debug log for details.' From e246892fd701dafa894ce76f49bb9092a53ac968 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sun, 28 Jul 2019 10:12:46 -0400 Subject: [PATCH 12/35] Merge #16464: [qa] Ensure we don't generate a too-big block in p2sh sigops test bf3be5297a746982cf8e83f45d342121e5665f80 [qa] Ensure we don't generate a too-big block in p2sh sigops test (Suhas Daftuar) Pull request description: There's a bug in the loop that is calculating the block size in the p2sh sigops test -- we start with the size of the block when it has no transactions, and then increment by the size of each transaction we add, without regard to the changing size of the encoding for the number of transactions in the block. This might be fine if the block construction were deterministic, but the first transaction in the block has an ECDSA signature which can be variable length, so we see intermittent failures of this test when the initial transaction has a 70-byte signature and the block ends up being one byte too big. Fix this by double-checking the block size after construction. ACKs for top commit: jonasschnelli: utACK bf3be5297a746982cf8e83f45d342121e5665f80 jnewbery: tested ACK bf3be5297a746982cf8e83f45d342121e5665f80 Tree-SHA512: f86385b96f7a6feafa4183727f5f2c9aae8ad70060b574aad13b150f174a17ce9a0040bc51ae7a04bd08f2a5298b983a84b0aed5e86a8440189ebc63b99e64dc --- test/functional/feature_block.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py index 96f4d115dc9f..44dc80ccdb3c 100755 --- a/test/functional/feature_block.py +++ b/test/functional/feature_block.py @@ -506,6 +506,14 @@ def run_test(self): tx_last = tx_new b39_outputs += 1 + # The accounting in the loop above can be off, because it misses the + # compact size encoding of the number of transactions in the block. + # Make sure we didn't accidentally make too big a block. Note that the + # size of the block has non-determinism due to the ECDSA signature in + # the first transaction. + while (len(b39.serialize()) >= MAX_BLOCK_SIZE): + del b39.vtx[-1] + b39 = self.update_block(39, []) self.send_blocks([b39], True) self.save_spendable_output() From 211faa9c2929d9835786b654501015cf36e69468 Mon Sep 17 00:00:00 2001 From: MeshCollider Date: Tue, 30 Jul 2019 20:31:12 +1200 Subject: [PATCH 13/35] Merge #15709: wallet: Do not add "setting" key as unknown 914923d125f5d17b39b4dc05f666d130e80a68b2 Add setting as known type (Peter Bushnell) Pull request description: When loading old wallets I get "Unknown wallet records" showing up in the log file. The key that is adding to the unknown record count is "setting", this is a known key removed in the 0.6 release of Bitcoin in the commit linked below. The "setting" key is not known to the wallet anymore, like "acentry" which is not added as an unknown record, but the "setting" key was used in previous versions of Bitcoin. https://github.com/bitcoin/bitcoin/commit/972060ce0e9746c979ce0ddeeb997121414c1d58#diff-8094838580e1bb7a3bb8fc78dcebc733 ACKs for top commit: laanwj: ACK 914923d125f5d17b39b4dc05f666d130e80a68b2, this code change is straightforward enough and I don't think it makes sense to warn about this key being present. meshcollider: ACK 914923d125f5d17b39b4dc05f666d130e80a68b2 Tree-SHA512: 6346690c05cebae2dcd868512322bf5250f6fbd07abb5e747065444185d3f69e19e1a99e3f38d6e34535ffd6979b2297100ba9c7da8e45ca792598eded5ae0d3 --- src/wallet/walletdb.cpp | 4 +++- src/wallet/walletdb.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 32ca41e963bc..b32544b28a2b 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -55,6 +55,7 @@ const std::string ORDERPOSNEXT{"orderposnext"}; const std::string POOL{"pool"}; const std::string PURPOSE{"purpose"}; const std::string PRIVATESEND_SALT{"ps_salt"}; +const std::string SETTINGS{"settings"}; const std::string TX{"tx"}; const std::string VERSION{"version"}; const std::string WATCHMETA{"watchmeta"}; @@ -487,7 +488,8 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, strErr = "Found unsupported 'wkey' record, try loading with version 0.17"; return false; } else if (strType != DBKeys::BESTBLOCK && strType != DBKeys::BESTBLOCK_NOMERKLE && - strType != DBKeys::MINVERSION && strType != DBKeys::ACENTRY && strType != DBKeys::VERSION) { + strType != DBKeys::MINVERSION && strType != DBKeys::ACENTRY && + strType != DBKeys::VERSION && strType != DBKeys::SETTINGS) { wss.m_unknown_records++; } } catch (const std::exception& e) { diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 2ec827c89ff8..878ed78df2d5 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -76,6 +76,7 @@ extern const std::string ORDERPOSNEXT; extern const std::string POOL; extern const std::string PURPOSE; extern const std::string PRIVATESEND_SALT; +extern const std::string SETTINGS; extern const std::string TX; extern const std::string VERSION; extern const std::string WATCHMETA; From 08aa10c8cb935d813869366a9bc9317768a8a4a5 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Thu, 30 Mar 2023 21:49:22 +0700 Subject: [PATCH 14/35] fix: add a missing name for key `hdaccounts` for RPC help for `getwalletinfo` (#5280) ## Issue being fixed or feature implemented RPC help has a wrongly generated RPC help output in CLI and online help: https://dashcore.readme.io/docs/core-api-ref-remote-procedure-calls-wallet#getwalletinfo New version: ``` ... "hdaccounts" : [ (json array) { (json object) "hdaccountindex" : n, (numeric) the index of the account "hdexternalkeyindex" : n, (numeric) current external childkey index "hdinternalkeyindex" : n (numeric) current internal childkey index }, ... ], ... ``` against old version: ``` ... "" : [ (json array) { (json object) "hdaccountindex" : n, (numeric) the index of the account "hdexternalkeyindex" : n, (numeric) current external childkey index "hdinternalkeyindex" : n (numeric) current internal childkey index }, ... ], ... ``` ## What was done? Add a missing name `hdaccounts` for that key for `getwalletinfo` RPC ## How Has This Been Tested? Run a command `help getwalletinfo` for old and for new versions. ## Breaking Changes No breaking changes. It doesn't change rpc, only change text description (help). ## Checklist: - [x] I have performed a self-review of my own code - [x] I have assigned this pull request to a milestone --- src/wallet/rpcwallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 1c92cac730e7..613b0b18d295 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2474,7 +2474,7 @@ static UniValue getwalletinfo(const JSONRPCRequest& request) {RPCResult::Type::STR_AMOUNT, "paytxfee", "the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB"}, {RPCResult::Type::STR_HEX, "hdchainid", "the ID of the HD chain"}, {RPCResult::Type::STR, "hdaccountcount", "how many accounts of the HD chain are in this wallet"}, - {RPCResult::Type::ARR, "", "", + {RPCResult::Type::ARR, "hdaccounts", "", { {RPCResult::Type::OBJ, "", "", { From f4b91c08a6ea0ed0447d0c30c41905f90d8626fb Mon Sep 17 00:00:00 2001 From: Odysseas Gabrielides Date: Thu, 30 Mar 2023 18:05:15 +0300 Subject: [PATCH 15/35] fix(net): Do not punish nodes when Quorum data are missing. (#5272) ## Issue being fixed or feature implemented Currently, we store internally the nodes that already requested `QGETDATA` for the same Quorum. If data for the same Quorum is requested twice from the same `proRegTx`, then the requester is P2P misbehaved. ## What was done? Some data like `VerificationVector` and `EncryptedContributions` are not instantly available. This PR does not misbehave nodes for requesting data that weren't available when asked. ## How Has This Been Tested? ## Breaking Changes ## Checklist: - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have made corresponding changes to the documentation **For repository code-owners and collaborators only** - [x] I have assigned this pull request to a milestone --- src/llmq/quorums.cpp | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/llmq/quorums.cpp b/src/llmq/quorums.cpp index cfcf66366822..1304ee12872e 100644 --- a/src/llmq/quorums.cpp +++ b/src/llmq/quorums.cpp @@ -631,13 +631,29 @@ void CQuorumManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, C CQuorumDataRequest request; vRecv >> request; - auto sendQDATA = [&](CQuorumDataRequest::Errors nError = CQuorumDataRequest::Errors::UNDEFINED, + auto sendQDATA = [&](CQuorumDataRequest::Errors nError, + bool request_limit_exceeded, const CDataStream& body = CDataStream(SER_NETWORK, PROTOCOL_VERSION)) { + switch (nError) { + case (CQuorumDataRequest::Errors::NONE): + case (CQuorumDataRequest::Errors::QUORUM_TYPE_INVALID): + case (CQuorumDataRequest::Errors::QUORUM_BLOCK_NOT_FOUND): + case (CQuorumDataRequest::Errors::QUORUM_NOT_FOUND): + case (CQuorumDataRequest::Errors::MASTERNODE_IS_NO_MEMBER): + case (CQuorumDataRequest::Errors::UNDEFINED): + if (request_limit_exceeded) errorHandler("Request limit exceeded", 25); + break; + case (CQuorumDataRequest::Errors::QUORUM_VERIFICATION_VECTOR_MISSING): + case (CQuorumDataRequest::Errors::ENCRYPTED_CONTRIBUTIONS_MISSING): + // Do not punish limit exceed if we don't have the requested data + break; + } request.SetError(nError); CDataStream ssResponse(SER_NETWORK, pfrom.GetSendVersion(), request, body); connman.PushMessage(&pfrom, CNetMsgMaker(pfrom.GetSendVersion()).Make(NetMsgType::QDATA, ssResponse)); }; + bool request_limit_exceeded(false); { LOCK2(cs_main, cs_data_requests); CQuorumDataRequestKey key; @@ -651,24 +667,24 @@ void CQuorumManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, C } else if (it->second.IsExpired()) { it->second = request; } else { - errorHandler("Request limit exceeded", 25); + request_limit_exceeded = true; } } if (!GetLLMQParams(request.GetLLMQType()).has_value()) { - sendQDATA(CQuorumDataRequest::Errors::QUORUM_TYPE_INVALID); + sendQDATA(CQuorumDataRequest::Errors::QUORUM_TYPE_INVALID, request_limit_exceeded); return; } const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return LookupBlockIndex(request.GetQuorumHash())); if (pQuorumBaseBlockIndex == nullptr) { - sendQDATA(CQuorumDataRequest::Errors::QUORUM_BLOCK_NOT_FOUND); + sendQDATA(CQuorumDataRequest::Errors::QUORUM_BLOCK_NOT_FOUND, request_limit_exceeded); return; } const CQuorumCPtr pQuorum = GetQuorum(request.GetLLMQType(), pQuorumBaseBlockIndex); if (pQuorum == nullptr) { - sendQDATA(CQuorumDataRequest::Errors::QUORUM_NOT_FOUND); + sendQDATA(CQuorumDataRequest::Errors::QUORUM_NOT_FOUND, request_limit_exceeded); return; } @@ -677,7 +693,7 @@ void CQuorumManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, C // Check if request wants QUORUM_VERIFICATION_VECTOR data if (request.GetDataMask() & CQuorumDataRequest::QUORUM_VERIFICATION_VECTOR) { if (!pQuorum->HasVerificationVector()) { - sendQDATA(CQuorumDataRequest::Errors::QUORUM_VERIFICATION_VECTOR_MISSING); + sendQDATA(CQuorumDataRequest::Errors::QUORUM_VERIFICATION_VECTOR_MISSING, request_limit_exceeded); return; } @@ -689,20 +705,20 @@ void CQuorumManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, C int memberIdx = pQuorum->GetMemberIndex(request.GetProTxHash()); if (memberIdx == -1) { - sendQDATA(CQuorumDataRequest::Errors::MASTERNODE_IS_NO_MEMBER); + sendQDATA(CQuorumDataRequest::Errors::MASTERNODE_IS_NO_MEMBER, request_limit_exceeded); return; } std::vector> vecEncrypted; if (!dkgManager.GetEncryptedContributions(request.GetLLMQType(), pQuorumBaseBlockIndex, pQuorum->qc->validMembers, request.GetProTxHash(), vecEncrypted)) { - sendQDATA(CQuorumDataRequest::Errors::ENCRYPTED_CONTRIBUTIONS_MISSING); + sendQDATA(CQuorumDataRequest::Errors::ENCRYPTED_CONTRIBUTIONS_MISSING, request_limit_exceeded); return; } ssResponseData << vecEncrypted; } - sendQDATA(CQuorumDataRequest::Errors::NONE, ssResponseData); + sendQDATA(CQuorumDataRequest::Errors::NONE, request_limit_exceeded, ssResponseData); return; } From 2d89442d89fbfebb69ddb4ea35221f5305ef980e Mon Sep 17 00:00:00 2001 From: Odysseas Gabrielides Date: Thu, 30 Mar 2023 18:06:47 +0300 Subject: [PATCH 16/35] fix: hpmn adjustements to getprojectedmnpayees (#5274) ## Issue being fixed or feature implemented `GetProjectedMNPayees` wasn't projecting MN payees correctly. ## What was done? HPMNs are now added 4 times before sorting the return list. In addition, the case of last payee being HPMN and having still pending payments is handled. ## How Has This Been Tested? Tested on Masternodes / Next Payment tab on Qt client on Testnet. ## Breaking Changes ## Checklist: - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have made corresponding changes to the documentation **For repository code-owners and collaborators only** - [x] I have assigned this pull request to a milestone --- src/evo/deterministicmns.cpp | 26 +++++++++++++++++++++++--- src/evo/deterministicmns.h | 9 +++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/evo/deterministicmns.cpp b/src/evo/deterministicmns.cpp index 9905d351b542..fe266149ad9c 100644 --- a/src/evo/deterministicmns.cpp +++ b/src/evo/deterministicmns.cpp @@ -218,15 +218,35 @@ std::vector CDeterministicMNList::GetProjectedMNPayees(int if (nCount < 0 ) { return {}; } - nCount = std::min(nCount, int(GetValidMNsCount())); + nCount = std::min(nCount, int(GetValidWeightedMNsCount())); std::vector result; result.reserve(nCount); + auto remaining_hpmn_payments = 0; + CDeterministicMNCPtr hpmn_to_be_skipped = nullptr; ForEachMNShared(true, [&](const CDeterministicMNCPtr& dmn) { - result.emplace_back(dmn); + if (dmn->pdmnState->nLastPaidHeight == nHeight) { + // We found the last MN Payee. + // If the last payee is a HPMN, we need to check its consecutive payments and pay him again if needed + if (dmn->nType == MnType::HighPerformance && dmn->pdmnState->nConsecutivePayments < dmn_types::HighPerformance.voting_weight) { + remaining_hpmn_payments = dmn_types::HighPerformance.voting_weight - dmn->pdmnState->nConsecutivePayments; + for ([[maybe_unused]] auto _ : irange::range(remaining_hpmn_payments)) { + result.emplace_back(dmn); + hpmn_to_be_skipped = dmn; + } + } + } + return; + }); + + ForEachMNShared(true, [&](const CDeterministicMNCPtr& dmn) { + if (dmn == hpmn_to_be_skipped) return; + for ([[maybe_unused]] auto _ : irange::range(GetMnType(dmn->nType).voting_weight)) { + result.emplace_back(dmn); + } }); - std::sort(result.begin(), result.end(), [&](const CDeterministicMNCPtr& a, const CDeterministicMNCPtr& b) { + std::sort(result.begin() + remaining_hpmn_payments, result.end(), [&](const CDeterministicMNCPtr& a, const CDeterministicMNCPtr& b) { return CompareByLastPaid(a.get(), b.get()); }); diff --git a/src/evo/deterministicmns.h b/src/evo/deterministicmns.h index bd7f74d15fa7..108cbbc75f7d 100644 --- a/src/evo/deterministicmns.h +++ b/src/evo/deterministicmns.h @@ -19,6 +19,7 @@ #include +#include #include #include @@ -241,6 +242,14 @@ class CDeterministicMNList return ranges::count_if(mnMap, [](const auto& p) { return p.second->nType == MnType::HighPerformance && IsMNValid(*p.second); }); } + [[nodiscard]] size_t GetValidWeightedMNsCount() const + { + return std::accumulate(mnMap.begin(), mnMap.end(), 0, [](auto res, const auto& p) { + if (!IsMNValid(*p.second)) return res; + return res + GetMnType(p.second->nType).voting_weight; + }); + } + /** * Execute a callback on all masternodes in the mnList. This will pass a reference * of each masternode to the callback function. This should be preferred over ForEachMNShared. From 1a96a98481b66a40443ceaeb7cc3578c55c4caba Mon Sep 17 00:00:00 2001 From: PastaPastaPasta <6443210+PastaPastaPasta@users.noreply.github.com> Date: Thu, 30 Mar 2023 10:24:44 -0500 Subject: [PATCH 17/35] fix: add a `bias` to IsExpired to avoid potential timing issues where nodeA thinks it's been 300 seconds but nodeB only thinks it's been 295 for some reason (#5276) ## Issue being fixed or feature implemented add a bias to IsExpired to avoid potential timing issues where nodeA thinks it's been 300 seconds but nodeB only thinks it's been 295 for some reason ## What was done? ## How Has This Been Tested? ## Breaking Changes ## Checklist: - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have made corresponding changes to the documentation **For repository code-owners and collaborators only** - [x] I have assigned this pull request to a milestone --- src/llmq/quorums.cpp | 8 ++++---- src/llmq/quorums.h | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/llmq/quorums.cpp b/src/llmq/quorums.cpp index 1304ee12872e..522e60d0a1d9 100644 --- a/src/llmq/quorums.cpp +++ b/src/llmq/quorums.cpp @@ -283,7 +283,7 @@ void CQuorumManager::UpdatedBlockTip(const CBlockIndex* pindexNew, bool fInitial LOCK(cs_data_requests); auto it = mapQuorumDataRequests.begin(); while (it != mapQuorumDataRequests.end()) { - if (it->second.IsExpired()) { + if (it->second.IsExpired(/*add_bias=*/true)) { it = mapQuorumDataRequests.erase(it); } else { ++it; @@ -474,7 +474,7 @@ bool CQuorumManager::RequestQuorumData(CNode* pfrom, Consensus::LLMQType llmqTyp key.quorumHash = pQuorumBaseBlockIndex->GetBlockHash(); key.llmqType = llmqType; auto it = mapQuorumDataRequests.emplace(key, CQuorumDataRequest(llmqType, pQuorumBaseBlockIndex->GetBlockHash(), nDataMask, proTxHash)); - if (!it.second && !it.first->second.IsExpired()) { + if (!it.second && !it.first->second.IsExpired(/*add_bias=*/true)) { LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- Already requested\n", __func__); return false; } @@ -664,7 +664,7 @@ void CQuorumManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, C auto it = mapQuorumDataRequests.find(key); if (it == mapQuorumDataRequests.end()) { it = mapQuorumDataRequests.emplace(key, request).first; - } else if (it->second.IsExpired()) { + } else if (it->second.IsExpired(/*add_bias=*/false)) { it->second = request; } else { request_limit_exceeded = true; @@ -919,7 +919,7 @@ void CQuorumManager::StartQuorumDataRecoveryThread(const CQuorumCPtr pQuorum, co key.quorumHash = pQuorum->qc->quorumHash; key.llmqType = pQuorum->qc->llmqType; auto it = mapQuorumDataRequests.find(key); - if (it != mapQuorumDataRequests.end() && !it->second.IsExpired()) { + if (it != mapQuorumDataRequests.end() && !it->second.IsExpired(/*add_bias=*/true)) { printLog("Already asked"); continue; } diff --git a/src/llmq/quorums.h b/src/llmq/quorums.h index 5e6d12dd8c06..6e24d369d1fd 100644 --- a/src/llmq/quorums.h +++ b/src/llmq/quorums.h @@ -83,6 +83,7 @@ class CQuorumDataRequest bool fProcessed{false}; static constexpr int64_t EXPIRATION_TIMEOUT{300}; + static constexpr int64_t EXPIRATION_BIAS{60}; public: @@ -119,7 +120,7 @@ class CQuorumDataRequest Errors GetError() const { return nError; } std::string GetErrorString() const; - bool IsExpired() const { return (GetTime() - nTime) >= EXPIRATION_TIMEOUT; } + bool IsExpired(bool add_bias) const { return (GetTime() - nTime) >= (EXPIRATION_TIMEOUT + (add_bias ? EXPIRATION_BIAS : 0)); } bool IsProcessed() const { return fProcessed; } void SetProcessed() { fProcessed = true; } From 6e00fd06059dfb40a3313dc06c62a26ae6beb1cf Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Thu, 30 Mar 2023 19:45:02 +0300 Subject: [PATCH 18/35] fix(test): bump `quorum_data_request_expiration_timeout` to fix `p2p_quorum_data.py` (#5281) ## Issue being fixed or feature implemented fix `p2p_quorum_data.py` test broken by #5276 ## What was done? adjust data request expiration timeout in tests ## How Has This Been Tested? `./test/functional/test_runner.py p2p_quorum_data.py` ## Breaking Changes n/a ## Checklist: - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [x] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have made corresponding changes to the documentation **For repository code-owners and collaborators only** - [x] I have assigned this pull request to a milestone --- test/functional/test_framework/test_framework.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 66d5745ab40c..abff8e31ee24 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -1000,8 +1000,8 @@ def set_dash_test_params(self, num_nodes, masterodes_count, extra_args=None, fas # This is nRequestTimeout in dash-q-recovery thread self.quorum_data_thread_request_timeout_seconds = 10 - # This is EXPIRATION_TIMEOUT in CQuorumDataRequest - self.quorum_data_request_expiration_timeout = 300 + # This is EXPIRATION_TIMEOUT + EXPIRATION_BIAS in CQuorumDataRequest + self.quorum_data_request_expiration_timeout = 360 def set_dash_dip8_activation(self, activate_after_block): self.dip8_activation_height = activate_after_block From 6947dfbda6a72a9b3d4bcb651f28452e75870f9d Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sat, 29 Aug 2020 10:03:41 +0200 Subject: [PATCH 19/35] Merge #18817: doc: Document differences in bitcoind and bitcoin-qt locale handling ca185cf5a14b16d61814d7172284bc8efcd28b69 doc: Document differences in bitcoind and bitcoin-qt locale handling (practicalswift) Pull request description: Document differences in `bitcoind` and `bitcoin-qt` locale handling. Since this seems to be the root cause to the locale dependency issues we've seen over the years I thought it was worth documenting :) Note that 1.) `QLocale` (used by Qt), 2.) C locale (used by locale-sensitive C standard library functions/POSIX functions and some parts of the C++ standard library such as `std::to_string`) and 3.) C++ locale (used by the C++ input/output library) are three separate things. This comment is about the perhaps surprising interference with the C locale (2) that takes place as part of the Qt initialization. ACKs for top commit: hebasto: re-ACK ca185cf5a14b16d61814d7172284bc8efcd28b69 Tree-SHA512: e51c32f3072c506b0029a001d8b108125e1acb4f2b6a48a6be721ddadda9da0ae77a9b39ff33f9d9eebabe2244c1db09e8502e3e7012d7a5d40d98e96da0dc44 --- src/qt/bitcoin.cpp | 1 + test/lint/lint-locale-dependence.sh | 33 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 4ee2d11fb03d..fc3c246c2960 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -206,6 +206,7 @@ BitcoinApplication::BitcoinApplication(interfaces::Node& node): pollShutdownTimer(nullptr), returnValue(0) { + // Qt runs setlocale(LC_ALL, "") on initialization. setQuitOnLastWindowClosed(false); } diff --git a/test/lint/lint-locale-dependence.sh b/test/lint/lint-locale-dependence.sh index 7020c43917d7..3f1ef8daf1b5 100755 --- a/test/lint/lint-locale-dependence.sh +++ b/test/lint/lint-locale-dependence.sh @@ -8,6 +8,39 @@ export LC_ALL=C # TODO: Reduce KNOWN_VIOLATIONS by replacing uses of locale dependent stoul/strtol with locale # independent ToIntegral(...). # TODO: Reduce KNOWN_VIOLATIONS by replacing uses of locale dependent snprintf with strprintf. + +# Be aware that bitcoind and bitcoin-qt differ in terms of localization: Qt +# opts in to POSIX localization by running setlocale(LC_ALL, "") on startup, +# whereas no such call is made in bitcoind. +# +# Qt runs setlocale(LC_ALL, "") on initialization. This installs the locale +# specified by the user's LC_ALL (or LC_*) environment variable as the new +# C locale. +# +# In contrast, bitcoind does not opt in to localization -- no call to +# setlocale(LC_ALL, "") is made and the environment variables LC_* are +# thus ignored. +# +# This results in situations where bitcoind is guaranteed to be running +# with the classic locale ("C") whereas the locale of bitcoin-qt will vary +# depending on the user's environment variables. +# +# An example: Assuming the environment variable LC_ALL=de_DE then the +# call std::to_string(1.23) will return "1.230000" in bitcoind but +# "1,230000" in bitcoin-qt. +# +# From the Qt documentation: +# "On Unix/Linux Qt is configured to use the system locale settings by default. +# This can cause a conflict when using POSIX functions, for instance, when +# converting between data types such as floats and strings, since the notation +# may differ between locales. To get around this problem, call the POSIX function +# setlocale(LC_NUMERIC,"C") right after initializing QApplication, QGuiApplication +# or QCoreApplication to reset the locale that is used for number formatting to +# "C"-locale." +# +# See https://doc.qt.io/qt-5/qcoreapplication.html#locale-settings and +# https://stackoverflow.com/a/34878283 for more details. + KNOWN_VIOLATIONS=( "src/bitcoin-tx.cpp.*stoul" "src/dbwrapper.cpp.*stoul" From b35557be971ebcd45bf1941d1fe3f8c1d845ef8b Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sat, 16 May 2020 06:16:45 -0400 Subject: [PATCH 20/35] Merge #18952: test: avoid os-dependant path 8a22fd01140bd957036fc00419b147e4268ae9b1 avoided os-dependant path (Ferdinando M. Ametrano) Pull request description: The current code fails on windows because of the forward slashes; using os.path.join solves the problem and it is in general more robust ACKs for top commit: MarcoFalke: ACK 8a22fd01140bd957036fc00419b147e4268ae9b1 Tree-SHA512: 813f27aea33f97c8afac52e716a55fc5d7fb69621023aba99d40df7e1d145e0ec8d1eee49ddd403b219bf0e0e168e0e987b05c78eaef611f744d99bf2fc8bc91 --- test/functional/test_framework/test_framework.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index abff8e31ee24..799142a619fa 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -238,8 +238,18 @@ def setup(self): config = self.config - self.options.bitcoind = os.getenv("BITCOIND", default=config["environment"]["BUILDDIR"] + '/src/dashd' + config["environment"]["EXEEXT"]) - self.options.bitcoincli = os.getenv("BITCOINCLI", default=config["environment"]["BUILDDIR"] + '/src/dash-cli' + config["environment"]["EXEEXT"]) + fname_bitcoind = os.path.join( + config["environment"]["BUILDDIR"], + "src", + "dashd" + config["environment"]["EXEEXT"] + ) + fname_bitcoincli = os.path.join( + config["environment"]["BUILDDIR"], + "src", + "dash-cli" + config["environment"]["EXEEXT"] + ) + self.options.bitcoind = os.getenv("BITCOIND", default=fname_bitcoind) + self.options.bitcoincli = os.getenv("BITCOINCLI", default=fname_bitcoincli) self.extra_args_from_options = self.options.dashd_extra_args From 79a5b197b0b3fa01c69d671e1d54fe824f7c20d7 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Tue, 4 Apr 2023 19:07:00 +0300 Subject: [PATCH 21/35] refactor/fix: replace expired requests with a new one in RequestQuorumData (#5286) ## Issue being fixed or feature implemented should fix "qdata: Already received" discouraging issue the root of the issue is that we remove expired requests on UpdatedBlockTip which is too late sometimes. ## What was done? replacing expired requests with a new one in RequestQuorumData kind of does the same (drops the expired request) but without waiting for UpdatedBlockTip ## How Has This Been Tested? ## Breaking Changes ## Checklist: - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have made corresponding changes to the documentation **For repository code-owners and collaborators only** - [ ] I have assigned this pull request to a milestone --- src/llmq/quorums.cpp | 45 +++++++++++++++----------------------------- src/llmq/quorums.h | 14 ++++++++++---- 2 files changed, 25 insertions(+), 34 deletions(-) diff --git a/src/llmq/quorums.cpp b/src/llmq/quorums.cpp index 522e60d0a1d9..b3a8998258b7 100644 --- a/src/llmq/quorums.cpp +++ b/src/llmq/quorums.cpp @@ -468,21 +468,22 @@ bool CQuorumManager::RequestQuorumData(CNode* pfrom, Consensus::LLMQType llmqTyp } LOCK(cs_data_requests); - CQuorumDataRequestKey key; - key.proRegTx = pfrom->GetVerifiedProRegTxHash(); - key.flag = true; - key.quorumHash = pQuorumBaseBlockIndex->GetBlockHash(); - key.llmqType = llmqType; - auto it = mapQuorumDataRequests.emplace(key, CQuorumDataRequest(llmqType, pQuorumBaseBlockIndex->GetBlockHash(), nDataMask, proTxHash)); - if (!it.second && !it.first->second.IsExpired(/*add_bias=*/true)) { - LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- Already requested\n", __func__); - return false; + const CQuorumDataRequestKey key(pfrom->GetVerifiedProRegTxHash(), true, pQuorumBaseBlockIndex->GetBlockHash(), llmqType); + const CQuorumDataRequest request(llmqType, pQuorumBaseBlockIndex->GetBlockHash(), nDataMask, proTxHash); + auto [old_pair, exists] = mapQuorumDataRequests.emplace(key, request); + if (!exists) { + if (old_pair->second.IsExpired(/*add_bias=*/true)) { + old_pair->second = request; + } else { + LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- Already requested\n", __func__); + return false; + } } LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- sending QGETDATA quorumHash[%s] llmqType[%d] proRegTx[%s]\n", __func__, key.quorumHash.ToString(), ToUnderlying(key.llmqType), key.proRegTx.ToString()); CNetMsgMaker msgMaker(pfrom->GetSendVersion()); - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::QGETDATA, it.first->second)); + connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::QGETDATA, request)); return true; } @@ -656,11 +657,7 @@ void CQuorumManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, C bool request_limit_exceeded(false); { LOCK2(cs_main, cs_data_requests); - CQuorumDataRequestKey key; - key.proRegTx = pfrom.GetVerifiedProRegTxHash(); - key.flag = false; - key.quorumHash = request.GetQuorumHash(); - key.llmqType = request.GetLLMQType(); + const CQuorumDataRequestKey key(pfrom.GetVerifiedProRegTxHash(), false, request.GetQuorumHash(), request.GetLLMQType()); auto it = mapQuorumDataRequests.find(key); if (it == mapQuorumDataRequests.end()) { it = mapQuorumDataRequests.emplace(key, request).first; @@ -733,11 +730,7 @@ void CQuorumManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, C { LOCK2(cs_main, cs_data_requests); - CQuorumDataRequestKey key; - key.proRegTx = pfrom.GetVerifiedProRegTxHash(); - key.flag = true; - key.quorumHash = request.GetQuorumHash(); - key.llmqType = request.GetLLMQType(); + const CQuorumDataRequestKey key(pfrom.GetVerifiedProRegTxHash(), true, request.GetQuorumHash(), request.GetLLMQType()); auto it = mapQuorumDataRequests.find(key); if (it == mapQuorumDataRequests.end()) { errorHandler("Not requested"); @@ -913,11 +906,7 @@ void CQuorumManager::StartQuorumDataRecoveryThread(const CQuorumCPtr pQuorum, co pCurrentMemberHash = &vecMemberHashes[(nMyStartOffset + nTries++) % vecMemberHashes.size()]; { LOCK(cs_data_requests); - CQuorumDataRequestKey key; - key.proRegTx = *pCurrentMemberHash; - key.flag = true; - key.quorumHash = pQuorum->qc->quorumHash; - key.llmqType = pQuorum->qc->llmqType; + const CQuorumDataRequestKey key(*pCurrentMemberHash, true, pQuorum->qc->quorumHash, pQuorum->qc->llmqType); auto it = mapQuorumDataRequests.find(key); if (it != mapQuorumDataRequests.end() && !it->second.IsExpired(/*add_bias=*/true)) { printLog("Already asked"); @@ -943,11 +932,7 @@ void CQuorumManager::StartQuorumDataRecoveryThread(const CQuorumCPtr pQuorum, co printLog("Requested"); } else { LOCK(cs_data_requests); - CQuorumDataRequestKey key; - key.proRegTx = *pCurrentMemberHash; - key.flag = true; - key.quorumHash = pQuorum->qc->quorumHash; - key.llmqType = pQuorum->qc->llmqType; + const CQuorumDataRequestKey key(*pCurrentMemberHash, true, pQuorum->qc->quorumHash, pQuorum->qc->llmqType); auto it = mapQuorumDataRequests.find(key); if (it == mapQuorumDataRequests.end()) { printLog("Failed"); diff --git a/src/llmq/quorums.h b/src/llmq/quorums.h index 6e24d369d1fd..c254393322a9 100644 --- a/src/llmq/quorums.h +++ b/src/llmq/quorums.h @@ -39,14 +39,20 @@ static constexpr bool DEFAULT_WATCH_QUORUMS{false}; struct CQuorumDataRequestKey { uint256 proRegTx; - //TODO: Investigate purpose of this flag and rename accordingly - bool flag; + bool m_we_requested; uint256 quorumHash; Consensus::LLMQType llmqType; + CQuorumDataRequestKey(const uint256& proRegTxIn, const bool _m_we_requested, const uint256& quorumHashIn, const Consensus::LLMQType llmqTypeIn) : + proRegTx(proRegTxIn), + m_we_requested(_m_we_requested), + quorumHash(quorumHashIn), + llmqType(llmqTypeIn) + {} + bool operator ==(const CQuorumDataRequestKey& obj) const { - return (proRegTx == obj.proRegTx && flag == obj.flag && quorumHash == obj.quorumHash && llmqType == obj.llmqType); + return (proRegTx == obj.proRegTx && m_we_requested == obj.m_we_requested && quorumHash == obj.quorumHash && llmqType == obj.llmqType); } }; @@ -275,7 +281,7 @@ struct SaltedHasherImpl { CSipHasher c(k0, k1); c.Write((unsigned char*)&(v.proRegTx), sizeof(v.proRegTx)); - c.Write((unsigned char*)&(v.flag), sizeof(v.flag)); + c.Write((unsigned char*)&(v.m_we_requested), sizeof(v.m_we_requested)); c.Write((unsigned char*)&(v.quorumHash), sizeof(v.quorumHash)); c.Write((unsigned char*)&(v.llmqType), sizeof(v.llmqType)); return c.Finalize(); From 15a9783e52ec379be10439706cc2e8184b583745 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Tue, 4 Apr 2023 19:11:59 +0300 Subject: [PATCH 22/35] trivial(doc): fix typos in getrawtransaction and decoderawtransaction help texts (#5290) ## Issue being fixed or feature implemented fix typos in getrawtransaction and decoderawtransaction help texts ## What was done? tweak field name to match https://github.com/dashpay/dash/blob/develop/src/core_write.cpp#L192 ## How Has This Been Tested? ## Breaking Changes n/a ## Checklist: - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have made corresponding changes to the documentation **For repository code-owners and collaborators only** - [x] I have assigned this pull request to a milestone --- src/rpc/rawtransaction.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 9f90b07b0d47..ff318b9344a8 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -143,7 +143,7 @@ static UniValue getrawtransaction(const JSONRPCRequest& request) {RPCResult::Type::STR_HEX, "txid", "The transaction id (same as provided)"}, {RPCResult::Type::NUM, "size", "The serialized transaction size"}, {RPCResult::Type::NUM, "version", "The version"}, - {RPCResult::Type::NUM, "version", "The type"}, + {RPCResult::Type::NUM, "type", "The type"}, {RPCResult::Type::NUM_TIME, "locktime", "The lock time"}, {RPCResult::Type::ARR, "vin", "", { @@ -494,7 +494,7 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request) {RPCResult::Type::STR_HEX, "txid", "The transaction id"}, {RPCResult::Type::NUM, "size", "The transaction size"}, {RPCResult::Type::NUM, "version", "The version"}, - {RPCResult::Type::NUM, "version", "The type"}, + {RPCResult::Type::NUM, "type", "The type"}, {RPCResult::Type::NUM_TIME, "locktime", "The lock time"}, {RPCResult::Type::ARR, "vin", "", { From ce3e8072a74ab468e6ac988fff3f997ff9462c3c Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Mon, 2 Sep 2019 15:36:57 +0800 Subject: [PATCH 23/35] merge #13868: Remove unused fScriptChecks parameter from CheckInputs --- src/test/txvalidationcache_tests.cpp | 16 +-- src/validation.cpp | 169 +++++++++++++-------------- 2 files changed, 89 insertions(+), 96 deletions(-) diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index 85db73787b90..3c0747066319 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -12,7 +12,7 @@ #include -bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector *pvChecks); +bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector *pvChecks); BOOST_AUTO_TEST_SUITE(txvalidationcache_tests) @@ -118,7 +118,7 @@ static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t fail // script/interpreter.cpp test_flags |= SCRIPT_VERIFY_P2SH; } - bool ret = CheckInputs(tx, state, &::ChainstateActive().CoinsTip(), true, test_flags, true, add_to_cache, txdata, nullptr); + bool ret = CheckInputs(tx, state, &::ChainstateActive().CoinsTip(), test_flags, true, add_to_cache, txdata, nullptr); // CheckInputs should succeed iff test_flags doesn't intersect with // failing_flags bool expected_return_value = !(test_flags & failing_flags); @@ -128,13 +128,13 @@ static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t fail if (ret && add_to_cache) { // Check that we get a cache hit if the tx was valid std::vector scriptchecks; - BOOST_CHECK(CheckInputs(tx, state, &::ChainstateActive().CoinsTip(), true, test_flags, true, add_to_cache, txdata, &scriptchecks)); + BOOST_CHECK(CheckInputs(tx, state, &::ChainstateActive().CoinsTip(), test_flags, true, add_to_cache, txdata, &scriptchecks)); BOOST_CHECK(scriptchecks.empty()); } else { // Check that we get script executions to check, if the transaction // was invalid, or we didn't add to cache. std::vector scriptchecks; - BOOST_CHECK(CheckInputs(tx, state, &::ChainstateActive().CoinsTip(), true, test_flags, true, add_to_cache, txdata, &scriptchecks)); + BOOST_CHECK(CheckInputs(tx, state, &::ChainstateActive().CoinsTip(), test_flags, true, add_to_cache, txdata, &scriptchecks)); BOOST_CHECK_EQUAL(scriptchecks.size(), tx.vin.size()); } } @@ -196,13 +196,13 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) CValidationState state; PrecomputedTransactionData ptd_spend_tx; - BOOST_CHECK(!CheckInputs(CTransaction(spend_tx), state, &::ChainstateActive().CoinsTip(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr)); + BOOST_CHECK(!CheckInputs(CTransaction(spend_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr)); // If we call again asking for scriptchecks (as happens in // ConnectBlock), we should add a script check object for this -- we're // not caching invalidity (if that changes, delete this test case). std::vector scriptchecks; - BOOST_CHECK(CheckInputs(CTransaction(spend_tx), state, &::ChainstateActive().CoinsTip(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, &scriptchecks)); + BOOST_CHECK(CheckInputs(CTransaction(spend_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, &scriptchecks)); BOOST_CHECK_EQUAL(scriptchecks.size(), 1U); // Test that CheckInputs returns true iff DERSIG-enforcing flags are @@ -264,7 +264,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100; CValidationState state; PrecomputedTransactionData txdata; - BOOST_CHECK(CheckInputs(CTransaction(invalid_with_cltv_tx), state, &::ChainstateActive().CoinsTip(), true, SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr)); + BOOST_CHECK(CheckInputs(CTransaction(invalid_with_cltv_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr)); } // TEST CHECKSEQUENCEVERIFY @@ -292,7 +292,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100; CValidationState state; PrecomputedTransactionData txdata; - BOOST_CHECK(CheckInputs(CTransaction(invalid_with_csv_tx), state, &::ChainstateActive().CoinsTip(), true, SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr)); + BOOST_CHECK(CheckInputs(CTransaction(invalid_with_csv_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr)); } // TODO: add tests for remaining script flags diff --git a/src/validation.cpp b/src/validation.cpp index 1d4fe13252fe..fc4405d72647 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -201,7 +201,7 @@ std::unique_ptr pblocktree; // See definition for documentation static void FindFilesToPruneManual(ChainstateManager& chainman, std::set& setFilesToPrune, int nManualPruneHeight); static void FindFilesToPrune(ChainstateManager& chainman, std::set& setFilesToPrune, uint64_t nPruneAfterHeight); -bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector *pvChecks = nullptr); +bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector *pvChecks = nullptr); static FILE* OpenUndoFile(const FlatFilePos &pos, bool fReadOnly = false); static FlatFileSeq BlockFileSeq(); static FlatFileSeq UndoFileSeq(); @@ -503,7 +503,7 @@ static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, CValidationSt } // Call CheckInputs() to cache signature and script validity against current tip consensus rules. - return CheckInputs(tx, state, view, true, flags, /* cacheSigStore = */ true, /* cacheFullSciptStore = */ true, txdata); + return CheckInputs(tx, state, view, flags, /* cacheSigStore = */ true, /* cacheFullSciptStore = */ true, txdata); } /** @@ -731,7 +731,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. PrecomputedTransactionData txdata; - if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true, false, txdata)) { + if (!CheckInputs(tx, state, view, scriptVerifyFlags, true, false, txdata)) { assert(IsTransactionReason(state.GetReason())); return false; // state filled in by CheckInputs } @@ -1415,100 +1415,88 @@ void InitScriptExecutionCache() { * * Non-static (and re-declared) in src/test/txvalidationcache_tests.cpp */ -bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector *pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector *pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { boost::posix_time::ptime start = boost::posix_time::microsec_clock::local_time(); - if (!tx.IsCoinBase()) - { - if (pvChecks) - pvChecks->reserve(tx.vin.size()); - - // The first loop above does all the inexpensive checks. - // Only if ALL inputs pass do we perform expensive ECDSA signature checks. - // Helps prevent CPU exhaustion attacks. - - // Skip script verification when connecting blocks under the - // assumevalid block. Assuming the assumevalid block is valid this - // is safe because block merkle hashes are still computed and checked, - // Of course, if an assumed valid block is invalid due to false scriptSigs - // this optimization would allow an invalid chain to be accepted. - if (fScriptChecks) { - // First check if script executions have been cached with the same - // flags. Note that this assumes that the inputs provided are - // correct (ie that the transaction hash which is in tx's prevouts - // properly commits to the scriptPubKey in the inputs view of that - // transaction). - uint256 hashCacheEntry; - CSHA256 hasher = g_scriptExecutionCacheHasher; - hasher.Write(tx.GetHash().begin(), 32).Write((unsigned char*)&flags, sizeof(flags)).Finalize(hashCacheEntry.begin()); - AssertLockHeld(cs_main); //TODO: Remove this requirement by making CuckooCache not require external locks - if (g_scriptExecutionCache.contains(hashCacheEntry, !cacheFullScriptStore)) { - return true; - } - - if (!txdata.m_ready) { - txdata.Init(tx, {}); - } - - for (unsigned int i = 0; i < tx.vin.size(); i++) { - const COutPoint &prevout = tx.vin[i].prevout; - const Coin& coin = inputs.AccessCoin(prevout); - assert(!coin.IsSpent()); - - // We very carefully only pass in things to CScriptCheck which - // are clearly committed to by tx' witness hash. This provides - // a sanity check that our caching is not introducing consensus - // failures through additional data in, eg, the coins being - // spent being checked as a part of CScriptCheck. - - // Verify signature - CScriptCheck check(coin.out, tx, i, flags, cacheSigStore, &txdata); - if (pvChecks) { - pvChecks->push_back(CScriptCheck()); - check.swap(pvChecks->back()); - } else if (!check()) { - const bool hasNonMandatoryFlags = (flags & STANDARD_NOT_MANDATORY_VERIFY_FLAGS) != 0; - const bool hasDIP0020Opcodes = (flags & SCRIPT_ENABLE_DIP0020_OPCODES) != 0; - - if (hasNonMandatoryFlags || !hasDIP0020Opcodes) { - // Check whether the failure was caused by a - // non-mandatory script verification check, such as - // non-standard DER encodings or non-null dummy - // arguments; if so, ensure we return NOT_STANDARD - // instead of CONSENSUS to avoid downstream users - // splitting the network between upgraded and - // non-upgraded nodes by banning CONSENSUS-failing - // data providers. - CScriptCheck check2(coin.out, tx, i, - (flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS) | SCRIPT_ENABLE_DIP0020_OPCODES, cacheSigStore, &txdata); - if (check2()) - return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError()))); - } - // MANDATORY flag failures correspond to - // ValidationInvalidReason::CONSENSUS. Because CONSENSUS - // failures are the most serious case of validation - // failures, we may need to consider using - // RECENT_CONSENSUS_CHANGE for any script failure that - // could be due to non-upgraded nodes which we may want to - // support, to avoid splitting the network (but this - // depends on the details of how net_processing handles - // such errors). - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError()))); - } - } + if (tx.IsCoinBase()) return true; + + if (pvChecks) { + pvChecks->reserve(tx.vin.size()); + } + + // First check if script executions have been cached with the same + // flags. Note that this assumes that the inputs provided are + // correct (ie that the transaction hash which is in tx's prevouts + // properly commits to the scriptPubKey in the inputs view of that + // transaction). + uint256 hashCacheEntry; + CSHA256 hasher = g_scriptExecutionCacheHasher; + hasher.Write(tx.GetHash().begin(), 32).Write((unsigned char*)&flags, sizeof(flags)).Finalize(hashCacheEntry.begin()); + AssertLockHeld(cs_main); //TODO: Remove this requirement by making CuckooCache not require external locks + if (g_scriptExecutionCache.contains(hashCacheEntry, !cacheFullScriptStore)) { + return true; + } - if (cacheFullScriptStore && !pvChecks) { - // We executed all of the provided scripts, and were told to - // cache the result. Do so now. - g_scriptExecutionCache.insert(hashCacheEntry); + if (!txdata.m_ready) { + txdata.Init(tx, {}); + } + + for (unsigned int i = 0; i < tx.vin.size(); i++) { + const COutPoint &prevout = tx.vin[i].prevout; + const Coin& coin = inputs.AccessCoin(prevout); + assert(!coin.IsSpent()); + + // We very carefully only pass in things to CScriptCheck which + // are clearly committed to by tx' witness hash. This provides + // a sanity check that our caching is not introducing consensus + // failures through additional data in, eg, the coins being + // spent being checked as a part of CScriptCheck. + + // Verify signature + CScriptCheck check(coin.out, tx, i, flags, cacheSigStore, &txdata); + if (pvChecks) { + pvChecks->push_back(CScriptCheck()); + check.swap(pvChecks->back()); + } else if (!check()) { + const bool hasNonMandatoryFlags = (flags & STANDARD_NOT_MANDATORY_VERIFY_FLAGS) != 0; + const bool hasDIP0020Opcodes = (flags & SCRIPT_ENABLE_DIP0020_OPCODES) != 0; + + if (hasNonMandatoryFlags || !hasDIP0020Opcodes) { + // Check whether the failure was caused by a + // non-mandatory script verification check, such as + // non-standard DER encodings or non-null dummy + // arguments; if so, ensure we return NOT_STANDARD + // instead of CONSENSUS to avoid downstream users + // splitting the network between upgraded and + // non-upgraded nodes by banning CONSENSUS-failing + // data providers. + CScriptCheck check2(coin.out, tx, i, + (flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS) | SCRIPT_ENABLE_DIP0020_OPCODES, cacheSigStore, &txdata); + if (check2()) + return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError()))); } + // MANDATORY flag failures correspond to + // ValidationInvalidReason::CONSENSUS. Because CONSENSUS + // failures are the most serious case of validation + // failures, we may need to consider using + // RECENT_CONSENSUS_CHANGE for any script failure that + // could be due to non-upgraded nodes which we may want to + // support, to avoid splitting the network (but this + // depends on the details of how net_processing handles + // such errors). + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError()))); } } + if (cacheFullScriptStore && !pvChecks) { + // We executed all of the provided scripts, and were told to + // cache the result. Do so now. + g_scriptExecutionCache.insert(hashCacheEntry); + } + boost::posix_time::ptime finish = boost::posix_time::microsec_clock::local_time(); boost::posix_time::time_duration diff = finish - start; statsClient.timing("CheckInputs_ms", diff.total_milliseconds(), 1.0f); - return true; } @@ -2055,6 +2043,11 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl pindexBestHeader->GetAncestor(pindex->nHeight) == pindex && pindexBestHeader->nChainWork >= nMinimumChainWork) { // This block is a member of the assumed verified chain and an ancestor of the best header. + // Script verification is skipped when connecting blocks under the + // assumevalid block. Assuming the assumevalid block is valid this + // is safe because block merkle hashes are still computed and checked, + // Of course, if an assumed valid block is invalid due to false scriptSigs + // this optimization would allow an invalid chain to be accepted. // The equivalent time check discourages hash power from extorting the network via DOS attack // into accepting an invalid block through telling users they must manually set assumevalid. // Requiring a software change or burying the invalid block, regardless of the setting, makes @@ -2252,7 +2245,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl std::vector vChecks; bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */ - if (fScriptChecks && !CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, fCacheResults, txsdata[i], g_parallel_script_checks ? &vChecks : nullptr)) { + if (fScriptChecks && !CheckInputs(tx, state, view, flags, fCacheResults, fCacheResults, txsdata[i], g_parallel_script_checks ? &vChecks : nullptr)) { if (state.GetReason() == ValidationInvalidReason::TX_NOT_STANDARD) { // CheckInputs may return NOT_STANDARD for extra flags we passed, // but we can't return that, as it's not defined for a block, so From bd00a6a2e829e9f46da3768abce122f4849ba69d Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Thu, 16 Mar 2023 08:48:17 +0000 Subject: [PATCH 24/35] merge #16400: refactor: Rewrite AcceptToMemoryPoolWorker() using smaller parts --- src/validation.cpp | 541 +++++++++++++++++++++++++++++---------------- 1 file changed, 345 insertions(+), 196 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index fc4405d72647..54470bf5e2bf 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -506,22 +506,124 @@ static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, CValidationSt return CheckInputs(tx, state, view, flags, /* cacheSigStore = */ true, /* cacheFullSciptStore = */ true, txdata); } -/** - * @param[out] coins_to_uncache Return any outpoints which were not previously present in the - * coins cache, but were added as a result of validating the tx - * for mempool acceptance. This allows the caller to optionally - * remove the cache additions if the associated transaction ends - * up being rejected by the mempool. - */ -static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool& pool, CValidationState& state, const CTransactionRef& ptx, - bool* pfMissingInputs, int64_t nAcceptTime, bool bypass_limits, - const CAmount& nAbsurdFee, std::vector& coins_to_uncache, bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +namespace { + +class MemPoolAccept { - boost::posix_time::ptime start = boost::posix_time::microsec_clock::local_time(); - const CTransaction& tx = *ptx; - const uint256 hash = tx.GetHash(); - AssertLockHeld(cs_main); - LOCK(pool.cs); // mempool "read lock" (held through GetMainSignals().TransactionAddedToMempool()) +public: + MemPoolAccept(CTxMemPool& mempool) : m_pool(mempool), m_view(&m_dummy), m_viewmempool(&::ChainstateActive().CoinsTip(), m_pool), + m_limit_ancestors(gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT)), + m_limit_ancestor_size(gArgs.GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000), + m_limit_descendants(gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT)), + m_limit_descendant_size(gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT)*1000) {} + + // We put the arguments we're handed into a struct, so we can pass them + // around easier. + struct ATMPArgs { + const CChainParams& m_chainparams; + CValidationState &m_state; + bool* m_missing_inputs; + const int64_t m_accept_time; + const bool m_bypass_limits; + const CAmount& m_absurd_fee; + /* + * Return any outpoints which were not previously present in the coins + * cache, but were added as a result of validating the tx for mempool + * acceptance. This allows the caller to optionally remove the cache + * additions if the associated transaction ends up being rejected by + * the mempool. + */ + std::vector& m_coins_to_uncache; + const bool m_test_accept; + }; + + // Single transaction acceptance + bool AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs& args) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + +private: + // All the intermediate state that gets passed between the various levels + // of checking a given transaction. + struct Workspace { + Workspace(const CTransactionRef& ptx) : m_ptx(ptx), m_hash(ptx->GetHash()) {} + CTxMemPool::setEntries m_ancestors; + std::unique_ptr m_entry; + + CAmount m_modified_fees; + + const CTransactionRef& m_ptx; + const uint256& m_hash; + }; + + // Run the policy checks on a given transaction, excluding any script checks. + // Looks up inputs, calculates feerate, considers replacement, evaluates + // package limits, etc. As this function can be invoked for "free" by a peer, + // only tests that are fast should be done here (to avoid CPU DoS). + bool PreChecks(ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs); + + // Run the script checks using our policy flags. As this can be slow, we should + // only invoke this on transactions that have otherwise passed policy checks. + bool PolicyScriptChecks(ATMPArgs& args, Workspace& ws, PrecomputedTransactionData& txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + + // Re-run the script checks, using consensus flags, and try to cache the + // result in the scriptcache. This should be done after + // PolicyScriptChecks(). This requires that all inputs either be in our + // utxo set or in the mempool. + bool ConsensusScriptChecks(ATMPArgs& args, Workspace& ws, PrecomputedTransactionData &txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + + // Try to add the transaction to the mempool, removing any conflicts first. + // Returns true if the transaction is in the mempool after any size + // limiting is performed, false otherwise. + bool Finalize(ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs); + + // Compare a package's feerate against minimum allowed. + bool CheckFeeRate(size_t package_size, CAmount package_fee, CValidationState& state) + { + CAmount mempoolRejectFee = m_pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(package_size); + if (mempoolRejectFee > 0 && package_fee < mempoolRejectFee) { + return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", strprintf("%d < %d", package_fee, mempoolRejectFee)); + } + + if (package_fee < ::minRelayTxFee.GetFee(package_size)) { + return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "min relay fee not met", strprintf("%d < %d", package_fee, ::minRelayTxFee.GetFee(package_size))); + } + return true; + } + +private: + CTxMemPool& m_pool; + CCoinsViewCache m_view; + CCoinsViewMemPool m_viewmempool; + CCoinsView m_dummy; + + // The package limits in effect at the time of invocation. + const size_t m_limit_ancestors; + const size_t m_limit_ancestor_size; + // These may be modified while evaluating a transaction (eg to account for + // in-mempool conflicts; see below). + size_t m_limit_descendants; + size_t m_limit_descendant_size; +}; + +bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) +{ + const CTransactionRef& ptx = ws.m_ptx; + const CTransaction& tx = *ws.m_ptx; + const uint256& hash = ws.m_hash; + + // Copy/alias what we need out of args + const CChainParams& chainparams = args.m_chainparams; + CValidationState &state = args.m_state; + bool* pfMissingInputs = args.m_missing_inputs; + const int64_t nAcceptTime = args.m_accept_time; + const bool bypass_limits = args.m_bypass_limits; + const CAmount& nAbsurdFee = args.m_absurd_fee; + std::vector& coins_to_uncache = args.m_coins_to_uncache; + + // Alias what we need out of ws + CTxMemPool::setEntries& setAncestors = ws.m_ancestors; + std::unique_ptr& entry = ws.m_entry; + CAmount& nModifiedFees = ws.m_modified_fees; + if (pfMissingInputs) { *pfMissingInputs = false; } @@ -560,7 +662,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, REJECT_NONSTANDARD, "non-final"); // is it already in the memory pool? - if (pool.exists(hash)) { + if (m_pool.exists(hash)) { statsClient.inc("transactions.duplicate", 1.0f); return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, REJECT_DUPLICATE, "txn-already-in-mempool"); } @@ -568,7 +670,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool llmq::CInstantSendLockPtr conflictLock = llmq::quorumInstantSendManager->GetConflictingLock(tx); if (conflictLock) { uint256 hashBlock; - CTransactionRef txConflict = GetTransaction(/* block_index */ nullptr, &pool, conflictLock->txid, chainparams.GetConsensus(), hashBlock); + CTransactionRef txConflict = GetTransaction(/* block_index */ nullptr, &m_pool, conflictLock->txid, chainparams.GetConsensus(), hashBlock); if (txConflict) { GetMainSignals().NotifyInstantSendDoubleSpendAttempt(ptx, txConflict); } @@ -576,13 +678,13 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool } if (llmq::quorumInstantSendManager->IsWaitingForTx(hash)) { - pool.removeConflicts(tx); - pool.removeProTxConflicts(tx); + m_pool.removeConflicts(tx); + m_pool.removeProTxConflicts(tx); } else { // Check for conflicts with in-memory transactions for (const CTxIn &txin : tx.vin) { - const CTransaction* ptxConflicting = pool.GetConflictTx(txin.prevout); + const CTransaction* ptxConflicting = m_pool.GetConflictTx(txin.prevout); if (ptxConflicting) { // Transaction conflicts with mempool and RBF doesn't exist in Dash @@ -591,212 +693,255 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool } } - { - CCoinsView dummy; - CCoinsViewCache view(&dummy); - - LockPoints lp; - CCoinsViewCache& coins_cache = ::ChainstateActive().CoinsTip(); - CCoinsViewMemPool viewMemPool(&coins_cache, pool); - view.SetBackend(viewMemPool); - - // do all inputs exist? - for (const CTxIn& txin : tx.vin) { - if (!coins_cache.HaveCoinInCache(txin.prevout)) { - coins_to_uncache.push_back(txin.prevout); - } + LockPoints lp; + m_view.SetBackend(m_viewmempool); - // Note: this call may add txin.prevout to the coins cache - // (pcoinsTip.cacheCoins) by way of FetchCoin(). It should be removed - // later (via coins_to_uncache) if this tx turns out to be invalid. - if (!view.HaveCoin(txin.prevout)) { - // Are inputs missing because we already have the tx? - for (size_t out = 0; out < tx.vout.size(); out++) { - // Optimistically just do efficient check of cache for outputs - if (coins_cache.HaveCoinInCache(COutPoint(hash, out))) { - return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, REJECT_DUPLICATE, "txn-already-known"); - } - } - // Otherwise assume this might be an orphan tx for which we just haven't seen parents yet - if (pfMissingInputs) { - *pfMissingInputs = true; + CCoinsViewCache& coins_cache = ::ChainstateActive().CoinsTip(); + // do all inputs exist? + for (const CTxIn& txin : tx.vin) { + if (!coins_cache.HaveCoinInCache(txin.prevout)) { + coins_to_uncache.push_back(txin.prevout); + } + + // Note: this call may add txin.prevout to the coins cache + // (coins_cache.cacheCoins) by way of FetchCoin(). It should be removed + // later (via coins_to_uncache) if this tx turns out to be invalid. + if (!m_view.HaveCoin(txin.prevout)) { + // Are inputs missing because we already have the tx? + for (size_t out = 0; out < tx.vout.size(); out++) { + // Optimistically just do efficient check of cache for outputs + if (coins_cache.HaveCoinInCache(COutPoint(hash, out))) { + return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, REJECT_DUPLICATE, "txn-already-known"); } - return false; // fMissingInputs and !state.IsInvalid() is used to detect this condition, don't set state.Invalid() } + // Otherwise assume this might be an orphan tx for which we just haven't seen parents yet + if (pfMissingInputs) { + *pfMissingInputs = true; + } + return false; // fMissingInputs and !state.IsInvalid() is used to detect this condition, don't set state.Invalid() } + } - // Bring the best block into scope - view.GetBestBlock(); + // Bring the best block into scope + m_view.GetBestBlock(); - // we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool - view.SetBackend(dummy); + // we have all inputs cached now, so switch back to dummy (to protect + // against bugs where we pull more inputs from disk that miss being added + // to coins_to_uncache) + m_view.SetBackend(m_dummy); - // Only accept BIP68 sequence locked transactions that can be mined in the next - // block; we don't want our mempool filled up with transactions that can't - // be mined yet. - // Must keep pool.cs for this unless we change CheckSequenceLocks to take a - // CoinsViewCache instead of create its own - if (!CheckSequenceLocks(pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp)) - return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, REJECT_NONSTANDARD, "non-BIP68-final"); + // Only accept BIP68 sequence locked transactions that can be mined in the next + // block; we don't want our mempool filled up with transactions that can't + // be mined yet. + // Must keep pool.cs for this unless we change CheckSequenceLocks to take a + // CoinsViewCache instead of create its own + if (!CheckSequenceLocks(m_pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp)) + return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, REJECT_NONSTANDARD, "non-BIP68-final"); - CAmount nFees = 0; - if (!Consensus::CheckTxInputs(tx, state, view, GetSpendHeight(view), nFees)) { - return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), FormatStateMessage(state)); - } + CAmount nFees = 0; + if (!Consensus::CheckTxInputs(tx, state, m_view, GetSpendHeight(m_view), nFees)) { + return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), FormatStateMessage(state)); + } - // Check for non-standard pay-to-script-hash in inputs - if (fRequireStandard && !AreInputsStandard(tx, view)) - return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, "bad-txns-nonstandard-inputs"); + // Check for non-standard pay-to-script-hash in inputs + if (fRequireStandard && !AreInputsStandard(tx, m_view)) + return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, "bad-txns-nonstandard-inputs"); - unsigned int nSigOps = GetTransactionSigOpCount(tx, view, STANDARD_SCRIPT_VERIFY_FLAGS); + unsigned int nSigOps = GetTransactionSigOpCount(tx, m_view, STANDARD_SCRIPT_VERIFY_FLAGS); - // nModifiedFees includes any fee deltas from PrioritiseTransaction - CAmount nModifiedFees = nFees; - pool.ApplyDelta(hash, nModifiedFees); + // nModifiedFees includes any fee deltas from PrioritiseTransaction + nModifiedFees = nFees; + m_pool.ApplyDelta(hash, nModifiedFees); - // Keep track of transactions that spend a coinbase, which we re-scan - // during reorgs to ensure COINBASE_MATURITY is still met. - bool fSpendsCoinbase = false; - for (const CTxIn &txin : tx.vin) { - const Coin &coin = view.AccessCoin(txin.prevout); - if (coin.IsCoinBase()) { - fSpendsCoinbase = true; - break; - } + // Keep track of transactions that spend a coinbase, which we re-scan + // during reorgs to ensure COINBASE_MATURITY is still met. + bool fSpendsCoinbase = false; + for (const CTxIn &txin : tx.vin) { + const Coin &coin = m_view.AccessCoin(txin.prevout); + if (coin.IsCoinBase()) { + fSpendsCoinbase = true; + break; } + } - CTxMemPoolEntry entry(ptx, nFees, nAcceptTime, ::ChainActive().Height(), - fSpendsCoinbase, nSigOps, lp); - unsigned int nSize = entry.GetTxSize(); + entry.reset(new CTxMemPoolEntry(ptx, nFees, nAcceptTime, ::ChainActive().Height(), + fSpendsCoinbase, nSigOps, lp)); + unsigned int nSize = entry->GetTxSize(); - if (nSigOps > MAX_STANDARD_TX_SIGOPS) - return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", + if (nSigOps > MAX_STANDARD_TX_SIGOPS) + return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", strprintf("%d", nSigOps)); - CAmount mempoolRejectFee = pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize); - if (!bypass_limits && mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) { - return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", strprintf("%d < %d", nModifiedFees, mempoolRejectFee)); - } - - // No transactions are allowed below minRelayTxFee except from disconnected blocks - if (!bypass_limits && nModifiedFees < ::minRelayTxFee.GetFee(nSize)) { - return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "min relay fee not met", strprintf("%d < %d", nModifiedFees, ::minRelayTxFee.GetFee(nSize))); - } + // No transactions are allowed below minRelayTxFee except from disconnected + // blocks + if (!bypass_limits && !CheckFeeRate(nSize, nModifiedFees, state)) return false; - if (nAbsurdFee && nFees > nAbsurdFee) - return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, + if (nAbsurdFee && nFees > nAbsurdFee) + return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_HIGHFEE, "absurdly-high-fee", strprintf("%d > %d", nFees, nAbsurdFee)); - // Calculate in-mempool ancestors, up to a limit. - CTxMemPool::setEntries setAncestors; - size_t nLimitAncestors = gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT); - size_t nLimitAncestorSize = gArgs.GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000; - size_t nLimitDescendants = gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT); - size_t nLimitDescendantSize = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT)*1000; - std::string errString; - if (!pool.CalculateMemPoolAncestors(entry, setAncestors, nLimitAncestors, nLimitAncestorSize, nLimitDescendants, nLimitDescendantSize, errString)) { - setAncestors.clear(); - // If CalculateMemPoolAncestors fails second time, we want the original error string. - std::string dummy_err_string; - // If the new transaction is relatively small (up to 40k weight) - // and has at most one ancestor (ie ancestor limit of 2, including - // the new transaction), allow it if its parent has exactly the - // descendant limit descendants. - // - // This allows protocols which rely on distrusting counterparties - // being able to broadcast descendants of an unconfirmed transaction - // to be secure by simply only having two immediately-spendable - // outputs - one for each counterparty. For more info on the uses for - // this, see https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-November/016518.html - if (nSize > EXTRA_DESCENDANT_TX_SIZE_LIMIT || - !pool.CalculateMemPoolAncestors(entry, setAncestors, 2, nLimitAncestorSize, nLimitDescendants + 1, nLimitDescendantSize + EXTRA_DESCENDANT_TX_SIZE_LIMIT, dummy_err_string)) { - return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_NONSTANDARD, "too-long-mempool-chain", errString); - } - } + // Calculate in-mempool ancestors, up to a limit. + std::string errString; + if (!m_pool.CalculateMemPoolAncestors(*entry, setAncestors, m_limit_ancestors, m_limit_ancestor_size, m_limit_descendants, m_limit_descendant_size, errString)) { + setAncestors.clear(); + // If CalculateMemPoolAncestors fails second time, we want the original error string. + std::string dummy_err_string; + // If the new transaction is relatively small (up to 40k weight) + // and has at most one ancestor (ie ancestor limit of 2, including + // the new transaction), allow it if its parent has exactly the + // descendant limit descendants. + // + // This allows protocols which rely on distrusting counterparties + // being able to broadcast descendants of an unconfirmed transaction + // to be secure by simply only having two immediately-spendable + // outputs - one for each counterparty. For more info on the uses for + // this, see https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-November/016518.html + if (nSize > EXTRA_DESCENDANT_TX_SIZE_LIMIT || + !m_pool.CalculateMemPoolAncestors(*entry, setAncestors, 2, m_limit_ancestor_size, m_limit_descendants + 1, m_limit_descendant_size + EXTRA_DESCENDANT_TX_SIZE_LIMIT, dummy_err_string)) { + return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_NONSTANDARD, "too-long-mempool-chain", errString); + } + } + + // check special TXs after all the other checks. If we'd do this before the other checks, we might end up + // DoS scoring a node for non-critical errors, e.g. duplicate keys because a TX is received that was already + // mined + // NOTE: we use UTXO here and do NOT allow mempool txes as masternode collaterals + if (!CheckSpecialTx(tx, ::ChainActive().Tip(), state, ::ChainstateActive().CoinsTip(), true)) + return false; - // check special TXs after all the other checks. If we'd do this before the other checks, we might end up - // DoS scoring a node for non-critical errors, e.g. duplicate keys because a TX is received that was already - // mined - // NOTE: we use UTXO here and do NOT allow mempool txes as masternode collaterals - if (!CheckSpecialTx(tx, ::ChainActive().Tip(), state, ::ChainstateActive().CoinsTip(), true)) - return false; + if (m_pool.existsProviderTxConflict(tx)) { + return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, REJECT_DUPLICATE, "protx-dup"); + } - if (pool.existsProviderTxConflict(tx)) { - return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, REJECT_DUPLICATE, "protx-dup"); - } + return true; +} - constexpr unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS; +bool MemPoolAccept::PolicyScriptChecks(ATMPArgs& args, Workspace& ws, PrecomputedTransactionData& txdata) +{ + const CTransaction& tx = *ws.m_ptx; - // Check against previous transactions - // This is done last to help prevent CPU exhaustion denial-of-service attacks. - PrecomputedTransactionData txdata; - if (!CheckInputs(tx, state, view, scriptVerifyFlags, true, false, txdata)) { - assert(IsTransactionReason(state.GetReason())); - return false; // state filled in by CheckInputs - } + CValidationState &state = args.m_state; - // Check again against the current block tip's script verification - // flags to cache our script execution flags. This is, of course, - // useless if the next block has different script flags from the - // previous one, but because the cache tracks script flags for us it - // will auto-invalidate and we'll just have a few blocks of extra - // misses on soft-fork activation. - // - // This is also useful in case of bugs in the standard flags that cause - // transactions to pass as valid when they're actually invalid. For - // instance the STRICTENC flag was incorrectly allowing certain - // CHECKSIG NOT scripts to pass, even though they were invalid. - // - // 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(::ChainActive().Tip(), chainparams.GetConsensus()); - if (!CheckInputsFromMempoolAndCache(tx, state, view, pool, currentBlockScriptVerifyFlags, txdata)) { - return error("%s: BUG! PLEASE REPORT THIS! CheckInputs failed against latest-block but not STANDARD flags %s, %s", - __func__, hash.ToString(), FormatStateMessage(state)); - } + constexpr unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS; - if (test_accept) { - // Tx was accepted, but not added - return true; - } + // Check against previous transactions + // This is done last to help prevent CPU exhaustion denial-of-service attacks. + if (!CheckInputs(tx, state, m_view, scriptVerifyFlags, true, false, txdata)) { + assert(IsTransactionReason(state.GetReason())); + return false; // state filled in by CheckInputs + } - // This transaction should only count for fee estimation if: - // - it's not being re-added during a reorg which bypasses typical mempool fee limits - // - the node is not behind - // - the transaction is not dependent on any other transactions in the mempool - // - the transaction is not a zero fee transaction - bool validForFeeEstimation = (nFees !=0) && !bypass_limits && IsCurrentForFeeEstimation() && pool.HasNoInputsOf(tx); + return true; +} - // Store transaction in memory - pool.addUnchecked(entry, setAncestors, validForFeeEstimation); - CAmount nValueOut = tx.GetValueOut(); - statsClient.count("transactions.sizeBytes", nSize, 1.0f); - statsClient.count("transactions.fees", nFees, 1.0f); - statsClient.count("transactions.inputValue", nValueOut - nFees, 1.0f); - statsClient.count("transactions.outputValue", nValueOut, 1.0f); - statsClient.count("transactions.sigOps", nSigOps, 1.0f); +bool MemPoolAccept::ConsensusScriptChecks(ATMPArgs& args, Workspace& ws, PrecomputedTransactionData& txdata) +{ + const CTransaction& tx = *ws.m_ptx; + const uint256& hash = ws.m_hash; - // Add memory address index - if (fAddressIndex) { - pool.addAddressIndex(entry, view); - } + CValidationState &state = args.m_state; + const CChainParams& chainparams = args.m_chainparams; - // Add memory spent index - if (fSpentIndex) { - pool.addSpentIndex(entry, view); - } + // Check again against the current block tip's script verification + // flags to cache our script execution flags. This is, of course, + // useless if the next block has different script flags from the + // previous one, but because the cache tracks script flags for us it + // will auto-invalidate and we'll just have a few blocks of extra + // misses on soft-fork activation. + // + // This is also useful in case of bugs in the standard flags that cause + // transactions to pass as valid when they're actually invalid. For + // instance the STRICTENC flag was incorrectly allowing certain + // CHECKSIG NOT scripts to pass, even though they were invalid. + // + // 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(::ChainActive().Tip(), chainparams.GetConsensus()); + if (!CheckInputsFromMempoolAndCache(tx, state, m_view, m_pool, currentBlockScriptVerifyFlags, txdata)) { + return error("%s: BUG! PLEASE REPORT THIS! CheckInputs failed against latest-block but not STANDARD flags %s, %s", + __func__, hash.ToString(), FormatStateMessage(state)); + } - if (!bypass_limits) { - LimitMempoolSize(pool, gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, std::chrono::hours{gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)}); - if (!pool.exists(hash)) - return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "mempool full"); - } + return true; +} +bool MemPoolAccept::Finalize(ATMPArgs& args, Workspace& ws) +{ + const CTransaction& tx = *ws.m_ptx; + const uint256& hash = ws.m_hash; + CValidationState &state = args.m_state; + const bool bypass_limits = args.m_bypass_limits; + + CTxMemPool::setEntries& setAncestors = ws.m_ancestors; + const CAmount& nModifiedFees = ws.m_modified_fees; + std::unique_ptr& entry = ws.m_entry; + + // This transaction should only count for fee estimation if: + // - it's not being re-added during a reorg which bypasses typical mempool fee limits + // - the node is not behind + // - the transaction is not dependent on any other transactions in the mempool + // - the transaction is not a zero fee transaction + bool validForFeeEstimation = (nModifiedFees != 0) && !bypass_limits && IsCurrentForFeeEstimation() && m_pool.HasNoInputsOf(tx); + + // Store transaction in memory + m_pool.addUnchecked(*entry, setAncestors, validForFeeEstimation); + CAmount nValueOut = tx.GetValueOut(); + unsigned int nSigOps = GetTransactionSigOpCount(tx, m_view, STANDARD_SCRIPT_VERIFY_FLAGS); + + statsClient.count("transactions.sizeBytes", entry->GetTxSize(), 1.0f); + statsClient.count("transactions.fees", nModifiedFees, 1.0f); + statsClient.count("transactions.inputValue", nValueOut - nModifiedFees, 1.0f); + statsClient.count("transactions.outputValue", nValueOut, 1.0f); + statsClient.count("transactions.sigOps", nSigOps, 1.0f); + + // Add memory address index + if (fAddressIndex) { + m_pool.addAddressIndex(*entry, m_view); + } + + // Add memory spent index + if (fSpentIndex) { + m_pool.addSpentIndex(*entry, m_view); } + if (!bypass_limits) { + LimitMempoolSize(m_pool, gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, std::chrono::hours{gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)}); + if (!m_pool.exists(hash)) + return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "mempool full"); + } + return true; +} + +bool MemPoolAccept::AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs& args) +{ + boost::posix_time::ptime start = boost::posix_time::microsec_clock::local_time(); + AssertLockHeld(cs_main); + LOCK(m_pool.cs); // mempool "read lock" (held through GetMainSignals().TransactionAddedToMempool()) + + Workspace workspace(ptx); + + if (!PreChecks(args, workspace)) return false; + + // Only compute the precomputed transaction data if we need to verify + // scripts (ie, other policy checks pass). We perform the inexpensive + // checks first and avoid hashing and signature verification unless those + // checks pass, to mitigate CPU exhaustion denial-of-service attacks. + PrecomputedTransactionData txdata(*ptx); + + if (!PolicyScriptChecks(args, workspace, txdata)) return false; + + if (!ConsensusScriptChecks(args, workspace, txdata)) return false; + + // Tx was accepted, but not added + if (args.m_test_accept) return true; + + if (!Finalize(args, workspace)) return false; + + const int64_t nAcceptTime = args.m_accept_time; GetMainSignals().TransactionAddedToMempool(ptx, nAcceptTime); + const CTransaction& tx = *ptx; boost::posix_time::ptime finish = boost::posix_time::microsec_clock::local_time(); boost::posix_time::time_duration diff = finish - start; statsClient.timing("AcceptToMemoryPool_ms", diff.total_milliseconds(), 1.0f); @@ -807,19 +952,23 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool return true; } +} // anon namespace + /** (try to) add transaction to memory pool with a specified acceptance time **/ static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, bool* pfMissingInputs, int64_t nAcceptTime, bool bypass_limits, const CAmount nAbsurdFee, bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { std::vector coins_to_uncache; - bool res = AcceptToMemoryPoolWorker(chainparams, pool, state, tx, pfMissingInputs, nAcceptTime, bypass_limits, nAbsurdFee, coins_to_uncache, test_accept); + MemPoolAccept::ATMPArgs args { chainparams, state, pfMissingInputs, nAcceptTime, bypass_limits, nAbsurdFee, coins_to_uncache, test_accept }; + bool res = MemPoolAccept(pool).AcceptSingleTransaction(tx, args); if (!res || test_accept) { - if(!res) LogPrint(BCLog::MEMPOOL, "%s: %s %s (%s)\n", __func__, tx->GetHash().ToString(), state.GetRejectReason(), state.GetDebugMessage()); - // Remove coins that were not present in the coins cache before calling ATMPW; - // this is to prevent memory DoS in case we receive a large number of - // invalid transactions that attempt to overrun the in-memory coins cache - // (`CCoinsViewCache::cacheCoins`). + if (!res) LogPrint(BCLog::MEMPOOL, "%s: %s %s (%s)\n", __func__, tx->GetHash().ToString(), state.GetRejectReason(), state.GetDebugMessage()); + + // Remove coins that were not present in the coins cache before calling ATMPW; + // this is to prevent memory DoS in case we receive a large number of + // invalid transactions that attempt to overrun the in-memory coins cache + // (`CCoinsViewCache::cacheCoins`). for (const COutPoint& hashTx : coins_to_uncache) ::ChainstateActive().CoinsTip().Uncache(hashTx); From bce9b6bc97538972fa8643ce5fb384e664f16912 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kittywhiskers@users.noreply.github.com> Date: Mon, 7 Sep 2020 07:58:42 +0200 Subject: [PATCH 25/35] merge bitcoin#19905: Remove dead CheckForkWarningConditionsOnNewFork --- src/validation.cpp | 94 ++++++---------------------------------------- src/warnings.cpp | 18 +-------- src/warnings.h | 2 - 3 files changed, 13 insertions(+), 101 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index 54470bf5e2bf..cdf6ef08714f 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1340,8 +1340,6 @@ bool CChainState::IsInitialBlockDownload() const return false; } -static CBlockIndex *pindexBestForkTip = nullptr, *pindexBestForkBase = nullptr; - static void AlertNotify(const std::string& strMessage) { uiInterface.NotifyAlertChanged(); @@ -1367,80 +1365,16 @@ static void CheckForkWarningConditions() EXCLUSIVE_LOCKS_REQUIRED(cs_main) AssertLockHeld(cs_main); // Before we get past initial download, we cannot reliably alert about forks // (we assume we don't get stuck on a fork before finishing our initial sync) - if (::ChainstateActive().IsInitialBlockDownload()) + if (::ChainstateActive().IsInitialBlockDownload()) { return; - - // If our best fork is no longer within 72 blocks (+/- 3 hours if no one mines it) - // of our head, drop it - if (pindexBestForkTip && ::ChainActive().Height() - pindexBestForkTip->nHeight >= 72) - pindexBestForkTip = nullptr; - - if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > ::ChainActive().Tip()->nChainWork + (GetBlockProof(*::ChainActive().Tip()) * 6))) - { - if (!GetfLargeWorkForkFound() && pindexBestForkBase) - { - if(pindexBestForkBase->phashBlock){ - std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") + - pindexBestForkBase->phashBlock->ToString() + std::string("'"); - AlertNotify(warning); - } - } - if (pindexBestForkTip && pindexBestForkBase) - { - if(pindexBestForkBase->phashBlock){ - LogPrintf("%s: Warning: Large valid fork found\n forking the chain at height %d (%s)\n lasting to height %d (%s).\nChain state database corruption likely.\n", __func__, - pindexBestForkBase->nHeight, pindexBestForkBase->phashBlock->ToString(), - pindexBestForkTip->nHeight, pindexBestForkTip->phashBlock->ToString()); - SetfLargeWorkForkFound(true); - } - } - else - { - if(pindexBestInvalid->nHeight > ::ChainActive().Height() + 6) - LogPrintf("%s: Warning: Found invalid chain at least ~6 blocks longer than our best chain.\nChain state database corruption likely.\n", __func__); - else - LogPrintf("%s: Warning: Found invalid chain which has higher work (at least ~6 blocks worth of work) than our best chain.\nChain state database corruption likely.\n", __func__); - SetfLargeWorkInvalidChainFound(true); - } } - else - { - SetfLargeWorkForkFound(false); - SetfLargeWorkInvalidChainFound(false); - } -} -static void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) EXCLUSIVE_LOCKS_REQUIRED(cs_main) -{ - AssertLockHeld(cs_main); - // If we are on a fork that is sufficiently large, set a warning flag - CBlockIndex* pfork = pindexNewForkTip; - CBlockIndex* plonger = ::ChainActive().Tip(); - while (pfork && pfork != plonger) - { - while (plonger && plonger->nHeight > pfork->nHeight) - plonger = plonger->pprev; - if (pfork == plonger) - break; - pfork = pfork->pprev; - } - - // We define a condition where we should warn the user about as a fork of at least 7 blocks - // with a tip within 72 blocks (+/- 3 hours if no one mines it) of ours - // or a chain that is entirely longer than ours and invalid (note that this should be detected by both) - // We use 7 blocks rather arbitrarily as it represents just under 10% of sustained network - // hash rate operating on the fork. - // We define it this way because it allows us to only store the highest fork tip (+ base) which meets - // the 7-block condition and from this always have the most-likely-to-cause-warning fork - if (pfork && (!pindexBestForkTip || pindexNewForkTip->nHeight > pindexBestForkTip->nHeight) && - pindexNewForkTip->nChainWork - pfork->nChainWork > (GetBlockProof(*pfork) * 7) && - ::ChainActive().Height() - pindexNewForkTip->nHeight < 72) - { - pindexBestForkTip = pindexNewForkTip; - pindexBestForkBase = pfork; + if (pindexBestInvalid && pindexBestInvalid->nChainWork > ::ChainActive().Tip()->nChainWork + (GetBlockProof(*::ChainActive().Tip()) * 6)) { + LogPrintf("%s: Warning: Found invalid chain which has higher work (at least ~6 blocks worth of work) than our best chain.\nChain state database corruption likely.\n", __func__); + SetfLargeWorkInvalidChainFound(true); + } else { + SetfLargeWorkInvalidChainFound(false); } - - CheckForkWarningConditions(); } // Called both upon regular invalid block discovery *and* InvalidateBlock @@ -3094,8 +3028,8 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar AssertLockHeld(cs_main); AssertLockHeld(m_mempool.cs); - const CBlockIndex *pindexOldTip = m_chain.Tip(); - const CBlockIndex *pindexFork = m_chain.FindFork(pindexMostWork); + const CBlockIndex* pindexOldTip = m_chain.Tip(); + const CBlockIndex* pindexFork = m_chain.FindFork(pindexMostWork); // Disconnect active blocks which are no longer in the best chain. bool fBlocksDisconnected = false; @@ -3115,7 +3049,7 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar fBlocksDisconnected = true; } - // Build list of new blocks to connect. + // Build list of new blocks to connect (in descending height order). std::vector vpindexToConnect; bool fContinue = true; int nHeight = pindexFork ? pindexFork->nHeight : -1; @@ -3125,7 +3059,7 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar int nTargetHeight = std::min(nHeight + 32, pindexMostWork->nHeight); vpindexToConnect.clear(); vpindexToConnect.reserve(nTargetHeight - nHeight); - CBlockIndex *pindexIter = pindexMostWork->GetAncestor(nTargetHeight); + CBlockIndex* pindexIter = pindexMostWork->GetAncestor(nTargetHeight); while (pindexIter && pindexIter->nHeight != nHeight) { vpindexToConnect.push_back(pindexIter); pindexIter = pindexIter->pprev; @@ -3133,7 +3067,7 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar nHeight = nTargetHeight; // Connect new blocks. - for (CBlockIndex *pindexConnect : reverse_iterate(vpindexToConnect)) { + for (CBlockIndex* pindexConnect : reverse_iterate(vpindexToConnect)) { if (!ConnectTip(state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : std::shared_ptr(), connectTrace, disconnectpool)) { if (state.IsInvalid()) { // The block violates a consensus rule. @@ -3169,11 +3103,7 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar } m_mempool.check(&CoinsTip()); - // Callbacks/notifications for a new best chain. - if (fInvalidFound) - CheckForkWarningConditionsOnNewFork(vpindexToConnect.back()); - else - CheckForkWarningConditions(); + CheckForkWarningConditions(); return true; } diff --git a/src/warnings.cpp b/src/warnings.cpp index f50a997b2c8d..db0fcf0f1b0d 100644 --- a/src/warnings.cpp +++ b/src/warnings.cpp @@ -12,7 +12,6 @@ static Mutex g_warnings_mutex; static std::string strMiscWarning GUARDED_BY(g_warnings_mutex); -static bool fLargeWorkForkFound GUARDED_BY(g_warnings_mutex) = false; static bool fLargeWorkInvalidChainFound GUARDED_BY(g_warnings_mutex) = false; void SetMiscWarning(const std::string& strWarning) @@ -21,18 +20,6 @@ void SetMiscWarning(const std::string& strWarning) strMiscWarning = strWarning; } -void SetfLargeWorkForkFound(bool flag) -{ - LOCK(g_warnings_mutex); - fLargeWorkForkFound = flag; -} - -bool GetfLargeWorkForkFound() -{ - LOCK(g_warnings_mutex); - return fLargeWorkForkFound; -} - void SetfLargeWorkInvalidChainFound(bool flag) { LOCK(g_warnings_mutex); @@ -59,10 +46,7 @@ std::string GetWarnings(bool verbose) warnings_verbose += (warnings_verbose.empty() ? "" : warning_separator) + strMiscWarning; } - if (fLargeWorkForkFound) { - warnings_concise = "Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues."; - warnings_verbose += (warnings_verbose.empty() ? "" : warning_separator) + _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.").translated; - } else if (fLargeWorkInvalidChainFound) { + if (fLargeWorkInvalidChainFound) { warnings_concise = "Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade."; warnings_verbose += (warnings_verbose.empty() ? "" : warning_separator) + _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.").translated; } diff --git a/src/warnings.h b/src/warnings.h index 4bf7af53685d..b7906f877be1 100644 --- a/src/warnings.h +++ b/src/warnings.h @@ -9,8 +9,6 @@ #include void SetMiscWarning(const std::string& strWarning); -void SetfLargeWorkForkFound(bool flag); -bool GetfLargeWorkForkFound(); void SetfLargeWorkInvalidChainFound(bool flag); /** Format a string that describes several potential problems detected by the core. * @param[in] verbose bool From 0d7516e2c2991177f004f9a98896e30923933fb2 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kittywhiskers@users.noreply.github.com> Date: Tue, 8 Sep 2020 14:36:31 -0400 Subject: [PATCH 26/35] merge bitcoin#19927: Reduce direct g_chainman usage --- src/init.cpp | 2 +- src/qt/test/apptests.cpp | 7 ++- src/test/util/setup_common.cpp | 2 +- src/validation.cpp | 86 +++++++++++--------------------- src/validation.h | 38 ++++++++++++-- src/wallet/test/wallet_tests.cpp | 6 +-- 6 files changed, 72 insertions(+), 69 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 1a9dce565461..cb2614a2b835 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2015,7 +2015,7 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc chainman.m_total_coinstip_cache = nCoinCacheUsage; chainman.m_total_coinsdb_cache = nCoinDBCache; - UnloadBlockIndex(node.mempool.get()); + UnloadBlockIndex(node.mempool.get(), chainman); // new CBlockTreeDB tries to delete the existing file, which // fails if it's still open from the previous loop. Close it first: diff --git a/src/qt/test/apptests.cpp b/src/qt/test/apptests.cpp index 4486464cb89d..d4c4f3874974 100644 --- a/src/qt/test/apptests.cpp +++ b/src/qt/test/apptests.cpp @@ -87,8 +87,11 @@ void AppTests::appTests() // Reset global state to avoid interfering with later tests. LogInstance().DisconnectTestLogger(); AbortShutdown(); - UnloadBlockIndex(/* mempool */ nullptr); - WITH_LOCK(::cs_main, g_chainman.Reset()); + { + LOCK(cs_main); + UnloadBlockIndex(/* mempool */ nullptr, g_chainman); + g_chainman.Reset(); + } } //! Entry point for BitcoinGUI tests. diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 8cad26fec4be..010dc93e85b4 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -216,7 +216,7 @@ ChainTestingSetup::~ChainTestingSetup() m_node.addrman.reset(); m_node.args = nullptr; m_node.banman.reset(); - UnloadBlockIndex(m_node.mempool.get()); + UnloadBlockIndex(m_node.mempool.get(), *m_node.chainman); m_node.mempool.reset(); m_node.scheduler.reset(); m_node.llmq_ctx.reset(); diff --git a/src/validation.cpp b/src/validation.cpp index cdf6ef08714f..6fb2215cf61c 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -198,9 +198,6 @@ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& loc std::unique_ptr pblocktree; -// See definition for documentation -static void FindFilesToPruneManual(ChainstateManager& chainman, std::set& setFilesToPrune, int nManualPruneHeight); -static void FindFilesToPrune(ChainstateManager& chainman, std::set& setFilesToPrune, uint64_t nPruneAfterHeight); bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector *pvChecks = nullptr); static FILE* OpenUndoFile(const FlatFilePos &pos, bool fReadOnly = false); static FlatFileSeq BlockFileSeq(); @@ -2566,11 +2563,11 @@ bool CChainState::FlushStateToDisk( if (nManualPruneHeight > 0) { LOG_TIME_MILLIS_WITH_CATEGORY("find files to prune (manual)", BCLog::BENCHMARK); - FindFilesToPruneManual(g_chainman, setFilesToPrune, nManualPruneHeight); + m_blockman.FindFilesToPruneManual(setFilesToPrune, nManualPruneHeight, m_chain.Height()); } else { LOG_TIME_MILLIS_WITH_CATEGORY("find files to prune", BCLog::BENCHMARK); - FindFilesToPrune(g_chainman, setFilesToPrune, chainparams.PruneAfterHeight()); + m_blockman.FindFilesToPrune(setFilesToPrune, chainparams.PruneAfterHeight(), m_chain.Height(), IsInitialBlockDownload()); fCheckForPruning = false; } if (!setFilesToPrune.empty()) { @@ -4328,12 +4325,12 @@ uint64_t CalculateCurrentUsage() return retval; } -void ChainstateManager::PruneOneBlockFile(const int fileNumber) +void BlockManager::PruneOneBlockFile(const int fileNumber) { AssertLockHeld(cs_main); LOCK(cs_LastBlockFile); - for (const auto& entry : m_blockman.m_block_index) { + for (const auto& entry : m_block_index) { CBlockIndex* pindex = entry.second; if (pindex->nFile == fileNumber) { pindex->nStatus &= ~BLOCK_HAVE_DATA; @@ -4347,12 +4344,12 @@ void ChainstateManager::PruneOneBlockFile(const int fileNumber) // to be downloaded again in order to consider its chain, at which // point it would be considered as a candidate for // m_blocks_unlinked or setBlockIndexCandidates. - auto range = m_blockman.m_blocks_unlinked.equal_range(pindex->pprev); + auto range = m_blocks_unlinked.equal_range(pindex->pprev); while (range.first != range.second) { std::multimap::iterator _it = range.first; range.first++; if (_it->second == pindex) { - m_blockman.m_blocks_unlinked.erase(_it); + m_blocks_unlinked.erase(_it); } } } @@ -4373,22 +4370,23 @@ void UnlinkPrunedFiles(const std::set& setFilesToPrune) } } -/* Calculate the block/rev files to delete based on height specified by user with RPC command pruneblockchain */ -static void FindFilesToPruneManual(ChainstateManager& chainman, std::set& setFilesToPrune, int nManualPruneHeight) +void BlockManager::FindFilesToPruneManual(std::set& setFilesToPrune, int nManualPruneHeight, int chain_tip_height) { assert(fPruneMode && nManualPruneHeight > 0); LOCK2(cs_main, cs_LastBlockFile); - if (::ChainActive().Tip() == nullptr) + if (chain_tip_height < 0) { return; + } // last block to prune is the lesser of (user-specified height, MIN_BLOCKS_TO_KEEP from the tip) - unsigned int nLastBlockWeCanPrune = std::min((unsigned)nManualPruneHeight, ::ChainActive().Tip()->nHeight - MIN_BLOCKS_TO_KEEP); - int count=0; + unsigned int nLastBlockWeCanPrune = std::min((unsigned)nManualPruneHeight, chain_tip_height - MIN_BLOCKS_TO_KEEP); + int count = 0; for (int fileNumber = 0; fileNumber < nLastBlockFile; fileNumber++) { - if (vinfoBlockFile[fileNumber].nSize == 0 || vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune) + if (vinfoBlockFile[fileNumber].nSize == 0 || vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune) { continue; - chainman.PruneOneBlockFile(fileNumber); + } + PruneOneBlockFile(fileNumber); setFilesToPrune.insert(fileNumber); count++; } @@ -4406,46 +4404,31 @@ void PruneBlockFilesManual(int nManualPruneHeight) } } -/** - * Prune block and undo files (blk???.dat and undo???.dat) so that the disk space used is less than a user-defined target. - * The user sets the target (in MB) on the command line or in config file. This will be run on startup and whenever new - * space is allocated in a block or undo file, staying below the target. Changing back to unpruned requires a reindex - * (which in this case means the blockchain must be re-downloaded.) - * - * Pruning functions are called from FlushStateToDisk when the global fCheckForPruning flag has been set. - * Block and undo files are deleted in lock-step (when blk00003.dat is deleted, so is rev00003.dat.) - * Pruning cannot take place until the longest chain is at least a certain length (100000 on mainnet, 1000 on testnet, 1000 on regtest). - * Pruning will never delete a block within a defined distance (currently 288) from the active chain's tip. - * The block index is updated by unsetting HAVE_DATA and HAVE_UNDO for any blocks that were stored in the deleted files. - * A db flag records the fact that at least some block files have been pruned. - * - * @param[out] setFilesToPrune The set of file indices that can be unlinked will be returned - */ -static void FindFilesToPrune(ChainstateManager& chainman, std::set& setFilesToPrune, uint64_t nPruneAfterHeight) +void BlockManager::FindFilesToPrune(std::set& setFilesToPrune, uint64_t nPruneAfterHeight, int chain_tip_height, bool is_ibd) { LOCK2(cs_main, cs_LastBlockFile); - if (::ChainActive().Tip() == nullptr || nPruneTarget == 0) { + if (chain_tip_height < 0 || nPruneTarget == 0) { return; } - if ((uint64_t)::ChainActive().Tip()->nHeight <= nPruneAfterHeight) { + if ((uint64_t)chain_tip_height <= nPruneAfterHeight) { return; } - unsigned int nLastBlockWeCanPrune = ::ChainActive().Tip()->nHeight - MIN_BLOCKS_TO_KEEP; + unsigned int nLastBlockWeCanPrune = chain_tip_height - MIN_BLOCKS_TO_KEEP; uint64_t nCurrentUsage = CalculateCurrentUsage(); // We don't check to prune until after we've allocated new space for files // So we should leave a buffer under our target to account for another allocation // before the next pruning. uint64_t nBuffer = BLOCKFILE_CHUNK_SIZE + UNDOFILE_CHUNK_SIZE; uint64_t nBytesToPrune; - int count=0; + int count = 0; if (nCurrentUsage + nBuffer >= nPruneTarget) { // On a prune event, the chainstate DB is flushed. // To avoid excessive prune events negating the benefit of high dbcache // values, we should not prune too rapidly. // So when pruning in IBD, increase the buffer a bit to avoid a re-prune too soon. - if (::ChainstateActive().IsInitialBlockDownload()) { + if (is_ibd) { // Since this is only relevant during IBD, we use a fixed 10% nBuffer += nPruneTarget / 10; } @@ -4453,17 +4436,20 @@ static void FindFilesToPrune(ChainstateManager& chainman, std::set& setFile for (int fileNumber = 0; fileNumber < nLastBlockFile; fileNumber++) { nBytesToPrune = vinfoBlockFile[fileNumber].nSize + vinfoBlockFile[fileNumber].nUndoSize; - if (vinfoBlockFile[fileNumber].nSize == 0) + if (vinfoBlockFile[fileNumber].nSize == 0) { continue; + } - if (nCurrentUsage + nBuffer < nPruneTarget) // are we below our target? + if (nCurrentUsage + nBuffer < nPruneTarget) { // are we below our target? break; + } // don't prune files that could have a block within MIN_BLOCKS_TO_KEEP of the main chain's tip but keep scanning - if (vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune) + if (vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune) { continue; + } - chainman.PruneOneBlockFile(fileNumber); + PruneOneBlockFile(fileNumber); // Queue up the files for removal setFilesToPrune.insert(fileNumber); nCurrentUsage -= nBytesToPrune; @@ -4921,10 +4907,10 @@ void CChainState::UnloadBlockIndex() { // May NOT be used after any connections are up as much // of the peer-processing logic assumes a consistent // block index state -void UnloadBlockIndex(CTxMemPool* mempool) +void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman) { LOCK(cs_main); - g_chainman.Unload(); + chainman.Unload(); pindexBestInvalid = nullptr; pindexBestHeader = nullptr; if (mempool) mempool->clear(); @@ -5578,20 +5564,6 @@ double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex *pin return std::min(pindex->nChainTx / fTxTotal, 1.0); } -class CMainCleanup -{ -public: - CMainCleanup() {} - ~CMainCleanup() { - // block headers - BlockMap::iterator it1 = g_chainman.BlockIndex().begin(); - for (; it1 != g_chainman.BlockIndex().end(); it1++) - delete (*it1).second; - g_chainman.BlockIndex().clear(); - } -}; -static CMainCleanup instance_of_cmaincleanup; - std::optional ChainstateManager::SnapshotBlockhash() const { if (m_active_chainstate != nullptr) { // If a snapshot chainstate exists, it will always be our active. diff --git a/src/validation.h b/src/validation.h index d79b6ad20fe5..532e22ed1b81 100644 --- a/src/validation.h +++ b/src/validation.h @@ -180,7 +180,7 @@ void LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFi /** Ensures we have a genesis block in the block tree, possibly writing one to disk. */ bool LoadGenesisBlock(const CChainParams& chainparams); /** Unload database information */ -void UnloadBlockIndex(CTxMemPool* mempool); +void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman); /** Run instances of script checking worker threads */ void StartScriptCheckWorkerThreads(int threads_num); /** Stop all of the script checking worker threads */ @@ -375,7 +375,31 @@ struct CBlockIndexWorkComparator * This data is used mostly in `CChainState` - information about, e.g., * candidate tips is not maintained here. */ -class BlockManager { +class BlockManager +{ + friend CChainState; + +private: + /* Calculate the block/rev files to delete based on height specified by user with RPC command pruneblockchain */ + void FindFilesToPruneManual(std::set& setFilesToPrune, int nManualPruneHeight, int chain_tip_height); + + /** + * Prune block and undo files (blk???.dat and undo???.dat) so that the disk space used is less than a user-defined target. + * The user sets the target (in MB) on the command line or in config file. This will be run on startup and whenever new + * space is allocated in a block or undo file, staying below the target. Changing back to unpruned requires a reindex + * (which in this case means the blockchain must be re-downloaded.) + * + * Pruning functions are called from FlushStateToDisk when the global fCheckForPruning flag has been set. + * Block and undo files are deleted in lock-step (when blk00003.dat is deleted, so is rev00003.dat.) + * Pruning cannot take place until the longest chain is at least a certain length (100000 on mainnet, 1000 on testnet, 1000 on regtest). + * Pruning will never delete a block within a defined distance (currently 288) from the active chain's tip. + * The block index is updated by unsetting HAVE_DATA and HAVE_UNDO for any blocks that were stored in the deleted files. + * A db flag records the fact that at least some block files have been pruned. + * + * @param[out] setFilesToPrune The set of file indices that can be unlinked will be returned + */ + void FindFilesToPrune(std::set& setFilesToPrune, uint64_t nPruneAfterHeight, int chain_tip_height, bool is_ibd); + public: BlockMap m_block_index GUARDED_BY(cs_main); PrevBlockMap m_prev_block_index GUARDED_BY(cs_main); @@ -426,6 +450,9 @@ class BlockManager { /** Create a new block index entry for a given block hash */ CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + //! Mark one block file as pruned (modify associated database entries) + void PruneOneBlockFile(const int fileNumber) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + /** * If a block header hasn't already been seen, call CheckBlockHeader on it, ensure * that it doesn't descend from an invalid block, and then add it to m_block_index. @@ -435,6 +462,10 @@ class BlockManager { CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + + ~BlockManager() { + Unload(); + } }; /** @@ -948,9 +979,6 @@ class ChainstateManager */ bool ProcessNewBlockHeaders(const std::vector& block, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex = nullptr, CBlockHeader* first_invalid = nullptr) LOCKS_EXCLUDED(cs_main); - //! Mark one block file as pruned (modify associated database entries) - void PruneOneBlockFile(const int fileNumber) EXCLUSIVE_LOCKS_REQUIRED(cs_main); - //! Load the block tree and coins database from disk, initializing state if we're running with -reindex bool LoadBlockIndex(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main); diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 6626347f0a1f..c1a94d383603 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -134,7 +134,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) // Prune the older block file. { LOCK(cs_main); - Assert(m_node.chainman)->PruneOneBlockFile(oldTip->GetBlockPos().nFile); + Assert(m_node.chainman)->m_blockman.PruneOneBlockFile(oldTip->GetBlockPos().nFile); } UnlinkPrunedFiles({oldTip->GetBlockPos().nFile}); @@ -160,7 +160,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) // Prune the remaining block file. { LOCK(cs_main); - Assert(m_node.chainman)->PruneOneBlockFile(newTip->GetBlockPos().nFile); + Assert(m_node.chainman)->m_blockman.PruneOneBlockFile(newTip->GetBlockPos().nFile); } UnlinkPrunedFiles({newTip->GetBlockPos().nFile}); @@ -199,7 +199,7 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup) // Prune the older block file. { LOCK(cs_main); - Assert(m_node.chainman)->PruneOneBlockFile(oldTip->GetBlockPos().nFile); + Assert(m_node.chainman)->m_blockman.PruneOneBlockFile(oldTip->GetBlockPos().nFile); } UnlinkPrunedFiles({oldTip->GetBlockPos().nFile}); From 6648e9f199726adbd6233313f1a2d46fe61bc1da Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kittywhiskers@users.noreply.github.com> Date: Wed, 27 Jan 2021 16:20:59 -0500 Subject: [PATCH 27/35] merge bitcoin#21025: Guard all chainstates with cs_main --- src/validation.cpp | 6 ++++++ src/validation.h | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index 6fb2215cf61c..4531f02be9a5 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -5565,6 +5565,7 @@ double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex *pin } std::optional ChainstateManager::SnapshotBlockhash() const { + LOCK(::cs_main); if (m_active_chainstate != nullptr) { // If a snapshot chainstate exists, it will always be our active. return m_active_chainstate->m_from_snapshot_blockhash; @@ -5574,6 +5575,7 @@ std::optional ChainstateManager::SnapshotBlockhash() const { std::vector ChainstateManager::GetAll() { + LOCK(::cs_main); std::vector out; if (!IsSnapshotValidated() && m_ibd_chainstate) { @@ -5623,11 +5625,13 @@ CChainState& ChainstateManager::ActiveChainstate() const bool ChainstateManager::IsSnapshotActive() const { + LOCK(::cs_main); return m_snapshot_chainstate && m_active_chainstate == m_snapshot_chainstate.get(); } CChainState& ChainstateManager::ValidatedChainstate() const { + LOCK(::cs_main); if (m_snapshot_chainstate && IsSnapshotValidated()) { return *m_snapshot_chainstate.get(); } @@ -5637,6 +5641,7 @@ CChainState& ChainstateManager::ValidatedChainstate() const bool ChainstateManager::IsBackgroundIBD(CChainState* chainstate) const { + LOCK(::cs_main); return (m_snapshot_chainstate && chainstate == m_ibd_chainstate.get()); } @@ -5652,6 +5657,7 @@ void ChainstateManager::Unload() void ChainstateManager::Reset() { + LOCK(::cs_main); m_ibd_chainstate.reset(); m_snapshot_chainstate.reset(); m_active_chainstate = nullptr; diff --git a/src/validation.h b/src/validation.h index 532e22ed1b81..292bb13fca79 100644 --- a/src/validation.h +++ b/src/validation.h @@ -841,7 +841,7 @@ class ChainstateManager //! This is especially important when, e.g., calling ActivateBestChain() //! on all chainstates because we are not able to hold ::cs_main going into //! that call. - std::unique_ptr m_ibd_chainstate; + std::unique_ptr m_ibd_chainstate GUARDED_BY(::cs_main); //! A chainstate initialized on the basis of a UTXO snapshot. If this is //! non-null, it is always our active chainstate. @@ -854,7 +854,7 @@ class ChainstateManager //! This is especially important when, e.g., calling ActivateBestChain() //! on all chainstates because we are not able to hold ::cs_main going into //! that call. - std::unique_ptr m_snapshot_chainstate; + std::unique_ptr m_snapshot_chainstate GUARDED_BY(::cs_main); //! Points to either the ibd or snapshot chainstate; indicates our //! most-work chain. From b0b80d0c9c0e8b5ecb9957e3e39ddc3a796e5af9 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kittywhiskers@users.noreply.github.com> Date: Mon, 13 Mar 2023 15:35:09 +0000 Subject: [PATCH 28/35] partial bitcoin#19775: Activate segwit in TestChain100Setup excludes: - fad84b7e14ff92465bc17bfdaf1362bcffe092f6 --- src/test/util/setup_common.cpp | 25 ++++++++++++++----------- src/test/util/setup_common.h | 13 +++++++------ 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 010dc93e85b4..baf4f17665d9 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -269,8 +269,7 @@ TestChainSetup::TestChainSetup(int blockCount) // Generate a 100-block chain: coinbaseKey.MakeNewKey(true); CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; - for (int i = 0; i < blockCount; i++) - { + for (int i = 0; i < blockCount; i++) { std::vector noTxns; CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey); m_coinbase_txns.push_back(b.vtx[0]); @@ -288,8 +287,6 @@ TestChainSetup::TestChainSetup(int blockCount) } } -// Create a new block with just given transactions, coinbase paying to -// scriptPubKey, and try to add it to the current chain. CBlock TestChainSetup::CreateAndProcessBlock(const std::vector& txns, const CScript& scriptPubKey) { const CChainParams& chainparams = Params(); @@ -298,8 +295,7 @@ CBlock TestChainSetup::CreateAndProcessBlock(const std::vector shared_pblock = std::make_shared(block); Assert(m_node.chainman)->ProcessNewBlock(chainparams, shared_pblock, true, nullptr); - CBlock result = block; - return result; + return block; } CBlock TestChainSetup::CreateAndProcessBlock(const std::vector& txns, const CKey& scriptKey) @@ -311,8 +307,12 @@ CBlock TestChainSetup::CreateAndProcessBlock(const std::vector& txns, const CScript& scriptPubKey) { const CChainParams& chainparams = Params(); - std::unique_ptr pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, *m_node.mempool, chainparams).CreateNewBlock(scriptPubKey); - CBlock& block = pblocktemplate->block; + CTxMemPool empty_pool; + CBlock block = BlockAssembler( + *sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, + *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, + empty_pool, chainparams + ).CreateNewBlock(scriptPubKey)->block; std::vector llmqCommitments; for (const auto& tx : block.vtx) { @@ -323,10 +323,13 @@ CBlock TestChainSetup::CreateBlock(const std::vector& txns, // Replace mempool-selected txns with just coinbase plus passed-in txns: block.vtx.resize(1); + Assert(block.vtx.size() == 1); + // Re-add quorum commitments block.vtx.insert(block.vtx.end(), llmqCommitments.begin(), llmqCommitments.end()); - for (const CMutableTransaction& tx : txns) + for (const CMutableTransaction& tx : txns) { block.vtx.push_back(MakeTransactionRef(tx)); + } // Manually update CbTx as we modified the block here if (block.vtx[0]->nType == TRANSACTION_COINBASE) { @@ -373,8 +376,8 @@ TestChainSetup::~TestChainSetup() g_txindex.reset(); } - -CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx) { +CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction& tx) +{ return FromTx(MakeTransactionRef(tx)); } diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h index a009dd857222..d69dd73dbd4d 100644 --- a/src/test/util/setup_common.h +++ b/src/test/util/setup_common.h @@ -115,8 +115,10 @@ struct TestChainSetup : public RegTestingSetup TestChainSetup(int blockCount); ~TestChainSetup(); - // Create a new block with just given transactions, coinbase paying to - // scriptPubKey, and try to add it to the current chain. + /** + * Create a new block with just given transactions, coinbase paying to + * scriptPubKey, and try to add it to the current chain. + */ CBlock CreateAndProcessBlock(const std::vector& txns, const CScript& scriptPubKey); CBlock CreateAndProcessBlock(const std::vector& txns, @@ -130,10 +132,9 @@ struct TestChainSetup : public RegTestingSetup CKey coinbaseKey; // private/public key needed to spend coinbase transactions }; -// -// Testing fixture that pre-creates a -// 100-block REGTEST-mode block chain -// +/** + * Testing fixture that pre-creates a 100-block REGTEST-mode block chain + */ struct TestChain100Setup : public TestChainSetup { TestChain100Setup() : TestChainSetup(100) {} }; From 431415a67918fde4c964ec63d0927b4d5981be8b Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kittywhiskers@users.noreply.github.com> Date: Thu, 16 Mar 2023 08:46:21 +0000 Subject: [PATCH 29/35] merge bitcoin#20828: Introduce CallOneOf helper to replace switch-case --- src/test/fuzz/addrman.cpp | 138 ++++---- src/test/fuzz/autofile.cpp | 68 ++-- src/test/fuzz/banman.cpp | 82 ++--- src/test/fuzz/bloom_filter.cpp | 78 ++-- src/test/fuzz/buffered_file.cpp | 65 ++-- src/test/fuzz/coins_view.cpp | 332 +++++++++--------- src/test/fuzz/connman.cpp | 165 +++++---- src/test/fuzz/crypto.cpp | 163 ++++----- src/test/fuzz/crypto_chacha20.cpp | 47 ++- .../fuzz/crypto_chacha20_poly1305_aead.cpp | 71 ++-- src/test/fuzz/merkleblock.cpp | 48 ++- src/test/fuzz/net.cpp | 173 +++++---- src/test/fuzz/policy_estimator.cpp | 68 ++-- src/test/fuzz/rolling_bloom_filter.cpp | 46 ++- src/test/fuzz/script_ops.cpp | 85 +++-- src/test/fuzz/scriptnum_ops.cpp | 192 +++++----- src/test/fuzz/strprintf.cpp | 121 +++---- src/test/fuzz/system.cpp | 118 +++---- src/test/fuzz/util.h | 164 ++++----- 19 files changed, 1054 insertions(+), 1170 deletions(-) diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp index 14f133e40f20..b12f421bc833 100644 --- a/src/test/fuzz/addrman.cpp +++ b/src/test/fuzz/addrman.cpp @@ -35,83 +35,71 @@ FUZZ_TARGET_INIT(addrman, initialize_addrman) } } while (fuzzed_data_provider.ConsumeBool()) { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 11)) { - case 0: { - addr_man.Clear(); - break; - } - case 1: { - addr_man.ResolveCollisions(); - break; - } - case 2: { - (void)addr_man.SelectTriedCollision(); - break; - } - case 3: { - (void)addr_man.Select(fuzzed_data_provider.ConsumeBool()); - break; - } - case 4: { - (void)addr_man.GetAddr(); - break; - } - case 5: { - const std::optional opt_address = ConsumeDeserializable(fuzzed_data_provider); - const std::optional opt_net_addr = ConsumeDeserializable(fuzzed_data_provider); - if (opt_address && opt_net_addr) { - addr_man.Add(*opt_address, *opt_net_addr, fuzzed_data_provider.ConsumeIntegralInRange(0, 100000000)); - } - break; - } - case 6: { - std::vector addresses; - while (fuzzed_data_provider.ConsumeBool()) { + CallOneOf( + fuzzed_data_provider, + [&] { + addr_man.Clear(); + }, + [&] { + addr_man.ResolveCollisions(); + }, + [&] { + (void)addr_man.SelectTriedCollision(); + }, + [&] { + (void)addr_man.Select(fuzzed_data_provider.ConsumeBool()); + }, + [&] { + (void)addr_man.GetAddr(); + }, + [&] { const std::optional opt_address = ConsumeDeserializable(fuzzed_data_provider); - if (!opt_address) { - break; + const std::optional opt_net_addr = ConsumeDeserializable(fuzzed_data_provider); + if (opt_address && opt_net_addr) { + addr_man.Add(*opt_address, *opt_net_addr, fuzzed_data_provider.ConsumeIntegralInRange(0, 100000000)); } - addresses.push_back(*opt_address); - } - const std::optional opt_net_addr = ConsumeDeserializable(fuzzed_data_provider); - if (opt_net_addr) { - addr_man.Add(addresses, *opt_net_addr, fuzzed_data_provider.ConsumeIntegralInRange(0, 100000000)); - } - break; - } - case 7: { - const std::optional opt_service = ConsumeDeserializable(fuzzed_data_provider); - if (opt_service) { - addr_man.Good(*opt_service, fuzzed_data_provider.ConsumeBool(), ConsumeTime(fuzzed_data_provider)); - } - break; - } - case 8: { - const std::optional opt_service = ConsumeDeserializable(fuzzed_data_provider); - if (opt_service) { - addr_man.Attempt(*opt_service, fuzzed_data_provider.ConsumeBool(), ConsumeTime(fuzzed_data_provider)); - } - break; - } - case 9: { - const std::optional opt_service = ConsumeDeserializable(fuzzed_data_provider); - if (opt_service) { - addr_man.Connected(*opt_service, ConsumeTime(fuzzed_data_provider)); - } - break; - } - case 10: { - const std::optional opt_service = ConsumeDeserializable(fuzzed_data_provider); - if (opt_service) { - addr_man.SetServices(*opt_service, ServiceFlags{fuzzed_data_provider.ConsumeIntegral()}); - } - break; - } - case 11: { - (void)addr_man.Check(); - break; - } - } + }, + [&] { + std::vector addresses; + while (fuzzed_data_provider.ConsumeBool()) { + const std::optional opt_address = ConsumeDeserializable(fuzzed_data_provider); + if (!opt_address) { + break; + } + addresses.push_back(*opt_address); + } + const std::optional opt_net_addr = ConsumeDeserializable(fuzzed_data_provider); + if (opt_net_addr) { + addr_man.Add(addresses, *opt_net_addr, fuzzed_data_provider.ConsumeIntegralInRange(0, 100000000)); + } + }, + [&] { + const std::optional opt_service = ConsumeDeserializable(fuzzed_data_provider); + if (opt_service) { + addr_man.Good(*opt_service, fuzzed_data_provider.ConsumeBool(), ConsumeTime(fuzzed_data_provider)); + } + }, + [&] { + const std::optional opt_service = ConsumeDeserializable(fuzzed_data_provider); + if (opt_service) { + addr_man.Attempt(*opt_service, fuzzed_data_provider.ConsumeBool(), ConsumeTime(fuzzed_data_provider)); + } + }, + [&] { + const std::optional opt_service = ConsumeDeserializable(fuzzed_data_provider); + if (opt_service) { + addr_man.Connected(*opt_service, ConsumeTime(fuzzed_data_provider)); + } + }, + [&] { + const std::optional opt_service = ConsumeDeserializable(fuzzed_data_provider); + if (opt_service) { + addr_man.SetServices(*opt_service, ServiceFlags{fuzzed_data_provider.ConsumeIntegral()}); + } + }, + [&] { + (void)addr_man.Check(); + }); } (void)addr_man.size(); CDataStream data_stream(SER_NETWORK, PROTOCOL_VERSION); diff --git a/src/test/fuzz/autofile.cpp b/src/test/fuzz/autofile.cpp index 95be582d6587..e3f1a8572a4c 100644 --- a/src/test/fuzz/autofile.cpp +++ b/src/test/fuzz/autofile.cpp @@ -20,43 +20,37 @@ FUZZ_TARGET(autofile) FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider); CAutoFile auto_file = fuzzed_auto_file_provider.open(); while (fuzzed_data_provider.ConsumeBool()) { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 5)) { - case 0: { - std::array arr{}; - try { - auto_file.read((char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange(0, 4096)); - } catch (const std::ios_base::failure&) { - } - break; - } - case 1: { - const std::array arr{}; - try { - auto_file.write((const char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange(0, 4096)); - } catch (const std::ios_base::failure&) { - } - break; - } - case 2: { - try { - auto_file.ignore(fuzzed_data_provider.ConsumeIntegralInRange(0, 4096)); - } catch (const std::ios_base::failure&) { - } - break; - } - case 3: { - auto_file.fclose(); - break; - } - case 4: { - ReadFromStream(fuzzed_data_provider, auto_file); - break; - } - case 5: { - WriteToStream(fuzzed_data_provider, auto_file); - break; - } - } + CallOneOf( + fuzzed_data_provider, + [&] { + std::array arr{}; + try { + auto_file.read((char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange(0, 4096)); + } catch (const std::ios_base::failure&) { + } + }, + [&] { + const std::array arr{}; + try { + auto_file.write((const char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange(0, 4096)); + } catch (const std::ios_base::failure&) { + } + }, + [&] { + try { + auto_file.ignore(fuzzed_data_provider.ConsumeIntegralInRange(0, 4096)); + } catch (const std::ios_base::failure&) { + } + }, + [&] { + auto_file.fclose(); + }, + [&] { + ReadFromStream(fuzzed_data_provider, auto_file); + }, + [&] { + WriteToStream(fuzzed_data_provider, auto_file); + }); } (void)auto_file.Get(); (void)auto_file.GetType(); diff --git a/src/test/fuzz/banman.cpp b/src/test/fuzz/banman.cpp index bc321932e633..17271ff2cb7f 100644 --- a/src/test/fuzz/banman.cpp +++ b/src/test/fuzz/banman.cpp @@ -37,51 +37,43 @@ FUZZ_TARGET_INIT(banman, initialize_banman) { BanMan ban_man{banlist_file, nullptr, ConsumeBanTimeOffset(fuzzed_data_provider)}; while (fuzzed_data_provider.ConsumeBool()) { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 11)) { - case 0: { - ban_man.Ban(ConsumeNetAddr(fuzzed_data_provider), - ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool()); - break; - } - case 1: { - ban_man.Ban(ConsumeSubNet(fuzzed_data_provider), - ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool()); - break; - } - case 2: { - ban_man.ClearBanned(); - break; - } - case 4: { - ban_man.IsBanned(ConsumeNetAddr(fuzzed_data_provider)); - break; - } - case 5: { - ban_man.IsBanned(ConsumeSubNet(fuzzed_data_provider)); - break; - } - case 6: { - ban_man.Unban(ConsumeNetAddr(fuzzed_data_provider)); - break; - } - case 7: { - ban_man.Unban(ConsumeSubNet(fuzzed_data_provider)); - break; - } - case 8: { - banmap_t banmap; - ban_man.GetBanned(banmap); - break; - } - case 9: { - ban_man.DumpBanlist(); - break; - } - case 11: { - ban_man.Discourage(ConsumeNetAddr(fuzzed_data_provider)); - break; - } - } + CallOneOf( + fuzzed_data_provider, + [&] { + ban_man.Ban(ConsumeNetAddr(fuzzed_data_provider), + ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool()); + }, + [&] { + ban_man.Ban(ConsumeSubNet(fuzzed_data_provider), + ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool()); + }, + [&] { + ban_man.ClearBanned(); + }, + [] {}, + [&] { + ban_man.IsBanned(ConsumeNetAddr(fuzzed_data_provider)); + }, + [&] { + ban_man.IsBanned(ConsumeSubNet(fuzzed_data_provider)); + }, + [&] { + ban_man.Unban(ConsumeNetAddr(fuzzed_data_provider)); + }, + [&] { + ban_man.Unban(ConsumeSubNet(fuzzed_data_provider)); + }, + [&] { + banmap_t banmap; + ban_man.GetBanned(banmap); + }, + [&] { + ban_man.DumpBanlist(); + }, + [] {}, + [&] { + ban_man.Discourage(ConsumeNetAddr(fuzzed_data_provider)); + }); } } fs::remove(banlist_file); diff --git a/src/test/fuzz/bloom_filter.cpp b/src/test/fuzz/bloom_filter.cpp index c0c66c564b2c..d43c182644bb 100644 --- a/src/test/fuzz/bloom_filter.cpp +++ b/src/test/fuzz/bloom_filter.cpp @@ -25,47 +25,43 @@ FUZZ_TARGET(bloom_filter) fuzzed_data_provider.ConsumeIntegral(), static_cast(fuzzed_data_provider.PickValueInArray({BLOOM_UPDATE_NONE, BLOOM_UPDATE_ALL, BLOOM_UPDATE_P2PUBKEY_ONLY, BLOOM_UPDATE_MASK}))}; while (fuzzed_data_provider.remaining_bytes() > 0) { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 3)) { - case 0: { - const std::vector b = ConsumeRandomLengthByteVector(fuzzed_data_provider); - (void)bloom_filter.contains(b); - bloom_filter.insert(b); - const bool present = bloom_filter.contains(b); - assert(present); - break; - } - case 1: { - const std::optional out_point = ConsumeDeserializable(fuzzed_data_provider); - if (!out_point) { - break; - } - (void)bloom_filter.contains(*out_point); - bloom_filter.insert(*out_point); - const bool present = bloom_filter.contains(*out_point); - assert(present); - break; - } - case 2: { - const std::optional u256 = ConsumeDeserializable(fuzzed_data_provider); - if (!u256) { - break; - } - (void)bloom_filter.contains(*u256); - bloom_filter.insert(*u256); - const bool present = bloom_filter.contains(*u256); - assert(present); - break; - } - case 3: { - const std::optional mut_tx = ConsumeDeserializable(fuzzed_data_provider); - if (!mut_tx) { - break; - } - const CTransaction tx{*mut_tx}; - (void)bloom_filter.IsRelevantAndUpdate(tx); - break; - } - } + CallOneOf( + fuzzed_data_provider, + [&] { + const std::vector b = ConsumeRandomLengthByteVector(fuzzed_data_provider); + (void)bloom_filter.contains(b); + bloom_filter.insert(b); + const bool present = bloom_filter.contains(b); + assert(present); + }, + [&] { + const std::optional out_point = ConsumeDeserializable(fuzzed_data_provider); + if (!out_point) { + return; + } + (void)bloom_filter.contains(*out_point); + bloom_filter.insert(*out_point); + const bool present = bloom_filter.contains(*out_point); + assert(present); + }, + [&] { + const std::optional u256 = ConsumeDeserializable(fuzzed_data_provider); + if (!u256) { + return; + } + (void)bloom_filter.contains(*u256); + bloom_filter.insert(*u256); + const bool present = bloom_filter.contains(*u256); + assert(present); + }, + [&] { + const std::optional mut_tx = ConsumeDeserializable(fuzzed_data_provider); + if (!mut_tx) { + return; + } + const CTransaction tx{*mut_tx}; + (void)bloom_filter.IsRelevantAndUpdate(tx); + }); (void)bloom_filter.IsWithinSizeConstraints(); } } diff --git a/src/test/fuzz/buffered_file.cpp b/src/test/fuzz/buffered_file.cpp index e5a987783936..b32a59986aaa 100644 --- a/src/test/fuzz/buffered_file.cpp +++ b/src/test/fuzz/buffered_file.cpp @@ -30,41 +30,36 @@ FUZZ_TARGET(buffered_file) if (opt_buffered_file && fuzzed_file != nullptr) { bool setpos_fail = false; while (fuzzed_data_provider.ConsumeBool()) { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 4)) { - case 0: { - std::array arr{}; - try { - opt_buffered_file->read((char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange(0, 4096)); - } catch (const std::ios_base::failure&) { - } - break; - } - case 1: { - opt_buffered_file->SetLimit(fuzzed_data_provider.ConsumeIntegralInRange(0, 4096)); - break; - } - case 2: { - if (!opt_buffered_file->SetPos(fuzzed_data_provider.ConsumeIntegralInRange(0, 4096))) { - setpos_fail = true; - } - break; - } - case 3: { - if (setpos_fail) { - // Calling FindByte(...) after a failed SetPos(...) call may result in an infinite loop. - break; - } - try { - opt_buffered_file->FindByte(fuzzed_data_provider.ConsumeIntegral()); - } catch (const std::ios_base::failure&) { - } - break; - } - case 4: { - ReadFromStream(fuzzed_data_provider, *opt_buffered_file); - break; - } - } + CallOneOf( + fuzzed_data_provider, + [&] { + std::array arr{}; + try { + opt_buffered_file->read((char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange(0, 4096)); + } catch (const std::ios_base::failure&) { + } + }, + [&] { + opt_buffered_file->SetLimit(fuzzed_data_provider.ConsumeIntegralInRange(0, 4096)); + }, + [&] { + if (!opt_buffered_file->SetPos(fuzzed_data_provider.ConsumeIntegralInRange(0, 4096))) { + setpos_fail = true; + } + }, + [&] { + if (setpos_fail) { + // Calling FindByte(...) after a failed SetPos(...) call may result in an infinite loop. + return; + } + try { + opt_buffered_file->FindByte(fuzzed_data_provider.ConsumeIntegral()); + } catch (const std::ios_base::failure&) { + } + }, + [&] { + ReadFromStream(fuzzed_data_provider, *opt_buffered_file); + }); } opt_buffered_file->GetPos(); opt_buffered_file->GetType(); diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp index e3781d057a28..748c4c29a734 100644 --- a/src/test/fuzz/coins_view.cpp +++ b/src/test/fuzz/coins_view.cpp @@ -51,103 +51,93 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view) Coin random_coin; CMutableTransaction random_mutable_transaction; while (fuzzed_data_provider.ConsumeBool()) { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 9)) { - case 0: { - if (random_coin.IsSpent()) { - break; - } - Coin coin = random_coin; - bool expected_code_path = false; - const bool possible_overwrite = fuzzed_data_provider.ConsumeBool(); - try { - coins_view_cache.AddCoin(random_out_point, std::move(coin), possible_overwrite); - expected_code_path = true; - } catch (const std::logic_error& e) { - if (e.what() == std::string{"Attempted to overwrite an unspent coin (when possible_overwrite is false)"}) { - assert(!possible_overwrite); + CallOneOf( + fuzzed_data_provider, + [&] { + if (random_coin.IsSpent()) { + return; + } + Coin coin = random_coin; + bool expected_code_path = false; + const bool possible_overwrite = fuzzed_data_provider.ConsumeBool(); + try { + coins_view_cache.AddCoin(random_out_point, std::move(coin), possible_overwrite); expected_code_path = true; + } catch (const std::logic_error& e) { + if (e.what() == std::string{"Attempted to overwrite an unspent coin (when possible_overwrite is false)"}) { + assert(!possible_overwrite); + expected_code_path = true; + } } - } - assert(expected_code_path); - break; - } - case 1: { - (void)coins_view_cache.Flush(); - break; - } - case 2: { - coins_view_cache.SetBestBlock(ConsumeUInt256(fuzzed_data_provider)); - break; - } - case 3: { - Coin move_to; - (void)coins_view_cache.SpendCoin(random_out_point, fuzzed_data_provider.ConsumeBool() ? &move_to : nullptr); - break; - } - case 4: { - coins_view_cache.Uncache(random_out_point); - break; - } - case 5: { - if (fuzzed_data_provider.ConsumeBool()) { - backend_coins_view = CCoinsView{}; - } - coins_view_cache.SetBackend(backend_coins_view); - break; - } - case 6: { - const std::optional opt_out_point = ConsumeDeserializable(fuzzed_data_provider); - if (!opt_out_point) { - break; - } - random_out_point = *opt_out_point; - break; - } - case 7: { - const std::optional opt_coin = ConsumeDeserializable(fuzzed_data_provider); - if (!opt_coin) { - break; - } - random_coin = *opt_coin; - break; - } - case 8: { - const std::optional opt_mutable_transaction = ConsumeDeserializable(fuzzed_data_provider); - if (!opt_mutable_transaction) { - break; - } - random_mutable_transaction = *opt_mutable_transaction; - break; - } - case 9: { - CCoinsMap coins_map; - while (fuzzed_data_provider.ConsumeBool()) { - CCoinsCacheEntry coins_cache_entry; - coins_cache_entry.flags = fuzzed_data_provider.ConsumeIntegral(); + assert(expected_code_path); + }, + [&] { + (void)coins_view_cache.Flush(); + }, + [&] { + coins_view_cache.SetBestBlock(ConsumeUInt256(fuzzed_data_provider)); + }, + [&] { + Coin move_to; + (void)coins_view_cache.SpendCoin(random_out_point, fuzzed_data_provider.ConsumeBool() ? &move_to : nullptr); + }, + [&] { + coins_view_cache.Uncache(random_out_point); + }, + [&] { if (fuzzed_data_provider.ConsumeBool()) { - coins_cache_entry.coin = random_coin; - } else { - const std::optional opt_coin = ConsumeDeserializable(fuzzed_data_provider); - if (!opt_coin) { - break; + backend_coins_view = CCoinsView{}; + } + coins_view_cache.SetBackend(backend_coins_view); + }, + [&] { + const std::optional opt_out_point = ConsumeDeserializable(fuzzed_data_provider); + if (!opt_out_point) { + return; + } + random_out_point = *opt_out_point; + }, + [&] { + const std::optional opt_coin = ConsumeDeserializable(fuzzed_data_provider); + if (!opt_coin) { + return; + } + random_coin = *opt_coin; + }, + [&] { + const std::optional opt_mutable_transaction = ConsumeDeserializable(fuzzed_data_provider); + if (!opt_mutable_transaction) { + return; + } + random_mutable_transaction = *opt_mutable_transaction; + }, + [&] { + CCoinsMap coins_map; + while (fuzzed_data_provider.ConsumeBool()) { + CCoinsCacheEntry coins_cache_entry; + coins_cache_entry.flags = fuzzed_data_provider.ConsumeIntegral(); + if (fuzzed_data_provider.ConsumeBool()) { + coins_cache_entry.coin = random_coin; + } else { + const std::optional opt_coin = ConsumeDeserializable(fuzzed_data_provider); + if (!opt_coin) { + return; + } + coins_cache_entry.coin = *opt_coin; } - coins_cache_entry.coin = *opt_coin; + coins_map.emplace(random_out_point, std::move(coins_cache_entry)); } - coins_map.emplace(random_out_point, std::move(coins_cache_entry)); - } - bool expected_code_path = false; - try { - coins_view_cache.BatchWrite(coins_map, fuzzed_data_provider.ConsumeBool() ? ConsumeUInt256(fuzzed_data_provider) : coins_view_cache.GetBestBlock()); - expected_code_path = true; - } catch (const std::logic_error& e) { - if (e.what() == std::string{"FRESH flag misapplied to coin that exists in parent cache"}) { + bool expected_code_path = false; + try { + coins_view_cache.BatchWrite(coins_map, fuzzed_data_provider.ConsumeBool() ? ConsumeUInt256(fuzzed_data_provider) : coins_view_cache.GetBestBlock()); expected_code_path = true; + } catch (const std::logic_error& e) { + if (e.what() == std::string{"FRESH flag misapplied to coin that exists in parent cache"}) { + expected_code_path = true; + } } - } - assert(expected_code_path); - break; - } - } + assert(expected_code_path); + }); } { @@ -200,92 +190,86 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view) } if (fuzzed_data_provider.ConsumeBool()) { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 5)) { - case 0: { - const CTransaction transaction{random_mutable_transaction}; - bool is_spent = false; - for (const CTxOut& tx_out : transaction.vout) { - if (Coin{tx_out, 0, transaction.IsCoinBase()}.IsSpent()) { - is_spent = true; + CallOneOf( + fuzzed_data_provider, + [&] { + const CTransaction transaction{random_mutable_transaction}; + bool is_spent = false; + for (const CTxOut& tx_out : transaction.vout) { + if (Coin{tx_out, 0, transaction.IsCoinBase()}.IsSpent()) { + is_spent = true; + } + } + if (is_spent) { + // Avoid: + // coins.cpp:69: void CCoinsViewCache::AddCoin(const COutPoint &, Coin &&, bool): Assertion `!coin.IsSpent()' failed. + return; } - } - if (is_spent) { - // Avoid: - // coins.cpp:69: void CCoinsViewCache::AddCoin(const COutPoint &, Coin &&, bool): Assertion `!coin.IsSpent()' failed. - break; - } - bool expected_code_path = false; - const int height = fuzzed_data_provider.ConsumeIntegral(); - const bool possible_overwrite = fuzzed_data_provider.ConsumeBool(); - try { - AddCoins(coins_view_cache, transaction, height, possible_overwrite); - expected_code_path = true; - } catch (const std::logic_error& e) { - if (e.what() == std::string{"Attempted to overwrite an unspent coin (when possible_overwrite is false)"}) { - assert(!possible_overwrite); + bool expected_code_path = false; + const int height = fuzzed_data_provider.ConsumeIntegral(); + const bool possible_overwrite = fuzzed_data_provider.ConsumeBool(); + try { + AddCoins(coins_view_cache, transaction, height, possible_overwrite); expected_code_path = true; + } catch (const std::logic_error& e) { + if (e.what() == std::string{"Attempted to overwrite an unspent coin (when possible_overwrite is false)"}) { + assert(!possible_overwrite); + expected_code_path = true; + } } - } - assert(expected_code_path); - break; - } - case 1: { - (void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache); - break; - } - case 2: { - CValidationState state; - CAmount tx_fee_out; - const CTransaction transaction{random_mutable_transaction}; - if (ContainsSpentInput(transaction, coins_view_cache)) { - // Avoid: - // consensus/tx_verify.cpp:171: bool Consensus::CheckTxInputs(const CTransaction &, CValidationState &, const CCoinsViewCache &, int, CAmount &): Assertion `!coin.IsSpent()' failed. - break; - } - try { - (void)Consensus::CheckTxInputs(transaction, state, coins_view_cache, fuzzed_data_provider.ConsumeIntegralInRange(0, std::numeric_limits::max()), tx_fee_out); - assert(MoneyRange(tx_fee_out)); - } catch (const std::runtime_error&) { - } - break; - } - case 3: { - const CTransaction transaction{random_mutable_transaction}; - if (ContainsSpentInput(transaction, coins_view_cache)) { - // Avoid: - // consensus/tx_verify.cpp:130: unsigned int GetP2SHSigOpCount(const CTransaction &, const CCoinsViewCache &): Assertion `!coin.IsSpent()' failed. - break; - } - (void)GetP2SHSigOpCount(transaction, coins_view_cache); - break; - } - case 4: { - const CTransaction transaction{random_mutable_transaction}; - if (ContainsSpentInput(transaction, coins_view_cache)) { - // Avoid: - // consensus/tx_verify.cpp:130: unsigned int GetP2SHSigOpCount(const CTransaction &, const CCoinsViewCache &): Assertion `!coin.IsSpent()' failed. - break; - } - const int flags = fuzzed_data_provider.ConsumeIntegral(); - if (!transaction.vin.empty() && (flags & SCRIPT_VERIFY_P2SH) == 0) { - // Avoid: - // script/interpreter.cpp:1705: size_t CountWitnessSigOps(const CScript &, const CScript &, const CScriptWitness *, unsigned int): Assertion `(flags & SCRIPT_VERIFY_P2SH) != 0' failed. - break; - } - (void)GetTransactionSigOpCount(transaction, coins_view_cache, flags); - break; - } - case 5: { - CCoinsStats stats; - bool expected_code_path = false; - try { - (void)GetUTXOStats(&coins_view_cache, stats, CoinStatsHashType::HASH_SERIALIZED); - } catch (const std::logic_error&) { - expected_code_path = true; - } - assert(expected_code_path); - break; - } - } + assert(expected_code_path); + }, + [&] { + (void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache); + }, + [&] { + CValidationState state; + CAmount tx_fee_out; + const CTransaction transaction{random_mutable_transaction}; + if (ContainsSpentInput(transaction, coins_view_cache)) { + // Avoid: + // consensus/tx_verify.cpp:171: bool Consensus::CheckTxInputs(const CTransaction &, CValidationState &, const CCoinsViewCache &, int, CAmount &): Assertion `!coin.IsSpent()' failed. + return; + } + try { + (void)Consensus::CheckTxInputs(transaction, state, coins_view_cache, fuzzed_data_provider.ConsumeIntegralInRange(0, std::numeric_limits::max()), tx_fee_out); + assert(MoneyRange(tx_fee_out)); + } catch (const std::runtime_error&) { + } + }, + [&] { + const CTransaction transaction{random_mutable_transaction}; + if (ContainsSpentInput(transaction, coins_view_cache)) { + // Avoid: + // consensus/tx_verify.cpp:130: unsigned int GetP2SHSigOpCount(const CTransaction &, const CCoinsViewCache &): Assertion `!coin.IsSpent()' failed. + return; + } + (void)GetP2SHSigOpCount(transaction, coins_view_cache); + }, + [&] { + const CTransaction transaction{random_mutable_transaction}; + if (ContainsSpentInput(transaction, coins_view_cache)) { + // Avoid: + // consensus/tx_verify.cpp:130: unsigned int GetP2SHSigOpCount(const CTransaction &, const CCoinsViewCache &): Assertion `!coin.IsSpent()' failed. + return; + } + const int flags = fuzzed_data_provider.ConsumeIntegral(); + if (!transaction.vin.empty() && (flags & SCRIPT_VERIFY_P2SH) == 0) { + // Avoid: + // script/interpreter.cpp:1705: size_t CountWitnessSigOps(const CScript &, const CScript &, const CScriptWitness *, unsigned int): Assertion `(flags & SCRIPT_VERIFY_P2SH) != 0' failed. + return; + } + (void)GetTransactionSigOpCount(transaction, coins_view_cache, flags); + }, + [&] { + CCoinsStats stats; + bool expected_code_path = false; + try { + (void)GetUTXOStats(&coins_view_cache, stats, CoinStatsHashType::HASH_SERIALIZED); + } catch (const std::logic_error&) { + expected_code_path = true; + } + assert(expected_code_path); + }); } } diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp index f2c52f7a37b6..13de7604bd37 100644 --- a/src/test/fuzz/connman.cpp +++ b/src/test/fuzz/connman.cpp @@ -30,90 +30,87 @@ FUZZ_TARGET_INIT(connman, initialize_connman) CSubNet random_subnet; std::string random_string; while (fuzzed_data_provider.ConsumeBool()) { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 23)) { - case 0: - random_netaddr = ConsumeNetAddr(fuzzed_data_provider); - break; - case 1: - random_subnet = ConsumeSubNet(fuzzed_data_provider); - break; - case 2: - random_string = fuzzed_data_provider.ConsumeRandomLengthString(64); - break; - case 3: - connman.AddNode(random_string); - break; - case 4: - connman.CheckIncomingNonce(fuzzed_data_provider.ConsumeIntegral()); - break; - case 5: - connman.DisconnectNode(fuzzed_data_provider.ConsumeIntegral()); - break; - case 6: - connman.DisconnectNode(random_netaddr); - break; - case 7: - connman.DisconnectNode(random_string); - break; - case 8: - connman.DisconnectNode(random_subnet); - break; - case 9: - connman.ForEachNode([](auto) {}); - break; - case 10: - connman.ForEachNodeThen([](auto) {}, []() {}); - break; - case 11: - (void)connman.ForNode(fuzzed_data_provider.ConsumeIntegral(), [&](auto) { return fuzzed_data_provider.ConsumeBool(); }); - break; - case 12: - (void)connman.GetAddresses(); - break; - case 13: { - (void)connman.GetAddresses(); - break; - } - case 14: - (void)connman.GetDeterministicRandomizer(fuzzed_data_provider.ConsumeIntegral()); - break; - case 15: - (void)connman.GetNodeCount(fuzzed_data_provider.PickValueInArray({CConnman::CONNECTIONS_NONE, CConnman::CONNECTIONS_IN, CConnman::CONNECTIONS_OUT, CConnman::CONNECTIONS_ALL})); - break; - case 16: - (void)connman.OutboundTargetReached(fuzzed_data_provider.ConsumeBool()); - break; - case 17: - // Limit now to int32_t to avoid signed integer overflow - (void)connman.PoissonNextSendInbound(fuzzed_data_provider.ConsumeIntegral(), fuzzed_data_provider.ConsumeIntegral()); - break; - case 18: { - CSerializedNetMsg serialized_net_msg; - serialized_net_msg.command = fuzzed_data_provider.ConsumeRandomLengthString(CMessageHeader::COMMAND_SIZE); - serialized_net_msg.data = ConsumeRandomLengthByteVector(fuzzed_data_provider); - connman.PushMessage(&random_node, std::move(serialized_net_msg)); - break; - } - case 19: - connman.RemoveAddedNode(random_string); - break; - case 20: { - const std::vector asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider); - if (SanityCheckASMap(asmap)) { - connman.SetAsmap(asmap); - } - break; - } - case 21: - connman.SetBestHeight(fuzzed_data_provider.ConsumeIntegral()); - break; - case 22: - connman.SetNetworkActive(fuzzed_data_provider.ConsumeBool()); - break; - case 23: - connman.SetTryNewOutboundPeer(fuzzed_data_provider.ConsumeBool()); - break; - } + CallOneOf( + fuzzed_data_provider, + [&] { + random_netaddr = ConsumeNetAddr(fuzzed_data_provider); + }, + [&] { + random_subnet = ConsumeSubNet(fuzzed_data_provider); + }, + [&] { + random_string = fuzzed_data_provider.ConsumeRandomLengthString(64); + }, + [&] { + connman.AddNode(random_string); + }, + [&] { + connman.CheckIncomingNonce(fuzzed_data_provider.ConsumeIntegral()); + }, + [&] { + connman.DisconnectNode(fuzzed_data_provider.ConsumeIntegral()); + }, + [&] { + connman.DisconnectNode(random_netaddr); + }, + [&] { + connman.DisconnectNode(random_string); + }, + [&] { + connman.DisconnectNode(random_subnet); + }, + [&] { + connman.ForEachNode([](auto) {}); + }, + [&] { + connman.ForEachNodeThen([](auto) {}, []() {}); + }, + [&] { + (void)connman.ForNode(fuzzed_data_provider.ConsumeIntegral(), [&](auto) { return fuzzed_data_provider.ConsumeBool(); }); + }, + [&] { + (void)connman.GetAddresses(); + }, + [&] { + (void)connman.GetAddresses(); + }, + [&] { + (void)connman.GetDeterministicRandomizer(fuzzed_data_provider.ConsumeIntegral()); + }, + [&] { + (void)connman.GetNodeCount(fuzzed_data_provider.PickValueInArray({CConnman::CONNECTIONS_NONE, CConnman::CONNECTIONS_IN, CConnman::CONNECTIONS_OUT, CConnman::CONNECTIONS_ALL})); + }, + [&] { + (void)connman.OutboundTargetReached(fuzzed_data_provider.ConsumeBool()); + }, + [&] { + // Limit now to int32_t to avoid signed integer overflow + (void)connman.PoissonNextSendInbound(fuzzed_data_provider.ConsumeIntegral(), fuzzed_data_provider.ConsumeIntegral()); + }, + [&] { + CSerializedNetMsg serialized_net_msg; + serialized_net_msg.command = fuzzed_data_provider.ConsumeRandomLengthString(CMessageHeader::COMMAND_SIZE); + serialized_net_msg.data = ConsumeRandomLengthByteVector(fuzzed_data_provider); + connman.PushMessage(&random_node, std::move(serialized_net_msg)); + }, + [&] { + connman.RemoveAddedNode(random_string); + }, + [&] { + const std::vector asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider); + if (SanityCheckASMap(asmap)) { + connman.SetAsmap(asmap); + } + }, + [&] { + connman.SetBestHeight(fuzzed_data_provider.ConsumeIntegral()); + }, + [&] { + connman.SetNetworkActive(fuzzed_data_provider.ConsumeBool()); + }, + [&] { + connman.SetTryNewOutboundPeer(fuzzed_data_provider.ConsumeBool()); + }); } (void)connman.GetAddedNodeInfo(); (void)connman.GetBestHeight(); diff --git a/src/test/fuzz/crypto.cpp b/src/test/fuzz/crypto.cpp index 08cfa823a91c..901378d66079 100644 --- a/src/test/fuzz/crypto.cpp +++ b/src/test/fuzz/crypto.cpp @@ -37,97 +37,84 @@ FUZZ_TARGET(crypto) CSipHasher sip_hasher{fuzzed_data_provider.ConsumeIntegral(), fuzzed_data_provider.ConsumeIntegral()}; while (fuzzed_data_provider.ConsumeBool()) { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 2)) { - case 0: { - if (fuzzed_data_provider.ConsumeBool()) { - data = ConsumeRandomLengthByteVector(fuzzed_data_provider); - if (data.empty()) { - data.resize(fuzzed_data_provider.ConsumeIntegralInRange(1, 4096), fuzzed_data_provider.ConsumeIntegral()); + CallOneOf( + fuzzed_data_provider, + [&] { + if (fuzzed_data_provider.ConsumeBool()) { + data = ConsumeRandomLengthByteVector(fuzzed_data_provider); + if (data.empty()) { + data.resize(fuzzed_data_provider.ConsumeIntegralInRange(1, 4096), fuzzed_data_provider.ConsumeIntegral()); + } } - } - (void)hash160.Write(data); - (void)hash256.Write(data); - (void)hmac_sha256.Write(data.data(), data.size()); - (void)hmac_sha512.Write(data.data(), data.size()); - (void)ripemd160.Write(data.data(), data.size()); - (void)sha1.Write(data.data(), data.size()); - (void)sha256.Write(data.data(), data.size()); - (void)sha3.Write(data); - (void)sha512.Write(data.data(), data.size()); - (void)sip_hasher.Write(data.data(), data.size()); + (void)hash160.Write(data); + (void)hash256.Write(data); + (void)hmac_sha256.Write(data.data(), data.size()); + (void)hmac_sha512.Write(data.data(), data.size()); + (void)ripemd160.Write(data.data(), data.size()); + (void)sha1.Write(data.data(), data.size()); + (void)sha256.Write(data.data(), data.size()); + (void)sha3.Write(data); + (void)sha512.Write(data.data(), data.size()); + (void)sip_hasher.Write(data.data(), data.size()); - (void)Hash160(data); - (void)Hash160(data.begin(), data.end()); - (void)sha512.Size(); - break; - } - case 1: { - (void)hash160.Reset(); - (void)hash256.Reset(); - (void)ripemd160.Reset(); - (void)sha1.Reset(); - (void)sha256.Reset(); - (void)sha3.Reset(); - (void)sha512.Reset(); - break; - } - case 2: { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 9)) { - case 0: { - data.resize(CHash160::OUTPUT_SIZE); - hash160.Finalize(data); - break; - } - case 1: { - data.resize(CHash256::OUTPUT_SIZE); - hash256.Finalize(data); - break; - } - case 2: { - data.resize(CHMAC_SHA256::OUTPUT_SIZE); - hmac_sha256.Finalize(data.data()); - break; - } - case 3: { - data.resize(CHMAC_SHA512::OUTPUT_SIZE); - hmac_sha512.Finalize(data.data()); - break; - } - case 4: { - data.resize(CRIPEMD160::OUTPUT_SIZE); - ripemd160.Finalize(data.data()); - break; - } - case 5: { - data.resize(CSHA1::OUTPUT_SIZE); - sha1.Finalize(data.data()); - break; - } - case 6: { - data.resize(CSHA256::OUTPUT_SIZE); - sha256.Finalize(data.data()); - break; - } - case 7: { - data.resize(CSHA512::OUTPUT_SIZE); - sha512.Finalize(data.data()); - break; - } - case 8: { - data.resize(1); - data[0] = sip_hasher.Finalize() % 256; - break; - } - case 9: { - data.resize(SHA3_256::OUTPUT_SIZE); - sha3.Finalize(data); - break; - } - } - break; - } - } + (void)Hash160(data); + (void)Hash160(data.begin(), data.end()); + (void)sha512.Size(); + }, + [&] { + (void)hash160.Reset(); + (void)hash256.Reset(); + (void)ripemd160.Reset(); + (void)sha1.Reset(); + (void)sha256.Reset(); + (void)sha3.Reset(); + (void)sha512.Reset(); + }, + [&] { + CallOneOf( + fuzzed_data_provider, + [&] { + data.resize(CHash160::OUTPUT_SIZE); + hash160.Finalize(data); + }, + [&] { + data.resize(CHash256::OUTPUT_SIZE); + hash256.Finalize(data); + }, + [&] { + data.resize(CHMAC_SHA256::OUTPUT_SIZE); + hmac_sha256.Finalize(data.data()); + }, + [&] { + data.resize(CHMAC_SHA512::OUTPUT_SIZE); + hmac_sha512.Finalize(data.data()); + }, + [&] { + data.resize(CRIPEMD160::OUTPUT_SIZE); + ripemd160.Finalize(data.data()); + }, + [&] { + data.resize(CSHA1::OUTPUT_SIZE); + sha1.Finalize(data.data()); + }, + [&] { + data.resize(CSHA256::OUTPUT_SIZE); + sha256.Finalize(data.data()); + }, + [&] { + data.resize(CSHA512::OUTPUT_SIZE); + sha512.Finalize(data.data()); + }, + [&] { + data.resize(1); + data[0] = sip_hasher.Finalize() % 256; + }, + [&] { + data.resize(SHA3_256::OUTPUT_SIZE); + sha3.Finalize(data); + }); + }); } if (fuzzed_data_provider.ConsumeBool()) { uint64_t state[25]; diff --git a/src/test/fuzz/crypto_chacha20.cpp b/src/test/fuzz/crypto_chacha20.cpp index d751466f1157..bb8dd4594ff9 100644 --- a/src/test/fuzz/crypto_chacha20.cpp +++ b/src/test/fuzz/crypto_chacha20.cpp @@ -20,31 +20,26 @@ FUZZ_TARGET(crypto_chacha20) chacha20 = ChaCha20{key.data(), key.size()}; } while (fuzzed_data_provider.ConsumeBool()) { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 4)) { - case 0: { - const std::vector key = ConsumeFixedLengthByteVector(fuzzed_data_provider, fuzzed_data_provider.ConsumeIntegralInRange(16, 32)); - chacha20.SetKey(key.data(), key.size()); - break; - } - case 1: { - chacha20.SetIV(fuzzed_data_provider.ConsumeIntegral()); - break; - } - case 2: { - chacha20.Seek(fuzzed_data_provider.ConsumeIntegral()); - break; - } - case 3: { - std::vector output(fuzzed_data_provider.ConsumeIntegralInRange(0, 4096)); - chacha20.Keystream(output.data(), output.size()); - break; - } - case 4: { - std::vector output(fuzzed_data_provider.ConsumeIntegralInRange(0, 4096)); - const std::vector input = ConsumeFixedLengthByteVector(fuzzed_data_provider, output.size()); - chacha20.Crypt(input.data(), output.data(), input.size()); - break; - } - } + CallOneOf( + fuzzed_data_provider, + [&] { + const std::vector key = ConsumeFixedLengthByteVector(fuzzed_data_provider, fuzzed_data_provider.ConsumeIntegralInRange(16, 32)); + chacha20.SetKey(key.data(), key.size()); + }, + [&] { + chacha20.SetIV(fuzzed_data_provider.ConsumeIntegral()); + }, + [&] { + chacha20.Seek(fuzzed_data_provider.ConsumeIntegral()); + }, + [&] { + std::vector output(fuzzed_data_provider.ConsumeIntegralInRange(0, 4096)); + chacha20.Keystream(output.data(), output.size()); + }, + [&] { + std::vector output(fuzzed_data_provider.ConsumeIntegralInRange(0, 4096)); + const std::vector input = ConsumeFixedLengthByteVector(fuzzed_data_provider, output.size()); + chacha20.Crypt(input.data(), output.data(), input.size()); + }); } } diff --git a/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp b/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp index 631af9c70dd0..1f122082b21d 100644 --- a/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp +++ b/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp @@ -29,44 +29,37 @@ FUZZ_TARGET(crypto_chacha20_poly1305_aead) std::vector out(buffer_size + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0); bool is_encrypt = fuzzed_data_provider.ConsumeBool(); while (fuzzed_data_provider.ConsumeBool()) { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 6)) { - case 0: { - buffer_size = fuzzed_data_provider.ConsumeIntegralInRange(64, 4096); - in = std::vector(buffer_size + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0); - out = std::vector(buffer_size + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0); - break; - } - case 1: { - (void)aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, out.data(), out.size(), in.data(), buffer_size, is_encrypt); - break; - } - case 2: { - uint32_t len = 0; - const bool ok = aead.GetLength(&len, seqnr_aad, aad_pos, in.data()); - assert(ok); - break; - } - case 3: { - seqnr_payload += 1; - aad_pos += CHACHA20_POLY1305_AEAD_AAD_LEN; - if (aad_pos + CHACHA20_POLY1305_AEAD_AAD_LEN > CHACHA20_ROUND_OUTPUT) { - aad_pos = 0; - seqnr_aad += 1; - } - break; - } - case 4: { - seqnr_payload = fuzzed_data_provider.ConsumeIntegral(); - break; - } - case 5: { - seqnr_aad = fuzzed_data_provider.ConsumeIntegral(); - break; - } - case 6: { - is_encrypt = fuzzed_data_provider.ConsumeBool(); - break; - } - } + CallOneOf( + fuzzed_data_provider, + [&] { + buffer_size = fuzzed_data_provider.ConsumeIntegralInRange(64, 4096); + in = std::vector(buffer_size + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0); + out = std::vector(buffer_size + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0); + }, + [&] { + (void)aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, out.data(), out.size(), in.data(), buffer_size, is_encrypt); + }, + [&] { + uint32_t len = 0; + const bool ok = aead.GetLength(&len, seqnr_aad, aad_pos, in.data()); + assert(ok); + }, + [&] { + seqnr_payload += 1; + aad_pos += CHACHA20_POLY1305_AEAD_AAD_LEN; + if (aad_pos + CHACHA20_POLY1305_AEAD_AAD_LEN > CHACHA20_ROUND_OUTPUT) { + aad_pos = 0; + seqnr_aad += 1; + } + }, + [&] { + seqnr_payload = fuzzed_data_provider.ConsumeIntegral(); + }, + [&] { + seqnr_aad = fuzzed_data_provider.ConsumeIntegral(); + }, + [&] { + is_encrypt = fuzzed_data_provider.ConsumeBool(); + }); } } diff --git a/src/test/fuzz/merkleblock.cpp b/src/test/fuzz/merkleblock.cpp index 15bcfab3ad80..23e0baa56458 100644 --- a/src/test/fuzz/merkleblock.cpp +++ b/src/test/fuzz/merkleblock.cpp @@ -17,33 +17,31 @@ FUZZ_TARGET(merkleblock) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); CPartialMerkleTree partial_merkle_tree; - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 1)) { - case 0: { - const std::optional opt_partial_merkle_tree = ConsumeDeserializable(fuzzed_data_provider); - if (opt_partial_merkle_tree) { - partial_merkle_tree = *opt_partial_merkle_tree; - } - break; - } - case 1: { - CMerkleBlock merkle_block; - const std::optional opt_block = ConsumeDeserializable(fuzzed_data_provider); - CBloomFilter bloom_filter; - std::set txids; - if (opt_block && !opt_block->vtx.empty()) { - if (fuzzed_data_provider.ConsumeBool()) { - merkle_block = CMerkleBlock{*opt_block, bloom_filter}; - } else if (fuzzed_data_provider.ConsumeBool()) { - while (fuzzed_data_provider.ConsumeBool()) { - txids.insert(ConsumeUInt256(fuzzed_data_provider)); + CallOneOf( + fuzzed_data_provider, + [&] { + const std::optional opt_partial_merkle_tree = ConsumeDeserializable(fuzzed_data_provider); + if (opt_partial_merkle_tree) { + partial_merkle_tree = *opt_partial_merkle_tree; + } + }, + [&] { + CMerkleBlock merkle_block; + const std::optional opt_block = ConsumeDeserializable(fuzzed_data_provider); + CBloomFilter bloom_filter; + std::set txids; + if (opt_block && !opt_block->vtx.empty()) { + if (fuzzed_data_provider.ConsumeBool()) { + merkle_block = CMerkleBlock{*opt_block, bloom_filter}; + } else if (fuzzed_data_provider.ConsumeBool()) { + while (fuzzed_data_provider.ConsumeBool()) { + txids.insert(ConsumeUInt256(fuzzed_data_provider)); + } + merkle_block = CMerkleBlock{*opt_block, txids}; } - merkle_block = CMerkleBlock{*opt_block, txids}; } - } - partial_merkle_tree = merkle_block.txn; - break; - } - } + partial_merkle_tree = merkle_block.txn; + }); (void)partial_merkle_tree.GetNumTransactions(); std::vector matches; std::vector indices; diff --git a/src/test/fuzz/net.cpp b/src/test/fuzz/net.cpp index 7a32948f8b3c..8f44042dd9e8 100644 --- a/src/test/fuzz/net.cpp +++ b/src/test/fuzz/net.cpp @@ -50,99 +50,86 @@ FUZZ_TARGET_INIT(net, initialize_net) fuzzed_data_provider.ConsumeBool() }; while (fuzzed_data_provider.ConsumeBool()) { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 12)) { - case 0: { - CAddrMan addrman; - CConnman connman{fuzzed_data_provider.ConsumeIntegral(), fuzzed_data_provider.ConsumeIntegral(), addrman}; - node.CloseSocketDisconnect(&connman); - break; - } - case 1: { - node.MaybeSetAddrName(fuzzed_data_provider.ConsumeRandomLengthString(32)); - break; - } - case 2: { - node.SetSendVersion(fuzzed_data_provider.ConsumeIntegral()); - break; - } - case 3: { - const std::vector asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider); - if (!SanityCheckASMap(asmap)) { - break; - } - CNodeStats stats; - node.copyStats(stats, asmap); - break; - } - case 4: { - node.SetRecvVersion(fuzzed_data_provider.ConsumeIntegral()); - break; - } - case 5: { - const CNode* add_ref_node = node.AddRef(); - assert(add_ref_node == &node); - break; - } - case 6: { - if (node.GetRefCount() > 0) { - node.Release(); - } - break; - } - case 7: { - // if (node.m_addr_known == nullptr) { - // break; - // } - const std::optional addr_opt = ConsumeDeserializable(fuzzed_data_provider); - if (!addr_opt) { - break; - } - node.AddAddressKnown(*addr_opt); - break; - } - case 8: { - // if (node.m_addr_known == nullptr) { - // break; - // } - const std::optional addr_opt = ConsumeDeserializable(fuzzed_data_provider); - if (!addr_opt) { - break; - } - FastRandomContext fast_random_context{ConsumeUInt256(fuzzed_data_provider)}; - node.PushAddress(*addr_opt, fast_random_context); - break; - } - case 9: { - const std::optional inv_opt = ConsumeDeserializable(fuzzed_data_provider); - if (!inv_opt) { - break; - } - // node.AddKnownTx(inv_opt->hash); - break; - } - case 10: { - const std::optional inv_opt = ConsumeDeserializable(fuzzed_data_provider); - if (!inv_opt) { - break; - } - node.PushInventory(*inv_opt); - break; - } - case 11: { - const std::optional service_opt = ConsumeDeserializable(fuzzed_data_provider); - if (!service_opt) { - break; - } - node.SetAddrLocal(*service_opt); - break; - } - case 12: { - const std::vector b = ConsumeRandomLengthByteVector(fuzzed_data_provider); - bool complete; - node.ReceiveMsgBytes((const char*)b.data(), b.size(), complete); - break; - } - } + CallOneOf( + fuzzed_data_provider, + [&] { + CAddrMan addrman; + CConnman connman{fuzzed_data_provider.ConsumeIntegral(), fuzzed_data_provider.ConsumeIntegral(), addrman}; + node.CloseSocketDisconnect(&connman); + }, + [&] { + node.MaybeSetAddrName(fuzzed_data_provider.ConsumeRandomLengthString(32)); + }, + [&] { + node.SetSendVersion(fuzzed_data_provider.ConsumeIntegral()); + }, + [&] { + const std::vector asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider); + if (!SanityCheckASMap(asmap)) { + return; + } + CNodeStats stats; + node.copyStats(stats, asmap); + }, + [&] { + node.SetRecvVersion(fuzzed_data_provider.ConsumeIntegral()); + }, + [&] { + const CNode* add_ref_node = node.AddRef(); + assert(add_ref_node == &node); + }, + [&] { + if (node.GetRefCount() > 0) { + node.Release(); + } + }, + [&] { + // if (node.m_addr_known == nullptr) { + // return; + // } + const std::optional addr_opt = ConsumeDeserializable(fuzzed_data_provider); + if (!addr_opt) { + return; + } + node.AddAddressKnown(*addr_opt); + }, + [&] { + // if (node.m_addr_known == nullptr) { + // return; + // } + const std::optional addr_opt = ConsumeDeserializable(fuzzed_data_provider); + if (!addr_opt) { + return; + } + FastRandomContext fast_random_context{ConsumeUInt256(fuzzed_data_provider)}; + node.PushAddress(*addr_opt, fast_random_context); + }, + [&] { + const std::optional inv_opt = ConsumeDeserializable(fuzzed_data_provider); + if (!inv_opt) { + return; + } + // node.AddKnownTx(inv_opt->hash); + }, + [&] { + const std::optional inv_opt = ConsumeDeserializable(fuzzed_data_provider); + if (!inv_opt) { + return; + } + node.PushInventory(*inv_opt); + }, + [&] { + const std::optional service_opt = ConsumeDeserializable(fuzzed_data_provider); + if (!service_opt) { + return; + } + node.SetAddrLocal(*service_opt); + }, + [&] { + const std::vector b = ConsumeRandomLengthByteVector(fuzzed_data_provider); + bool complete; + node.ReceiveMsgBytes((const char*)b.data(), b.size(), complete); + }); } (void)node.GetAddrLocal(); diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp index 451d4a3b5b60..8c77391e99f7 100644 --- a/src/test/fuzz/policy_estimator.cpp +++ b/src/test/fuzz/policy_estimator.cpp @@ -19,46 +19,42 @@ FUZZ_TARGET(policy_estimator) FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); CBlockPolicyEstimator block_policy_estimator; while (fuzzed_data_provider.ConsumeBool()) { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 3)) { - case 0: { - const std::optional mtx = ConsumeDeserializable(fuzzed_data_provider); - if (!mtx) { - break; - } - const CTransaction tx{*mtx}; - block_policy_estimator.processTransaction(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx), fuzzed_data_provider.ConsumeBool()); - if (fuzzed_data_provider.ConsumeBool()) { - (void)block_policy_estimator.removeTx(tx.GetHash(), /* inBlock */ fuzzed_data_provider.ConsumeBool()); - } - break; - } - case 1: { - std::vector mempool_entries; - while (fuzzed_data_provider.ConsumeBool()) { + CallOneOf( + fuzzed_data_provider, + [&] { const std::optional mtx = ConsumeDeserializable(fuzzed_data_provider); if (!mtx) { - break; + return; } const CTransaction tx{*mtx}; - mempool_entries.push_back(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx)); - } - std::vector ptrs; - ptrs.reserve(mempool_entries.size()); - for (const CTxMemPoolEntry& mempool_entry : mempool_entries) { - ptrs.push_back(&mempool_entry); - } - block_policy_estimator.processBlock(fuzzed_data_provider.ConsumeIntegral(), ptrs); - break; - } - case 2: { - (void)block_policy_estimator.removeTx(ConsumeUInt256(fuzzed_data_provider), /* inBlock */ fuzzed_data_provider.ConsumeBool()); - break; - } - case 3: { - block_policy_estimator.FlushUnconfirmed(); - break; - } - } + block_policy_estimator.processTransaction(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx), fuzzed_data_provider.ConsumeBool()); + if (fuzzed_data_provider.ConsumeBool()) { + (void)block_policy_estimator.removeTx(tx.GetHash(), /* inBlock */ fuzzed_data_provider.ConsumeBool()); + } + }, + [&] { + std::vector mempool_entries; + while (fuzzed_data_provider.ConsumeBool()) { + const std::optional mtx = ConsumeDeserializable(fuzzed_data_provider); + if (!mtx) { + break; + } + const CTransaction tx{*mtx}; + mempool_entries.push_back(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx)); + } + std::vector ptrs; + ptrs.reserve(mempool_entries.size()); + for (const CTxMemPoolEntry& mempool_entry : mempool_entries) { + ptrs.push_back(&mempool_entry); + } + block_policy_estimator.processBlock(fuzzed_data_provider.ConsumeIntegral(), ptrs); + }, + [&] { + (void)block_policy_estimator.removeTx(ConsumeUInt256(fuzzed_data_provider), /* inBlock */ fuzzed_data_provider.ConsumeBool()); + }, + [&] { + block_policy_estimator.FlushUnconfirmed(); + }); (void)block_policy_estimator.estimateFee(fuzzed_data_provider.ConsumeIntegral()); EstimationResult result; (void)block_policy_estimator.estimateRawFee(fuzzed_data_provider.ConsumeIntegral(), fuzzed_data_provider.ConsumeFloatingPoint(), fuzzed_data_provider.PickValueInArray({FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE}), fuzzed_data_provider.ConsumeBool() ? &result : nullptr); diff --git a/src/test/fuzz/rolling_bloom_filter.cpp b/src/test/fuzz/rolling_bloom_filter.cpp index 6087ee964a99..2a08b45aa324 100644 --- a/src/test/fuzz/rolling_bloom_filter.cpp +++ b/src/test/fuzz/rolling_bloom_filter.cpp @@ -22,29 +22,27 @@ FUZZ_TARGET(rolling_bloom_filter) fuzzed_data_provider.ConsumeIntegralInRange(1, 1000), 0.999 / fuzzed_data_provider.ConsumeIntegralInRange(1, std::numeric_limits::max())}; while (fuzzed_data_provider.remaining_bytes() > 0) { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 2)) { - case 0: { - const std::vector b = ConsumeRandomLengthByteVector(fuzzed_data_provider); - (void)rolling_bloom_filter.contains(b); - rolling_bloom_filter.insert(b); - const bool present = rolling_bloom_filter.contains(b); - assert(present); - break; - } - case 1: { - const std::optional u256 = ConsumeDeserializable(fuzzed_data_provider); - if (!u256) { - break; - } - (void)rolling_bloom_filter.contains(*u256); - rolling_bloom_filter.insert(*u256); - const bool present = rolling_bloom_filter.contains(*u256); - assert(present); - break; - } - case 2: - rolling_bloom_filter.reset(); - break; - } + CallOneOf( + fuzzed_data_provider, + [&] { + const std::vector b = ConsumeRandomLengthByteVector(fuzzed_data_provider); + (void)rolling_bloom_filter.contains(b); + rolling_bloom_filter.insert(b); + const bool present = rolling_bloom_filter.contains(b); + assert(present); + }, + [&] { + const std::optional u256 = ConsumeDeserializable(fuzzed_data_provider); + if (!u256) { + return; + } + (void)rolling_bloom_filter.contains(*u256); + rolling_bloom_filter.insert(*u256); + const bool present = rolling_bloom_filter.contains(*u256); + assert(present); + }, + [&] { + rolling_bloom_filter.reset(); + }); } } diff --git a/src/test/fuzz/script_ops.cpp b/src/test/fuzz/script_ops.cpp index 501e0c8ced90..569e85332652 100644 --- a/src/test/fuzz/script_ops.cpp +++ b/src/test/fuzz/script_ops.cpp @@ -16,49 +16,46 @@ FUZZ_TARGET(script_ops) FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); CScript script = ConsumeScript(fuzzed_data_provider); while (fuzzed_data_provider.remaining_bytes() > 0) { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 7)) { - case 0: { - CScript s = ConsumeScript(fuzzed_data_provider); - script = std::move(s); - break; - } - case 1: { - const CScript& s = ConsumeScript(fuzzed_data_provider); - script = s; - break; - } - case 2: - script << fuzzed_data_provider.ConsumeIntegral(); - break; - case 3: - script << ConsumeOpcodeType(fuzzed_data_provider); - break; - case 4: - script << ConsumeScriptNum(fuzzed_data_provider); - break; - case 5: - script << ConsumeRandomLengthByteVector(fuzzed_data_provider); - break; - case 6: - script.clear(); - break; - case 7: { - (void)script.GetSigOpCount(false); - (void)script.GetSigOpCount(true); - (void)script.GetSigOpCount(script); - (void)script.IsPayToScriptHash(); - (void)script.IsPushOnly(); - (void)script.IsUnspendable(); - { - CScript::const_iterator pc = script.begin(); - opcodetype opcode; - (void)script.GetOp(pc, opcode); - std::vector data; - (void)script.GetOp(pc, opcode, data); - (void)script.IsPushOnly(pc); - } - break; - } - } + CallOneOf( + fuzzed_data_provider, + [&] { + CScript s = ConsumeScript(fuzzed_data_provider); + script = std::move(s); + }, + [&] { + const CScript& s = ConsumeScript(fuzzed_data_provider); + script = s; + }, + [&] { + script << fuzzed_data_provider.ConsumeIntegral(); + }, + [&] { + script << ConsumeOpcodeType(fuzzed_data_provider); + }, + [&] { + script << ConsumeScriptNum(fuzzed_data_provider); + }, + [&] { + script << ConsumeRandomLengthByteVector(fuzzed_data_provider); + }, + [&] { + script.clear(); + }, + [&] { + (void)script.GetSigOpCount(false); + (void)script.GetSigOpCount(true); + (void)script.GetSigOpCount(script); + (void)script.IsPayToScriptHash(); + (void)script.IsPushOnly(); + (void)script.IsUnspendable(); + { + CScript::const_iterator pc = script.begin(); + opcodetype opcode; + (void)script.GetOp(pc, opcode); + std::vector data; + (void)script.GetOp(pc, opcode, data); + (void)script.IsPushOnly(pc); + } + }); } } diff --git a/src/test/fuzz/scriptnum_ops.cpp b/src/test/fuzz/scriptnum_ops.cpp index fa5605f7578e..e112c894b531 100644 --- a/src/test/fuzz/scriptnum_ops.cpp +++ b/src/test/fuzz/scriptnum_ops.cpp @@ -29,105 +29,99 @@ FUZZ_TARGET(scriptnum_ops) FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); CScriptNum script_num = ConsumeScriptNum(fuzzed_data_provider); while (fuzzed_data_provider.remaining_bytes() > 0) { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 11)) { - case 0: { - const int64_t i = fuzzed_data_provider.ConsumeIntegral(); - assert((script_num == i) != (script_num != i)); - assert((script_num <= i) != (script_num > i)); - assert((script_num >= i) != (script_num < i)); - // Avoid signed integer overflow: - // script/script.h:264:93: runtime error: signed integer overflow: -2261405121394637306 + -9223372036854775802 cannot be represented in type 'long' - if (IsValidAddition(script_num, CScriptNum{i})) { - assert((script_num + i) - i == script_num); - } - // Avoid signed integer overflow: - // script/script.h:265:93: runtime error: signed integer overflow: 9223371895120855039 - -9223372036854710486 cannot be represented in type 'long' - if (IsValidSubtraction(script_num, CScriptNum{i})) { - assert((script_num - i) + i == script_num); - } - break; - } - case 1: { - const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider); - assert((script_num == random_script_num) != (script_num != random_script_num)); - assert((script_num <= random_script_num) != (script_num > random_script_num)); - assert((script_num >= random_script_num) != (script_num < random_script_num)); - // Avoid signed integer overflow: - // script/script.h:264:93: runtime error: signed integer overflow: -9223126527765971126 + -9223372036854756825 cannot be represented in type 'long' - if (IsValidAddition(script_num, random_script_num)) { - assert((script_num + random_script_num) - random_script_num == script_num); - } - // Avoid signed integer overflow: - // script/script.h:265:93: runtime error: signed integer overflow: 6052837899185946624 - -9223372036854775808 cannot be represented in type 'long' - if (IsValidSubtraction(script_num, random_script_num)) { - assert((script_num - random_script_num) + random_script_num == script_num); - } - break; - } - case 2: { - const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider); - if (!IsValidAddition(script_num, random_script_num)) { - // Avoid assertion failure: - // ./script/script.h:292: CScriptNum &CScriptNum::operator+=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits::max() - rhs) || (rhs < 0 && m_value >= std::numeric_limits::min() - rhs)' failed. - break; - } - script_num += random_script_num; - break; - } - case 3: { - const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider); - if (!IsValidSubtraction(script_num, random_script_num)) { - // Avoid assertion failure: - // ./script/script.h:300: CScriptNum &CScriptNum::operator-=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits::min() + rhs) || (rhs < 0 && m_value <= std::numeric_limits::max() + rhs)' failed. - break; - } - script_num -= random_script_num; - break; - } - case 4: - script_num = script_num & fuzzed_data_provider.ConsumeIntegral(); - break; - case 5: - script_num = script_num & ConsumeScriptNum(fuzzed_data_provider); - break; - case 6: - script_num &= ConsumeScriptNum(fuzzed_data_provider); - break; - case 7: - if (script_num == CScriptNum{std::numeric_limits::min()}) { - // Avoid assertion failure: - // ./script/script.h:279: CScriptNum CScriptNum::operator-() const: Assertion `m_value != std::numeric_limits::min()' failed. - break; - } - script_num = -script_num; - break; - case 8: - script_num = fuzzed_data_provider.ConsumeIntegral(); - break; - case 9: { - const int64_t random_integer = fuzzed_data_provider.ConsumeIntegral(); - if (!IsValidAddition(script_num, CScriptNum{random_integer})) { - // Avoid assertion failure: - // ./script/script.h:292: CScriptNum &CScriptNum::operator+=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits::max() - rhs) || (rhs < 0 && m_value >= std::numeric_limits::min() - rhs)' failed. - break; - } - script_num += random_integer; - break; - } - case 10: { - const int64_t random_integer = fuzzed_data_provider.ConsumeIntegral(); - if (!IsValidSubtraction(script_num, CScriptNum{random_integer})) { - // Avoid assertion failure: - // ./script/script.h:300: CScriptNum &CScriptNum::operator-=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits::min() + rhs) || (rhs < 0 && m_value <= std::numeric_limits::max() + rhs)' failed. - break; - } - script_num -= random_integer; - break; - } - case 11: - script_num &= fuzzed_data_provider.ConsumeIntegral(); - break; - } + CallOneOf( + fuzzed_data_provider, + [&] { + const int64_t i = fuzzed_data_provider.ConsumeIntegral(); + assert((script_num == i) != (script_num != i)); + assert((script_num <= i) != (script_num > i)); + assert((script_num >= i) != (script_num < i)); + // Avoid signed integer overflow: + // script/script.h:264:93: runtime error: signed integer overflow: -2261405121394637306 + -9223372036854775802 cannot be represented in type 'long' + if (IsValidAddition(script_num, CScriptNum{i})) { + assert((script_num + i) - i == script_num); + } + // Avoid signed integer overflow: + // script/script.h:265:93: runtime error: signed integer overflow: 9223371895120855039 - -9223372036854710486 cannot be represented in type 'long' + if (IsValidSubtraction(script_num, CScriptNum{i})) { + assert((script_num - i) + i == script_num); + } + }, + [&] { + const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider); + assert((script_num == random_script_num) != (script_num != random_script_num)); + assert((script_num <= random_script_num) != (script_num > random_script_num)); + assert((script_num >= random_script_num) != (script_num < random_script_num)); + // Avoid signed integer overflow: + // script/script.h:264:93: runtime error: signed integer overflow: -9223126527765971126 + -9223372036854756825 cannot be represented in type 'long' + if (IsValidAddition(script_num, random_script_num)) { + assert((script_num + random_script_num) - random_script_num == script_num); + } + // Avoid signed integer overflow: + // script/script.h:265:93: runtime error: signed integer overflow: 6052837899185946624 - -9223372036854775808 cannot be represented in type 'long' + if (IsValidSubtraction(script_num, random_script_num)) { + assert((script_num - random_script_num) + random_script_num == script_num); + } + }, + [&] { + const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider); + if (!IsValidAddition(script_num, random_script_num)) { + // Avoid assertion failure: + // ./script/script.h:292: CScriptNum &CScriptNum::operator+=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits::max() - rhs) || (rhs < 0 && m_value >= std::numeric_limits::min() - rhs)' failed. + return; + } + script_num += random_script_num; + }, + [&] { + const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider); + if (!IsValidSubtraction(script_num, random_script_num)) { + // Avoid assertion failure: + // ./script/script.h:300: CScriptNum &CScriptNum::operator-=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits::min() + rhs) || (rhs < 0 && m_value <= std::numeric_limits::max() + rhs)' failed. + return; + } + script_num -= random_script_num; + }, + [&] { + script_num = script_num & fuzzed_data_provider.ConsumeIntegral(); + }, + [&] { + script_num = script_num & ConsumeScriptNum(fuzzed_data_provider); + }, + [&] { + script_num &= ConsumeScriptNum(fuzzed_data_provider); + }, + [&] { + if (script_num == CScriptNum{std::numeric_limits::min()}) { + // Avoid assertion failure: + // ./script/script.h:279: CScriptNum CScriptNum::operator-() const: Assertion `m_value != std::numeric_limits::min()' failed. + return; + } + script_num = -script_num; + }, + [&] { + script_num = fuzzed_data_provider.ConsumeIntegral(); + }, + [&] { + const int64_t random_integer = fuzzed_data_provider.ConsumeIntegral(); + if (!IsValidAddition(script_num, CScriptNum{random_integer})) { + // Avoid assertion failure: + // ./script/script.h:292: CScriptNum &CScriptNum::operator+=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits::max() - rhs) || (rhs < 0 && m_value >= std::numeric_limits::min() - rhs)' failed. + return; + } + script_num += random_integer; + }, + [&] { + const int64_t random_integer = fuzzed_data_provider.ConsumeIntegral(); + if (!IsValidSubtraction(script_num, CScriptNum{random_integer})) { + // Avoid assertion failure: + // ./script/script.h:300: CScriptNum &CScriptNum::operator-=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits::min() + rhs) || (rhs < 0 && m_value <= std::numeric_limits::max() + rhs)' failed. + return; + } + script_num -= random_integer; + }, + [&] { + script_num &= fuzzed_data_provider.ConsumeIntegral(); + }); (void)script_num.getint(); // Avoid negation failure: // script/script.h:332:35: runtime error: negation of -9223372036854775808 cannot be represented in type 'int64_t' (aka 'long'); cast to an unsigned type to negate this value to itself diff --git a/src/test/fuzz/strprintf.cpp b/src/test/fuzz/strprintf.cpp index 4af0e750ceb0..b66a7abfb317 100644 --- a/src/test/fuzz/strprintf.cpp +++ b/src/test/fuzz/strprintf.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -109,32 +110,32 @@ FUZZ_TARGET(str_printf) } try { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 5)) { - case 0: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32)); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeRandomLengthString(32)); - break; - case 1: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str()); - break; - case 2: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral()); - break; - case 3: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral()); - break; - case 4: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral()); - break; - case 5: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeBool()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeBool()); - break; - } + CallOneOf( + fuzzed_data_provider, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32)); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeRandomLengthString(32)); + }, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str()); + }, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral()); + }, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral()); + }, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral()); + }, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeBool()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeBool()); + }); } catch (const tinyformat::format_error&) { } @@ -155,40 +156,40 @@ FUZZ_TARGET(str_printf) } try { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 7)) { - case 0: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeFloatingPoint()); - break; - case 1: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeFloatingPoint()); - break; - case 2: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral()); - break; - case 3: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral()); - break; - case 4: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral()); - break; - case 5: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral()); - break; - case 6: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral()); - break; - case 7: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral()); - break; - } + CallOneOf( + fuzzed_data_provider, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeFloatingPoint()); + }, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeFloatingPoint()); + }, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral()); + }, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral()); + }, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral()); + }, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral()); + }, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral()); + }, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral()); + }); } catch (const tinyformat::format_error&) { } } diff --git a/src/test/fuzz/system.cpp b/src/test/fuzz/system.cpp index 70f616ed979f..274a71d8ab3e 100644 --- a/src/test/fuzz/system.cpp +++ b/src/test/fuzz/system.cpp @@ -32,71 +32,63 @@ FUZZ_TARGET(system) } while (fuzzed_data_provider.ConsumeBool()) { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 7)) { - case 0: { - args_manager.SelectConfigNetwork(fuzzed_data_provider.ConsumeRandomLengthString(16)); - break; - } - case 1: { - args_manager.SoftSetArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeRandomLengthString(16)); - break; - } - case 2: { - args_manager.ForceSetArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeRandomLengthString(16)); - break; - } - case 3: { - args_manager.SoftSetBoolArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeBool()); - break; - } - case 4: { - const OptionsCategory options_category = fuzzed_data_provider.PickValueInArray({OptionsCategory::OPTIONS, OptionsCategory::CONNECTION, OptionsCategory::WALLET, OptionsCategory::WALLET_DEBUG_TEST, OptionsCategory::ZMQ, OptionsCategory::DEBUG_TEST, OptionsCategory::CHAINPARAMS, OptionsCategory::NODE_RELAY, OptionsCategory::BLOCK_CREATION, OptionsCategory::RPC, OptionsCategory::GUI, OptionsCategory::COMMANDS, OptionsCategory::REGISTER_COMMANDS, OptionsCategory::HIDDEN}); - // Avoid hitting: - // util/system.cpp:425: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed. - const std::string argument_name = GetArgumentName(fuzzed_data_provider.ConsumeRandomLengthString(16)); - if (args_manager.GetArgFlags(argument_name)) { - break; - } - args_manager.AddArg(argument_name, fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeIntegral(), options_category); - break; - } - case 5: { - // Avoid hitting: - // util/system.cpp:425: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed. - const std::vector names = ConsumeRandomLengthStringVector(fuzzed_data_provider); - std::vector hidden_arguments; - for (const std::string& name : names) { - const std::string hidden_argument = GetArgumentName(name); - if (args_manager.GetArgFlags(hidden_argument)) { - continue; + CallOneOf( + fuzzed_data_provider, + [&] { + args_manager.SelectConfigNetwork(fuzzed_data_provider.ConsumeRandomLengthString(16)); + }, + [&] { + args_manager.SoftSetArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeRandomLengthString(16)); + }, + [&] { + args_manager.ForceSetArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeRandomLengthString(16)); + }, + [&] { + args_manager.SoftSetBoolArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeBool()); + }, + [&] { + const OptionsCategory options_category = fuzzed_data_provider.PickValueInArray({OptionsCategory::OPTIONS, OptionsCategory::CONNECTION, OptionsCategory::WALLET, OptionsCategory::WALLET_DEBUG_TEST, OptionsCategory::ZMQ, OptionsCategory::DEBUG_TEST, OptionsCategory::CHAINPARAMS, OptionsCategory::NODE_RELAY, OptionsCategory::BLOCK_CREATION, OptionsCategory::RPC, OptionsCategory::GUI, OptionsCategory::COMMANDS, OptionsCategory::REGISTER_COMMANDS, OptionsCategory::HIDDEN}); + // Avoid hitting: + // util/system.cpp:425: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed. + const std::string argument_name = GetArgumentName(fuzzed_data_provider.ConsumeRandomLengthString(16)); + if (args_manager.GetArgFlags(argument_name) != std::nullopt) { + return; } - if (std::find(hidden_arguments.begin(), hidden_arguments.end(), hidden_argument) != hidden_arguments.end()) { - continue; + args_manager.AddArg(argument_name, fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeIntegral(), options_category); + }, + [&] { + // Avoid hitting: + // util/system.cpp:425: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed. + const std::vector names = ConsumeRandomLengthStringVector(fuzzed_data_provider); + std::vector hidden_arguments; + for (const std::string& name : names) { + const std::string hidden_argument = GetArgumentName(name); + if (args_manager.GetArgFlags(hidden_argument) != std::nullopt) { + continue; + } + if (std::find(hidden_arguments.begin(), hidden_arguments.end(), hidden_argument) != hidden_arguments.end()) { + continue; + } + hidden_arguments.push_back(hidden_argument); } - hidden_arguments.push_back(hidden_argument); - } - args_manager.AddHiddenArgs(hidden_arguments); - break; - } - case 6: { - args_manager.ClearArgs(); - break; - } - case 7: { - const std::vector random_arguments = ConsumeRandomLengthStringVector(fuzzed_data_provider); - std::vector argv; - argv.reserve(random_arguments.size()); - for (const std::string& random_argument : random_arguments) { - argv.push_back(random_argument.c_str()); - } - try { - std::string error; - (void)args_manager.ParseParameters(argv.size(), argv.data(), error); - } catch (const std::logic_error&) { - } - break; - } - } + args_manager.AddHiddenArgs(hidden_arguments); + }, + [&] { + args_manager.ClearArgs(); + }, + [&] { + const std::vector random_arguments = ConsumeRandomLengthStringVector(fuzzed_data_provider); + std::vector argv; + argv.reserve(random_arguments.size()); + for (const std::string& random_argument : random_arguments) { + argv.push_back(random_argument.c_str()); + } + try { + std::string error; + (void)args_manager.ParseParameters(argv.size(), argv.data(), error); + } catch (const std::logic_error&) { + } + }); } const std::string s1 = fuzzed_data_provider.ConsumeRandomLengthString(16); diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h index c5ddecddf64e..0038fd27e4f5 100644 --- a/src/test/fuzz/util.h +++ b/src/test/fuzz/util.h @@ -36,6 +36,17 @@ #include #include +template +void CallOneOf(FuzzedDataProvider& fuzzed_data_provider, Callables... callables) +{ + constexpr size_t call_size{sizeof...(callables)}; + static_assert(call_size >= 1); + const size_t call_index{fuzzed_data_provider.ConsumeIntegralInRange(0, call_size - 1)}; + + size_t i{0}; + return ((i++ == call_index ? callables() : void()), ...); +} + [[ nodiscard ]] inline std::vector ConsumeRandomLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept { const std::string s = fuzzed_data_provider.ConsumeRandomLengthString(max_length); @@ -157,20 +168,17 @@ template [[ nodiscard ]] inline CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) noexcept { CTxDestination tx_destination; - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 2)) { - case 0: { - tx_destination = CNoDestination{}; - break; - } - case 1: { - tx_destination = PKHash{ConsumeUInt160(fuzzed_data_provider)}; - break; - } - case 2: { - tx_destination = ScriptHash{ConsumeUInt160(fuzzed_data_provider)}; - break; - } - } + CallOneOf( + fuzzed_data_provider, + [&] { + tx_destination = CNoDestination{}; + }, + [&] { + tx_destination = PKHash{ConsumeUInt160(fuzzed_data_provider)}; + }, + [&] { + tx_destination = ScriptHash{ConsumeUInt160(fuzzed_data_provider)}; + }); return tx_destination; } @@ -316,32 +324,26 @@ class FuzzedFileProvider return nullptr; } std::string mode; - switch (m_fuzzed_data_provider.ConsumeIntegralInRange(0, 5)) { - case 0: { - mode = "r"; - break; - } - case 1: { - mode = "r+"; - break; - } - case 2: { - mode = "w"; - break; - } - case 3: { - mode = "w+"; - break; - } - case 4: { - mode = "a"; - break; - } - case 5: { - mode = "a+"; - break; - } - } + CallOneOf( + m_fuzzed_data_provider, + [&] { + mode = "r"; + }, + [&] { + mode = "r+"; + }, + [&] { + mode = "w"; + }, + [&] { + mode = "w+"; + }, + [&] { + mode = "a"; + }, + [&] { + mode = "a+"; + }); #ifdef _GNU_SOURCE const cookie_io_functions_t io_hooks = { FuzzedFileProvider::read, @@ -439,66 +441,64 @@ class FuzzedAutoFileProvider return {fuzzed_data_provider}; } -#define WRITE_TO_STREAM_CASE(id, type, consume) \ - case id: { \ - type o = consume; \ - stream << o; \ - break; \ +#define WRITE_TO_STREAM_CASE(type, consume) \ + [&] { \ + type o = consume; \ + stream << o; \ } template void WriteToStream(FuzzedDataProvider& fuzzed_data_provider, Stream& stream) noexcept { while (fuzzed_data_provider.ConsumeBool()) { try { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 13)) { - WRITE_TO_STREAM_CASE(0, bool, fuzzed_data_provider.ConsumeBool()) - WRITE_TO_STREAM_CASE(1, char, fuzzed_data_provider.ConsumeIntegral()) - WRITE_TO_STREAM_CASE(2, int8_t, fuzzed_data_provider.ConsumeIntegral()) - WRITE_TO_STREAM_CASE(3, uint8_t, fuzzed_data_provider.ConsumeIntegral()) - WRITE_TO_STREAM_CASE(4, int16_t, fuzzed_data_provider.ConsumeIntegral()) - WRITE_TO_STREAM_CASE(5, uint16_t, fuzzed_data_provider.ConsumeIntegral()) - WRITE_TO_STREAM_CASE(6, int32_t, fuzzed_data_provider.ConsumeIntegral()) - WRITE_TO_STREAM_CASE(7, uint32_t, fuzzed_data_provider.ConsumeIntegral()) - WRITE_TO_STREAM_CASE(8, int64_t, fuzzed_data_provider.ConsumeIntegral()) - WRITE_TO_STREAM_CASE(9, uint64_t, fuzzed_data_provider.ConsumeIntegral()) - WRITE_TO_STREAM_CASE(10, float, fuzzed_data_provider.ConsumeFloatingPoint()) - WRITE_TO_STREAM_CASE(11, double, fuzzed_data_provider.ConsumeFloatingPoint()) - WRITE_TO_STREAM_CASE(12, std::string, fuzzed_data_provider.ConsumeRandomLengthString(32)) - WRITE_TO_STREAM_CASE(13, std::vector, ConsumeRandomLengthIntegralVector(fuzzed_data_provider)) - } + CallOneOf( + fuzzed_data_provider, + WRITE_TO_STREAM_CASE(bool, fuzzed_data_provider.ConsumeBool()), + WRITE_TO_STREAM_CASE(char, fuzzed_data_provider.ConsumeIntegral()), + WRITE_TO_STREAM_CASE(int8_t, fuzzed_data_provider.ConsumeIntegral()), + WRITE_TO_STREAM_CASE(uint8_t, fuzzed_data_provider.ConsumeIntegral()), + WRITE_TO_STREAM_CASE(int16_t, fuzzed_data_provider.ConsumeIntegral()), + WRITE_TO_STREAM_CASE(uint16_t, fuzzed_data_provider.ConsumeIntegral()), + WRITE_TO_STREAM_CASE(int32_t, fuzzed_data_provider.ConsumeIntegral()), + WRITE_TO_STREAM_CASE(uint32_t, fuzzed_data_provider.ConsumeIntegral()), + WRITE_TO_STREAM_CASE(int64_t, fuzzed_data_provider.ConsumeIntegral()), + WRITE_TO_STREAM_CASE(uint64_t, fuzzed_data_provider.ConsumeIntegral()), + WRITE_TO_STREAM_CASE(float, fuzzed_data_provider.ConsumeFloatingPoint()), + WRITE_TO_STREAM_CASE(double, fuzzed_data_provider.ConsumeFloatingPoint()), + WRITE_TO_STREAM_CASE(std::string, fuzzed_data_provider.ConsumeRandomLengthString(32)), + WRITE_TO_STREAM_CASE(std::vector, ConsumeRandomLengthIntegralVector(fuzzed_data_provider))); } catch (const std::ios_base::failure&) { break; } } } -#define READ_FROM_STREAM_CASE(id, type) \ - case id: { \ - type o; \ - stream >> o; \ - break; \ +#define READ_FROM_STREAM_CASE(type) \ + [&] { \ + type o; \ + stream >> o; \ } template void ReadFromStream(FuzzedDataProvider& fuzzed_data_provider, Stream& stream) noexcept { while (fuzzed_data_provider.ConsumeBool()) { try { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 13)) { - READ_FROM_STREAM_CASE(0, bool) - READ_FROM_STREAM_CASE(1, char) - READ_FROM_STREAM_CASE(2, int8_t) - READ_FROM_STREAM_CASE(3, uint8_t) - READ_FROM_STREAM_CASE(4, int16_t) - READ_FROM_STREAM_CASE(5, uint16_t) - READ_FROM_STREAM_CASE(6, int32_t) - READ_FROM_STREAM_CASE(7, uint32_t) - READ_FROM_STREAM_CASE(8, int64_t) - READ_FROM_STREAM_CASE(9, uint64_t) - READ_FROM_STREAM_CASE(10, float) - READ_FROM_STREAM_CASE(11, double) - READ_FROM_STREAM_CASE(12, std::string) - READ_FROM_STREAM_CASE(13, std::vector) - } + CallOneOf( + fuzzed_data_provider, + READ_FROM_STREAM_CASE(bool), + READ_FROM_STREAM_CASE(char), + READ_FROM_STREAM_CASE(int8_t), + READ_FROM_STREAM_CASE(uint8_t), + READ_FROM_STREAM_CASE(int16_t), + READ_FROM_STREAM_CASE(uint16_t), + READ_FROM_STREAM_CASE(int32_t), + READ_FROM_STREAM_CASE(uint32_t), + READ_FROM_STREAM_CASE(int64_t), + READ_FROM_STREAM_CASE(uint64_t), + READ_FROM_STREAM_CASE(float), + READ_FROM_STREAM_CASE(double), + READ_FROM_STREAM_CASE(std::string), + READ_FROM_STREAM_CASE(std::vector)); } catch (const std::ios_base::failure&) { break; } From 3eb89314da1473ec5cd9cbcfe3f01572241eb7e5 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kittywhiskers@users.noreply.github.com> Date: Thu, 16 Mar 2023 08:44:21 +0000 Subject: [PATCH 30/35] fuzz: remove unused variable in script_bitcoin_consensus --- src/test/fuzz/script_bitcoin_consensus.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/fuzz/script_bitcoin_consensus.cpp b/src/test/fuzz/script_bitcoin_consensus.cpp index 94ee91d9da23..f2ab1a2ebb57 100644 --- a/src/test/fuzz/script_bitcoin_consensus.cpp +++ b/src/test/fuzz/script_bitcoin_consensus.cpp @@ -17,7 +17,6 @@ FUZZ_TARGET(script_bitcoin_consensus) FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const std::vector random_bytes_1 = ConsumeRandomLengthByteVector(fuzzed_data_provider); const std::vector random_bytes_2 = ConsumeRandomLengthByteVector(fuzzed_data_provider); - const CAmount money = ConsumeMoney(fuzzed_data_provider); dashconsensus_error err; dashconsensus_error* err_p = fuzzed_data_provider.ConsumeBool() ? &err : nullptr; const unsigned int n_in = fuzzed_data_provider.ConsumeIntegral(); From 9d55bd8d1c3aa1f693a72240eca5d256c8376586 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kittywhiskers@users.noreply.github.com> Date: Mon, 27 Mar 2023 14:51:49 +0000 Subject: [PATCH 31/35] merge bitcoin#20749: Prune g_chainman usage related to ::LookupBlockIndex --- src/evo/mnhftx.cpp | 2 +- src/evo/simplifiedmns.cpp | 4 +- src/governance/object.cpp | 4 +- src/index/base.cpp | 4 +- src/init.cpp | 8 +- src/interfaces/chain.cpp | 10 +- src/llmq/blockprocessor.cpp | 6 +- src/llmq/chainlocks.cpp | 10 +- src/llmq/commitment.cpp | 2 +- src/llmq/debug.cpp | 2 +- src/llmq/dkgsessionhandler.cpp | 2 +- src/llmq/dkgsessionmgr.cpp | 4 +- src/llmq/instantsend.cpp | 12 +-- src/llmq/quorums.cpp | 4 +- src/llmq/snapshot.cpp | 4 +- src/miner.cpp | 2 +- src/net_processing.cpp | 36 +++---- src/node/coinstats.cpp | 2 +- src/rest.cpp | 4 +- src/rpc/blockchain.cpp | 32 +++---- src/rpc/masternode.cpp | 2 +- src/rpc/mining.cpp | 10 +- src/rpc/quorums.cpp | 6 +- src/rpc/rawtransaction.cpp | 10 +- src/test/blockfilter_index_tests.cpp | 10 +- src/test/fuzz/load_external_block_file.cpp | 2 +- src/test/util/setup_common.cpp | 2 +- src/txmempool.cpp | 2 +- src/validation.cpp | 103 +++++++++++++-------- src/validation.h | 70 +++++++------- 30 files changed, 199 insertions(+), 172 deletions(-) diff --git a/src/evo/mnhftx.cpp b/src/evo/mnhftx.cpp index d3b86dc4beed..81b931016730 100644 --- a/src/evo/mnhftx.cpp +++ b/src/evo/mnhftx.cpp @@ -45,7 +45,7 @@ bool CheckMNHFTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidat return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-version"); } - const CBlockIndex* pindexQuorum = LookupBlockIndex(mnhfTx.signal.quorumHash); + const CBlockIndex* pindexQuorum = g_chainman.m_blockman.LookupBlockIndex(mnhfTx.signal.quorumHash); if (!pindexQuorum) { return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-quorum-hash"); } diff --git a/src/evo/simplifiedmns.cpp b/src/evo/simplifiedmns.cpp index 202396047e3f..f1f378e58f0b 100644 --- a/src/evo/simplifiedmns.cpp +++ b/src/evo/simplifiedmns.cpp @@ -243,14 +243,14 @@ bool BuildSimplifiedMNListDiff(const uint256& baseBlockHash, const uint256& bloc const CBlockIndex* baseBlockIndex = ::ChainActive().Genesis(); if (!baseBlockHash.IsNull()) { - baseBlockIndex = LookupBlockIndex(baseBlockHash); + baseBlockIndex = g_chainman.m_blockman.LookupBlockIndex(baseBlockHash); if (!baseBlockIndex) { errorRet = strprintf("block %s not found", baseBlockHash.ToString()); return false; } } - const CBlockIndex* blockIndex = LookupBlockIndex(blockHash); + const CBlockIndex* blockIndex = g_chainman.m_blockman.LookupBlockIndex(blockHash); if (!blockIndex) { errorRet = strprintf("block %s not found", blockHash.ToString()); return false; diff --git a/src/governance/object.cpp b/src/governance/object.cpp index 61b104335592..b05ddd1446c6 100644 --- a/src/governance/object.cpp +++ b/src/governance/object.cpp @@ -563,7 +563,7 @@ bool CGovernanceObject::IsCollateralValid(std::string& strError, bool& fMissingC findScript << OP_RETURN << ToByteVector(nExpectedHash); AssertLockHeld(cs_main); - bool fork_active = VersionBitsState(LookupBlockIndex(nBlockHash), Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024, versionbitscache) == ThresholdState::ACTIVE; + bool fork_active = VersionBitsState(g_chainman.m_blockman.LookupBlockIndex(nBlockHash), Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024, versionbitscache) == ThresholdState::ACTIVE; CAmount nMinFee = GetMinCollateralFee(fork_active); LogPrint(BCLog::GOBJECT, "CGovernanceObject::IsCollateralValid -- txCollateral->vout.size() = %s, findScript = %s, nMinFee = %lld\n", @@ -594,7 +594,7 @@ bool CGovernanceObject::IsCollateralValid(std::string& strError, bool& fMissingC AssertLockHeld(cs_main); int nConfirmationsIn = 0; if (nBlockHash != uint256()) { - const CBlockIndex* pindex = LookupBlockIndex(nBlockHash); + const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(nBlockHash); if (pindex && ::ChainActive().Contains(pindex)) { nConfirmationsIn += ::ChainActive().Height() - pindex->nHeight + 1; } diff --git a/src/index/base.cpp b/src/index/base.cpp index 2eaacc1f6eeb..c8fd962a186c 100644 --- a/src/index/base.cpp +++ b/src/index/base.cpp @@ -61,7 +61,7 @@ bool BaseIndex::Init() if (locator.IsNull()) { m_best_block_index = nullptr; } else { - m_best_block_index = FindForkInGlobalIndex(::ChainActive(), locator); + m_best_block_index = g_chainman.m_blockman.FindForkInGlobalIndex(::ChainActive(), locator); } m_synced = m_best_block_index.load() == ::ChainActive().Tip(); return true; @@ -238,7 +238,7 @@ void BaseIndex::ChainStateFlushed(const CBlockLocator& locator) const CBlockIndex* locator_tip_index; { LOCK(cs_main); - locator_tip_index = LookupBlockIndex(locator_tip_hash); + locator_tip_index = g_chainman.m_blockman.LookupBlockIndex(locator_tip_hash); } if (!locator_tip_index) { diff --git a/src/init.cpp b/src/init.cpp index cb2614a2b835..c0ac35e21831 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -893,7 +893,7 @@ static void ThreadImport(ChainstateManager& chainman, std::vector vImp if (!file) break; // This error is logged in OpenBlockFile LogPrintf("Reindexing block file blk%05u.dat...\n", (unsigned int)nFile); - LoadExternalBlockFile(chainparams, file, &pos); + ::ChainstateActive().LoadExternalBlockFile(chainparams, file, &pos); if (ShutdownRequested()) { LogPrintf("Shutdown requested. Exit %s\n", __func__); return; @@ -912,7 +912,7 @@ static void ThreadImport(ChainstateManager& chainman, std::vector vImp FILE *file = fsbridge::fopen(path, "rb"); if (file) { LogPrintf("Importing blocks file %s...\n", path.string()); - LoadExternalBlockFile(chainparams, file); + ::ChainstateActive().LoadExternalBlockFile(chainparams, file); if (ShutdownRequested()) { LogPrintf("Shutdown requested. Exit %s\n", __func__); return; @@ -2056,12 +2056,12 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc // If the loaded chain has a wrong genesis, bail out immediately // (we're likely using a testnet datadir, or the other way around). if (!chainman.BlockIndex().empty() && - !LookupBlockIndex(chainparams.GetConsensus().hashGenesisBlock)) { + !g_chainman.m_blockman.LookupBlockIndex(chainparams.GetConsensus().hashGenesisBlock)) { return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?")); } if (!chainparams.GetConsensus().hashDevnetGenesisBlock.IsNull() && !chainman.BlockIndex().empty() && - !LookupBlockIndex(chainparams.GetConsensus().hashDevnetGenesisBlock)) { + !g_chainman.m_blockman.LookupBlockIndex(chainparams.GetConsensus().hashDevnetGenesisBlock)) { return InitError(_("Incorrect or no devnet genesis block found. Wrong datadir for devnet specified?")); } diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp index 3d745d4928c8..c8ae63cb2f89 100644 --- a/src/interfaces/chain.cpp +++ b/src/interfaces/chain.cpp @@ -149,7 +149,7 @@ class ChainImpl : public Chain std::optional getBlockHeight(const uint256& hash) override { LOCK(::cs_main); - CBlockIndex* block = LookupBlockIndex(hash); + CBlockIndex* block = g_chainman.m_blockman.LookupBlockIndex(hash); if (block && ::ChainActive().Contains(block)) { return block->nHeight; } @@ -209,7 +209,7 @@ class ChainImpl : public Chain std::optional findFork(const uint256& hash, std::optional* height) override { LOCK(cs_main); - const CBlockIndex* block = LookupBlockIndex(hash); + const CBlockIndex* block = g_chainman.m_blockman.LookupBlockIndex(hash); const CBlockIndex* fork = block ? ::ChainActive().FindFork(block) : nullptr; if (height) { if (block) { @@ -231,7 +231,7 @@ class ChainImpl : public Chain std::optional findLocatorFork(const CBlockLocator& locator) override { LOCK(cs_main); - if (CBlockIndex* fork = FindForkInGlobalIndex(::ChainActive(), locator)) { + if (CBlockIndex* fork = g_chainman.m_blockman.FindForkInGlobalIndex(::ChainActive(), locator)) { return fork->nHeight; } return std::nullopt; @@ -246,7 +246,7 @@ class ChainImpl : public Chain CBlockIndex* index; { LOCK(cs_main); - index = LookupBlockIndex(hash); + index = g_chainman.m_blockman.LookupBlockIndex(hash); if (!index) { return false; } @@ -266,7 +266,7 @@ class ChainImpl : public Chain double guessVerificationProgress(const uint256& block_hash) override { LOCK(cs_main); - return GuessVerificationProgress(Params().TxData(), LookupBlockIndex(block_hash)); + return GuessVerificationProgress(Params().TxData(), g_chainman.m_blockman.LookupBlockIndex(block_hash)); } bool hasDescendantsInMempool(const uint256& txid) override { diff --git a/src/llmq/blockprocessor.cpp b/src/llmq/blockprocessor.cpp index 14580500ff7b..0e5f4943991e 100644 --- a/src/llmq/blockprocessor.cpp +++ b/src/llmq/blockprocessor.cpp @@ -72,7 +72,7 @@ void CQuorumBlockProcessor::ProcessMessage(const CNode& peer, std::string_view m const CBlockIndex* pQuorumBaseBlockIndex; { LOCK(cs_main); - pQuorumBaseBlockIndex = LookupBlockIndex(qc.quorumHash); + pQuorumBaseBlockIndex = g_chainman.m_blockman.LookupBlockIndex(qc.quorumHash); if (pQuorumBaseBlockIndex == nullptr) { LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- unknown block %s in commitment, peer=%d\n", __func__, qc.quorumHash.ToString(), peer.GetId()); @@ -261,7 +261,7 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-height"); } - const auto* pQuorumBaseBlockIndex = LookupBlockIndex(qc.quorumHash); + const auto* pQuorumBaseBlockIndex = g_chainman.m_blockman.LookupBlockIndex(qc.quorumHash); if (!qc.Verify(pQuorumBaseBlockIndex, fBLSChecks)) { LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s height=%d, type=%d, quorumIndex=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s qc verify failed.\n", __func__, @@ -386,7 +386,7 @@ bool CQuorumBlockProcessor::UpgradeDB() if (qc.IsNull()) { continue; } - const auto* pQuorumBaseBlockIndex = LookupBlockIndex(qc.quorumHash); + const auto* pQuorumBaseBlockIndex = g_chainman.m_blockman.LookupBlockIndex(qc.quorumHash); m_evoDb.GetRawDB().Write(std::make_pair(DB_MINED_COMMITMENT, std::make_pair(qc.llmqType, qc.quorumHash)), std::make_pair(qc, pindex->GetBlockHash())); const auto& llmq_params_opt = GetLLMQParams(qc.llmqType); assert(llmq_params_opt.has_value()); diff --git a/src/llmq/chainlocks.cpp b/src/llmq/chainlocks.cpp index 3ba96ec118f7..bcdb89d34840 100644 --- a/src/llmq/chainlocks.cpp +++ b/src/llmq/chainlocks.cpp @@ -130,7 +130,7 @@ void CChainLocksHandler::ProcessNewChainLock(const NodeId from, const llmq::CCha return; } - CBlockIndex* pindex = WITH_LOCK(cs_main, return LookupBlockIndex(clsig.getBlockHash())); + CBlockIndex* pindex = WITH_LOCK(cs_main, return g_chainman.m_blockman.LookupBlockIndex(clsig.getBlockHash())); { LOCK(cs); @@ -414,7 +414,7 @@ CChainLocksHandler::BlockTxs::mapped_type CChainLocksHandler::GetBlockTxs(const uint32_t blockTime; { LOCK(cs_main); - auto* pindex = LookupBlockIndex(blockHash); + auto* pindex = g_chainman.m_blockman.LookupBlockIndex(blockHash); CBlock block; if (!ReadBlockFromDisk(block, pindex, Params().GetConsensus())) { return nullptr; @@ -506,7 +506,7 @@ void CChainLocksHandler::EnforceBestChainLock() bool activateNeeded = WITH_LOCK(::cs_main, return ::ChainActive().Tip()->GetAncestor(currentBestChainLockBlockIndex->nHeight)) != currentBestChainLockBlockIndex; if (activateNeeded) { - if(!ActivateBestChain(state, params)) { + if (!::ChainstateActive().ActivateBestChain(state, params)) { LogPrintf("CChainLocksHandler::%s -- ActivateBestChain failed: %s\n", __func__, FormatStateMessage(state)); return; } @@ -638,7 +638,7 @@ void CChainLocksHandler::Cleanup() } for (auto it = blockTxs.begin(); it != blockTxs.end(); ) { - auto* pindex = LookupBlockIndex(it->first); + auto* pindex = g_chainman.m_blockman.LookupBlockIndex(it->first); if (InternalHasChainLock(pindex->nHeight, pindex->GetBlockHash())) { for (const auto& txid : *it->second) { txFirstSeenTime.erase(txid); @@ -657,7 +657,7 @@ void CChainLocksHandler::Cleanup() // tx has vanished, probably due to conflicts it = txFirstSeenTime.erase(it); } else if (!hashBlock.IsNull()) { - auto* pindex = LookupBlockIndex(hashBlock); + auto* pindex = g_chainman.m_blockman.LookupBlockIndex(hashBlock); if (::ChainActive().Tip()->GetAncestor(pindex->nHeight) == pindex && ::ChainActive().Height() - pindex->nHeight >= 6) { // tx got confirmed >= 6 times, so we can stop keeping track of it it = txFirstSeenTime.erase(it); diff --git a/src/llmq/commitment.cpp b/src/llmq/commitment.cpp index 91c1bb2db993..7d4718b02424 100644 --- a/src/llmq/commitment.cpp +++ b/src/llmq/commitment.cpp @@ -209,7 +209,7 @@ bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev, return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-height"); } - const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return LookupBlockIndex(qcTx.commitment.quorumHash)); + const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return g_chainman.m_blockman.LookupBlockIndex(qcTx.commitment.quorumHash)); if (pQuorumBaseBlockIndex == nullptr) { return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-quorum-hash"); } diff --git a/src/llmq/debug.cpp b/src/llmq/debug.cpp index 003b977e5acf..8f02c3d8d867 100644 --- a/src/llmq/debug.cpp +++ b/src/llmq/debug.cpp @@ -25,7 +25,7 @@ UniValue CDKGDebugSessionStatus::ToJson(int quorumIndex, int detailLevel) const std::vector dmnMembers; if (detailLevel == 2) { - const CBlockIndex* pindex = WITH_LOCK(cs_main, return LookupBlockIndex(quorumHash)); + const CBlockIndex* pindex = WITH_LOCK(cs_main, return g_chainman.m_blockman.LookupBlockIndex(quorumHash)); if (pindex != nullptr) { dmnMembers = utils::GetAllQuorumMembers(llmqType, pindex); } diff --git a/src/llmq/dkgsessionhandler.cpp b/src/llmq/dkgsessionhandler.cpp index db14b8bde9c2..e29b88c44ec3 100644 --- a/src/llmq/dkgsessionhandler.cpp +++ b/src/llmq/dkgsessionhandler.cpp @@ -491,7 +491,7 @@ void CDKGSessionHandler::HandleDKGRound() curQuorumHash = quorumHash; } - const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return LookupBlockIndex(curQuorumHash)); + const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return g_chainman.m_blockman.LookupBlockIndex(curQuorumHash)); if (!InitNewQuorum(pQuorumBaseBlockIndex)) { // should actually never happen diff --git a/src/llmq/dkgsessionmgr.cpp b/src/llmq/dkgsessionmgr.cpp index 943168992071..8cea880fa0b2 100644 --- a/src/llmq/dkgsessionmgr.cpp +++ b/src/llmq/dkgsessionmgr.cpp @@ -217,7 +217,7 @@ void CDKGSessionManager::ProcessMessage(CNode& pfrom, const CQuorumManager& quor // No luck, try to compute if (quorumIndex == -1) { - CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return LookupBlockIndex(quorumHash)); + CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return g_chainman.m_blockman.LookupBlockIndex(quorumHash)); if (pQuorumBaseBlockIndex == nullptr) { LogPrintf("CDKGSessionManager -- unknown quorumHash %s\n", quorumHash.ToString()); // NOTE: do not insta-ban for this, we might be lagging behind @@ -476,7 +476,7 @@ void CDKGSessionManager::CleanupOldContributions() const break; } cnt_all++; - const CBlockIndex* pindexQuorum = LookupBlockIndex(std::get<2>(k)); + const CBlockIndex* pindexQuorum = g_chainman.m_blockman.LookupBlockIndex(std::get<2>(k)); if (pindexQuorum == nullptr || ::ChainActive().Tip()->nHeight - pindexQuorum->nHeight > MAX_STORE_DEPTH) { // not found or too old batch.Erase(k); diff --git a/src/llmq/instantsend.cpp b/src/llmq/instantsend.cpp index 4d2540faec98..7ee02db87cee 100644 --- a/src/llmq/instantsend.cpp +++ b/src/llmq/instantsend.cpp @@ -619,7 +619,7 @@ bool CInstantSendManager::CheckCanLock(const COutPoint& outpoint, bool printDebu int nTxAge; { LOCK(cs_main); - pindexMined = LookupBlockIndex(hashBlock); + pindexMined = g_chainman.m_blockman.LookupBlockIndex(hashBlock); nTxAge = ::ChainActive().Height() - pindexMined->nHeight + 1; } @@ -796,7 +796,7 @@ void CInstantSendManager::ProcessMessageInstantSendLock(const CNode& pfrom, cons // Deterministic ISLocks are only produced by rotation quorums, if we don't see DIP24 as active, then we won't be able to validate it anyway if (islock->IsDeterministic() && fDIP0024IsActive) { - const auto blockIndex = WITH_LOCK(cs_main, return LookupBlockIndex(islock->cycleHash)); + const auto blockIndex = WITH_LOCK(cs_main, return g_chainman.m_blockman.LookupBlockIndex(islock->cycleHash)); if (blockIndex == nullptr) { // Maybe we don't have the block yet or maybe some peer spams invalid values for cycleHash Misbehaving(pfrom.GetId(), 1); @@ -967,7 +967,7 @@ std::unordered_set CInstantSendManager::ProcessPend if (islock->IsDeterministic()) { LOCK(cs_main); - const auto blockIndex = LookupBlockIndex(islock->cycleHash); + const auto blockIndex = g_chainman.m_blockman.LookupBlockIndex(islock->cycleHash); if (blockIndex == nullptr) { batchVerifier.badSources.emplace(nodeId); continue; @@ -1061,7 +1061,7 @@ void CInstantSendManager::ProcessInstantSendLock(NodeId from, const uint256& has const CBlockIndex* pindexMined{nullptr}; // we ignore failure here as we must be able to propagate the lock even if we don't have the TX locally if (tx && !hashBlock.IsNull()) { - pindexMined = WITH_LOCK(cs_main, return LookupBlockIndex(hashBlock)); + pindexMined = WITH_LOCK(cs_main, return g_chainman.m_blockman.LookupBlockIndex(hashBlock)); // Let's see if the TX that was locked by this islock is already mined in a ChainLocked block. If yes, // we can simply ignore the islock, as the ChainLock implies locking of all TXs in that chain @@ -1479,7 +1479,7 @@ void CInstantSendManager::ResolveBlockConflicts(const uint256& islockHash, const CValidationState state; // need non-const pointer - auto pindex2 = WITH_LOCK(::cs_main, return LookupBlockIndex(pindex->GetBlockHash())); + auto pindex2 = WITH_LOCK(::cs_main, return g_chainman.m_blockman.LookupBlockIndex(pindex->GetBlockHash())); if (!InvalidateBlock(state, Params(), pindex2)) { LogPrintf("CInstantSendManager::%s -- InvalidateBlock failed: %s\n", __func__, FormatStateMessage(state)); // This should not have happened and we are in a state were it's not safe to continue anymore @@ -1496,7 +1496,7 @@ void CInstantSendManager::ResolveBlockConflicts(const uint256& islockHash, const if (activateBestChain) { CValidationState state; - if (!ActivateBestChain(state, Params())) { + if (!::ChainstateActive().ActivateBestChain(state, Params())) { LogPrintf("CChainLocksHandler::%s -- ActivateBestChain failed: %s\n", __func__, FormatStateMessage(state)); // This should not have happened and we are in a state were it's not safe to continue anymore assert(false); diff --git a/src/llmq/quorums.cpp b/src/llmq/quorums.cpp index b3a8998258b7..37de78c4c66e 100644 --- a/src/llmq/quorums.cpp +++ b/src/llmq/quorums.cpp @@ -560,7 +560,7 @@ std::vector CQuorumManager::ScanQuorums(Consensus::LLMQType llmqTyp CQuorumCPtr CQuorumManager::GetQuorum(Consensus::LLMQType llmqType, const uint256& quorumHash) const { - const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return LookupBlockIndex(quorumHash)); + const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return g_chainman.m_blockman.LookupBlockIndex(quorumHash)); if (!pQuorumBaseBlockIndex) { LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- block %s not found\n", __func__, quorumHash.ToString()); return nullptr; @@ -673,7 +673,7 @@ void CQuorumManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, C return; } - const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return LookupBlockIndex(request.GetQuorumHash())); + const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return g_chainman.m_blockman.LookupBlockIndex(request.GetQuorumHash())); if (pQuorumBaseBlockIndex == nullptr) { sendQDATA(CQuorumDataRequest::Errors::QUORUM_BLOCK_NOT_FOUND, request_limit_exceeded); return; diff --git a/src/llmq/snapshot.cpp b/src/llmq/snapshot.cpp index 76bedfc7f3ff..1b46a033fe61 100644 --- a/src/llmq/snapshot.cpp +++ b/src/llmq/snapshot.cpp @@ -132,7 +132,7 @@ bool BuildQuorumRotationInfo(const CGetQuorumRotationInfo& request, CQuorumRotat baseBlockIndexes.push_back(blockIndex); } else { for (const auto& blockHash : request.baseBlockHashes) { - const CBlockIndex* blockIndex = LookupBlockIndex(blockHash); + const CBlockIndex* blockIndex = g_chainman.m_blockman.LookupBlockIndex(blockHash); if (!blockIndex) { errorRet = strprintf("block %s not found", blockHash.ToString()); return false; @@ -158,7 +158,7 @@ bool BuildQuorumRotationInfo(const CGetQuorumRotationInfo& request, CQuorumRotat return false; } - const CBlockIndex* blockIndex = LookupBlockIndex(request.blockRequestHash); + const CBlockIndex* blockIndex = g_chainman.m_blockman.LookupBlockIndex(request.blockRequestHash); if (!blockIndex) { errorRet = strprintf("block not found"); return false; diff --git a/src/miner.cpp b/src/miner.cpp index 277f7155779f..92ed3c6a2b4a 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -234,7 +234,7 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(*pblock->vtx[0]); CValidationState state; - if (!TestBlockValidity(state, m_clhandler, m_evoDb, chainparams, *pblock, pindexPrev, false, false)) { + if (!TestBlockValidity(state, m_clhandler, m_evoDb, chainparams, ::ChainstateActive(), *pblock, pindexPrev, false, false)) { throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state))); } int64_t nTime2 = GetTimeMicros(); diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 681ecf74dcfa..f8223a41d5d4 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -598,7 +598,7 @@ static void ProcessBlockAvailability(NodeId nodeid) EXCLUSIVE_LOCKS_REQUIRED(cs_ assert(state != nullptr); if (!state->hashLastUnknownBlock.IsNull()) { - const CBlockIndex* pindex = LookupBlockIndex(state->hashLastUnknownBlock); + const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(state->hashLastUnknownBlock); if (pindex && pindex->nChainWork > 0) { if (state->pindexBestKnownBlock == nullptr || pindex->nChainWork >= state->pindexBestKnownBlock->nChainWork) { state->pindexBestKnownBlock = pindex; @@ -615,7 +615,7 @@ static void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) EXCLUSIV ProcessBlockAvailability(nodeid); - const CBlockIndex* pindex = LookupBlockIndex(hash); + const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(hash); if (pindex && pindex->nChainWork > 0) { // An actually better block was announced. if (state->pindexBestKnownBlock == nullptr || pindex->nChainWork >= state->pindexBestKnownBlock->nChainWork) { @@ -1594,7 +1594,7 @@ bool static AlreadyHave(const CInv& inv, const CTxMemPool& mempool, const LLMQCo } case MSG_BLOCK: - return LookupBlockIndex(inv.hash) != nullptr; + return g_chainman.m_blockman.LookupBlockIndex(inv.hash) != nullptr; /* Dash Related Inventory Messages @@ -1696,7 +1696,7 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c bool need_activate_chain = false; { LOCK(cs_main); - const CBlockIndex* pindex = LookupBlockIndex(inv.hash); + const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(inv.hash); if (pindex) { if (pindex->HaveTxsDownloaded() && !pindex->IsValid(BLOCK_VALID_SCRIPTS) && pindex->IsValid(BLOCK_VALID_TREE)) { @@ -1711,13 +1711,13 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c } // release cs_main before calling ActivateBestChain if (need_activate_chain) { CValidationState state; - if (!ActivateBestChain(state, Params(), a_recent_block)) { + if (!::ChainstateActive().ActivateBestChain(state, Params(), a_recent_block)) { LogPrint(BCLog::NET, "failed to activate chain (%s)\n", FormatStateMessage(state)); } } LOCK(cs_main); - const CBlockIndex* pindex = LookupBlockIndex(inv.hash); + const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(inv.hash); if (pindex) { send = BlockRequestAllowed(pindex, consensusParams); if (!send) { @@ -2089,7 +2089,7 @@ static void ProcessHeadersMessage(CNode& pfrom, CConnman& connman, ChainstateMan // don't connect before giving DoS points // - Once a headers message is received that is valid and does connect, // nUnconnectingHeaders gets reset back to 0. - if (!LookupBlockIndex(headers[0].hashPrevBlock) && nCount < MAX_BLOCKS_TO_ANNOUNCE) { + if (!g_chainman.m_blockman.LookupBlockIndex(headers[0].hashPrevBlock) && nCount < MAX_BLOCKS_TO_ANNOUNCE) { nodestate->nUnconnectingHeaders++; std::string msg_type = (pfrom.nServices & NODE_HEADERS_COMPRESSED) ? NetMsgType::GETHEADERS2 : NetMsgType::GETHEADERS; connman.PushMessage(&pfrom, msgMaker.Make(msg_type, ::ChainActive().GetLocator(pindexBestHeader), uint256())); @@ -2121,7 +2121,7 @@ static void ProcessHeadersMessage(CNode& pfrom, CConnman& connman, ChainstateMan // If we don't have the last header, then they'll have given us // something new (if these headers are valid). - if (!LookupBlockIndex(hashLastBlock)) { + if (!g_chainman.m_blockman.LookupBlockIndex(hashLastBlock)) { received_new_header = true; } } @@ -2340,7 +2340,7 @@ static bool PrepareBlockFilterRequest(CNode& peer, const CChainParams& chain_par { LOCK(cs_main); - stop_index = LookupBlockIndex(stop_hash); + stop_index = g_chainman.m_blockman.LookupBlockIndex(stop_hash); // Check that the stop block exists and the peer would be allowed to fetch it. if (!stop_index || !BlockRequestAllowed(stop_index, chain_params.GetConsensus())) { @@ -3150,7 +3150,7 @@ void PeerLogicValidation::ProcessMessage( a_recent_block = most_recent_block; } CValidationState state; - if (!ActivateBestChain(state, Params(), a_recent_block)) { + if (!::ChainstateActive().ActivateBestChain(state, Params(), a_recent_block)) { LogPrint(BCLog::NET, "failed to activate chain (%s)\n", FormatStateMessage(state)); } } @@ -3158,7 +3158,7 @@ void PeerLogicValidation::ProcessMessage( LOCK(cs_main); // Find the last block the caller has in the main chain - const CBlockIndex* pindex = FindForkInGlobalIndex(::ChainActive(), locator); + const CBlockIndex* pindex = g_chainman.m_blockman.FindForkInGlobalIndex(::ChainActive(), locator); // Send the rest of the chain if (pindex) @@ -3213,7 +3213,7 @@ void PeerLogicValidation::ProcessMessage( LOCK(cs_main); - const CBlockIndex* pindex = LookupBlockIndex(req.blockhash); + const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(req.blockhash); if (!pindex || !(pindex->nStatus & BLOCK_HAVE_DATA)) { LogPrint(BCLog::NET, "Peer %d sent us a getblocktxn for a block we don't have\n", pfrom.GetId()); return; @@ -3266,7 +3266,7 @@ void PeerLogicValidation::ProcessMessage( if (locator.IsNull()) { // If locator is null, return the hashStop block - pindex = LookupBlockIndex(hashStop); + pindex = g_chainman.m_blockman.LookupBlockIndex(hashStop); if (!pindex) { return; } @@ -3279,7 +3279,7 @@ void PeerLogicValidation::ProcessMessage( else { // Find the last block the caller has in the main chain - pindex = FindForkInGlobalIndex(::ChainActive(), locator); + pindex = g_chainman.m_blockman.FindForkInGlobalIndex(::ChainActive(), locator); if (pindex) pindex = ::ChainActive().Next(pindex); } @@ -3501,14 +3501,14 @@ void PeerLogicValidation::ProcessMessage( { LOCK(cs_main); - if (!LookupBlockIndex(cmpctblock.header.hashPrevBlock)) { + if (!g_chainman.m_blockman.LookupBlockIndex(cmpctblock.header.hashPrevBlock)) { // Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers if (!::ChainstateActive().IsInitialBlockDownload()) m_connman.PushMessage(&pfrom, msgMaker.Make((pfrom.nServices & NODE_HEADERS_COMPRESSED) ? NetMsgType::GETHEADERS2 : NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), uint256())); return; } - if (!LookupBlockIndex(cmpctblock.header.GetHash())) { + if (!g_chainman.m_blockman.LookupBlockIndex(cmpctblock.header.GetHash())) { received_new_header = true; } } @@ -4597,7 +4597,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto) // then send all headers past that one. If we come across any // headers that aren't on ::ChainActive(), give up. for (const uint256 &hash : pto->vBlockHashesToAnnounce) { - const CBlockIndex* pindex = LookupBlockIndex(hash); + const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(hash); assert(pindex); if (::ChainActive()[pindex->nHeight] != pindex) { // Bail out if we reorged away from this block @@ -4705,7 +4705,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto) // in the past. if (!pto->vBlockHashesToAnnounce.empty()) { const uint256 &hashToAnnounce = pto->vBlockHashesToAnnounce.back(); - const CBlockIndex* pindex = LookupBlockIndex(hashToAnnounce); + const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(hashToAnnounce); assert(pindex); // Warn if we're announcing a block that is not on the main chain. diff --git a/src/node/coinstats.cpp b/src/node/coinstats.cpp index 782aa76fc92e..8f8a74fca99e 100644 --- a/src/node/coinstats.cpp +++ b/src/node/coinstats.cpp @@ -92,7 +92,7 @@ static bool GetUTXOStats(CCoinsView* view, CCoinsStats& stats, T hash_obj, const stats.hashBlock = pcursor->GetBestBlock(); { LOCK(cs_main); - stats.nHeight = LookupBlockIndex(stats.hashBlock)->nHeight; + stats.nHeight = g_chainman.m_blockman.LookupBlockIndex(stats.hashBlock)->nHeight; } PrepareHash(hash_obj, stats); diff --git a/src/rest.cpp b/src/rest.cpp index c561b1854358..2fa766b4763e 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -180,7 +180,7 @@ static bool rest_headers(const CoreContext& context, { LOCK(cs_main); tip = ::ChainActive().Tip(); - const CBlockIndex* pindex = LookupBlockIndex(hash); + const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(hash); while (pindex != nullptr && ::ChainActive().Contains(pindex)) { headers.push_back(pindex); if (headers.size() == (unsigned long)count) @@ -248,7 +248,7 @@ static bool rest_block(HTTPRequest* req, { LOCK(cs_main); tip = ::ChainActive().Tip(); - pblockindex = LookupBlockIndex(hash); + pblockindex = g_chainman.m_blockman.LookupBlockIndex(hash); if (!pblockindex) { return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); } diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 71ea21b39de1..5c10e93cc0fa 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -299,7 +299,7 @@ static UniValue getbestchainlock(const JSONRPCRequest& request) result.pushKV("signature", clsig.getSig().ToString()); LOCK(cs_main); - result.pushKV("known_block", LookupBlockIndex(clsig.getBlockHash()) != nullptr); + result.pushKV("known_block", g_chainman.m_blockman.LookupBlockIndex(clsig.getBlockHash()) != nullptr); return result; } @@ -873,7 +873,7 @@ static UniValue getblockheader(const JSONRPCRequest& request) const CBlockIndex* tip; { LOCK(cs_main); - pblockindex = LookupBlockIndex(hash); + pblockindex = g_chainman.m_blockman.LookupBlockIndex(hash); tip = ::ChainActive().Tip(); } @@ -943,7 +943,7 @@ static UniValue getblockheaders(const JSONRPCRequest& request) const CBlockIndex* tip; { LOCK(cs_main); - pblockindex = LookupBlockIndex(hash); + pblockindex = g_chainman.m_blockman.LookupBlockIndex(hash); tip = ::ChainActive().Tip(); } @@ -1051,7 +1051,7 @@ static UniValue getmerkleblocks(const JSONRPCRequest& request) std::string strHash = request.params[1].get_str(); uint256 hash(uint256S(strHash)); - const CBlockIndex* pblockindex = LookupBlockIndex(hash); + const CBlockIndex* pblockindex = g_chainman.m_blockman.LookupBlockIndex(hash); if (!pblockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } @@ -1170,7 +1170,7 @@ static UniValue getblock(const JSONRPCRequest& request) const CBlockIndex* tip; { LOCK(cs_main); - pblockindex = LookupBlockIndex(hash); + pblockindex = g_chainman.m_blockman.LookupBlockIndex(hash); tip = ::ChainActive().Tip(); if (!pblockindex) { @@ -1380,7 +1380,7 @@ static UniValue gettxout(const JSONRPCRequest& request) } } - const CBlockIndex* pindex = LookupBlockIndex(coins_view->GetBestBlock()); + const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(coins_view->GetBestBlock()); ret.pushKV("bestblock", pindex->GetBlockHash().GetHex()); if (coin.nHeight == MEMPOOL_HEIGHT) { ret.pushKV("confirmations", 0); @@ -1811,7 +1811,7 @@ static UniValue preciousblock(const JSONRPCRequest& request) { LOCK(cs_main); - pblockindex = LookupBlockIndex(hash); + pblockindex = g_chainman.m_blockman.LookupBlockIndex(hash); if (!pblockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } @@ -1848,7 +1848,7 @@ static UniValue invalidateblock(const JSONRPCRequest& request) CBlockIndex* pblockindex; { LOCK(cs_main); - pblockindex = LookupBlockIndex(hash); + pblockindex = g_chainman.m_blockman.LookupBlockIndex(hash); if (!pblockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } @@ -1856,7 +1856,7 @@ static UniValue invalidateblock(const JSONRPCRequest& request) InvalidateBlock(state, Params(), pblockindex); if (state.IsValid()) { - ActivateBestChain(state, Params()); + ::ChainstateActive().ActivateBestChain(state, Params()); } if (!state.IsValid()) { @@ -1886,7 +1886,7 @@ static UniValue reconsiderblock(const JSONRPCRequest& request) { LOCK(cs_main); - CBlockIndex* pblockindex = LookupBlockIndex(hash); + CBlockIndex* pblockindex = g_chainman.m_blockman.LookupBlockIndex(hash); if (!pblockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } @@ -1895,7 +1895,7 @@ static UniValue reconsiderblock(const JSONRPCRequest& request) } CValidationState state; - ActivateBestChain(state, Params()); + ::ChainstateActive().ActivateBestChain(state, Params()); if (!state.IsValid()) { throw JSONRPCError(RPC_DATABASE_ERROR, FormatStateMessage(state)); @@ -1939,7 +1939,7 @@ static UniValue getchaintxstats(const JSONRPCRequest& request) } else { uint256 hash = uint256S(request.params[1].get_str()); LOCK(cs_main); - pindex = LookupBlockIndex(hash); + pindex = g_chainman.m_blockman.LookupBlockIndex(hash); if (!pindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } @@ -2116,7 +2116,7 @@ static UniValue getblockstats(const JSONRPCRequest& request) } else { const uint256 hash = ParseHashV(request.params[0], "parameter 1"); - pindex = LookupBlockIndex(hash); + pindex = g_chainman.m_blockman.LookupBlockIndex(hash); if (!pindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } @@ -2336,7 +2336,7 @@ static UniValue getspecialtxes(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_PARAMETER, "Verbosity must be in range 0..2"); } } - const CBlockIndex* pblockindex = LookupBlockIndex(hash); + const CBlockIndex* pblockindex = g_chainman.m_blockman.LookupBlockIndex(hash); if (!pblockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } @@ -2657,7 +2657,7 @@ static UniValue getblockfilter(const JSONRPCRequest& request) bool block_was_connected; { LOCK(cs_main); - block_index = LookupBlockIndex(block_hash); + block_index = g_chainman.m_blockman.LookupBlockIndex(block_hash); if (!block_index) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } @@ -2761,7 +2761,7 @@ UniValue dumptxoutset(const JSONRPCRequest& request) } pcursor = std::unique_ptr(::ChainstateActive().CoinsDB().Cursor()); - tip = LookupBlockIndex(stats.hashBlock); + tip = g_chainman.m_blockman.LookupBlockIndex(stats.hashBlock); CHECK_NONFATAL(tip); } diff --git a/src/rpc/masternode.cpp b/src/rpc/masternode.cpp index 7d4fbb2473e8..82af40b21ca0 100644 --- a/src/rpc/masternode.cpp +++ b/src/rpc/masternode.cpp @@ -421,7 +421,7 @@ static UniValue masternode_payments(const JSONRPCRequest& request) } else { LOCK(cs_main); uint256 blockHash = ParseHashV(request.params[0], "blockhash"); - pindex = LookupBlockIndex(blockHash); + pindex = g_chainman.m_blockman.LookupBlockIndex(blockHash); if (pindex == nullptr) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 10da6d07916e..cd862c836679 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -383,7 +383,7 @@ static UniValue generateblock(const JSONRPCRequest& request) LOCK(cs_main); CValidationState state; - if (!TestBlockValidity(state, *llmq_ctx.clhandler, *node_context.evodb, chainparams, block, LookupBlockIndex(block.hashPrevBlock), false, false)) { + if (!TestBlockValidity(state, *llmq_ctx.clhandler, *node_context.evodb, chainparams, ::ChainstateActive(), block, g_chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock), false, false)) { throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("TestBlockValidity failed: %s", state.GetRejectReason())); } } @@ -657,7 +657,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); uint256 hash = block.GetHash(); - const CBlockIndex* pindex = LookupBlockIndex(hash); + const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(hash); if (pindex) { if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) return "duplicate"; @@ -673,7 +673,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) if (block.hashPrevBlock != pindexPrev->GetBlockHash()) return "inconclusive-not-best-prevblk"; CValidationState state; - TestBlockValidity(state, *llmq_ctx.clhandler, *node_context.evodb, Params(), block, pindexPrev, false, true); + TestBlockValidity(state, *llmq_ctx.clhandler, *node_context.evodb, Params(), ::ChainstateActive(), block, pindexPrev, false, true); return BIP22ValidationResult(state); } @@ -996,7 +996,7 @@ static UniValue submitblock(const JSONRPCRequest& request) uint256 hash = block.GetHash(); { LOCK(cs_main); - const CBlockIndex* pindex = LookupBlockIndex(hash); + const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(hash); if (pindex) { if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) { return "duplicate"; @@ -1043,7 +1043,7 @@ static UniValue submitheader(const JSONRPCRequest& request) } { LOCK(cs_main); - if (!LookupBlockIndex(h.hashPrevBlock)) { + if (!g_chainman.m_blockman.LookupBlockIndex(h.hashPrevBlock)) { throw JSONRPCError(RPC_VERIFY_ERROR, "Must submit previous header (" + h.hashPrevBlock.GetHex() + ") first"); } } diff --git a/src/rpc/quorums.cpp b/src/rpc/quorums.cpp index a0a0839e0d1a..2dfeb42143ad 100644 --- a/src/rpc/quorums.cpp +++ b/src/rpc/quorums.cpp @@ -741,7 +741,7 @@ static UniValue quorum_getdata(const JSONRPCRequest& request) NodeContext& node = EnsureNodeContext(request.context); LLMQContext& llmq_ctx = EnsureLLMQContext(request.context); - const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return LookupBlockIndex(quorumHash)); + const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return g_chainman.m_blockman.LookupBlockIndex(quorumHash)); return node.connman->ForNode(nodeId, [&](CNode* pNode) { return llmq_ctx.qman->RequestQuorumData(pNode, llmqType, pQuorumBaseBlockIndex, nDataMask, proTxHash); }); @@ -880,7 +880,7 @@ static UniValue verifychainlock(const JSONRPCRequest& request) int nBlockHeight; if (request.params[2].isNull()) { - const CBlockIndex* pIndex = WITH_LOCK(cs_main, return LookupBlockIndex(nBlockHash)); + const CBlockIndex* pIndex = WITH_LOCK(cs_main, return g_chainman.m_blockman.LookupBlockIndex(nBlockHash)); if (pIndex == nullptr) { throw JSONRPCError(RPC_INTERNAL_ERROR, "blockHash not found"); } @@ -933,7 +933,7 @@ static UniValue verifyislock(const JSONRPCRequest& request) uint256 hash_block; CTransactionRef tx = GetTransaction(/* block_index */ nullptr, /* mempool */ nullptr, txid, Params().GetConsensus(), hash_block); if (tx && !hash_block.IsNull()) { - pindexMined = LookupBlockIndex(hash_block); + pindexMined = g_chainman.m_blockman.LookupBlockIndex(hash_block); } } diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index ff318b9344a8..bfde57c3132b 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -92,7 +92,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, CTxMemPool& mempo LOCK(cs_main); entry.pushKV("blockhash", hashBlock.GetHex()); - CBlockIndex* pindex = LookupBlockIndex(hashBlock); + CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(hashBlock); if (pindex) { if (::ChainActive().Contains(pindex)) { entry.pushKV("height", pindex->nHeight); @@ -222,7 +222,7 @@ static UniValue getrawtransaction(const JSONRPCRequest& request) LOCK(cs_main); uint256 blockhash = ParseHashV(request.params[2], "parameter 3"); - blockindex = LookupBlockIndex(blockhash); + blockindex = g_chainman.m_blockman.LookupBlockIndex(blockhash); if (!blockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block hash not found"); } @@ -313,7 +313,7 @@ static UniValue gettxoutproof(const JSONRPCRequest& request) if (!request.params[1].isNull()) { LOCK(cs_main); hashBlock = uint256S(request.params[1].get_str()); - pblockindex = LookupBlockIndex(hashBlock); + pblockindex = g_chainman.m_blockman.LookupBlockIndex(hashBlock); if (!pblockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } @@ -343,7 +343,7 @@ static UniValue gettxoutproof(const JSONRPCRequest& request) if (!tx || hashBlock.IsNull()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block"); } - pblockindex = LookupBlockIndex(hashBlock); + pblockindex = g_chainman.m_blockman.LookupBlockIndex(hashBlock); if (!pblockindex) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction index corrupt"); } @@ -404,7 +404,7 @@ static UniValue verifytxoutproof(const JSONRPCRequest& request) LOCK(cs_main); - const CBlockIndex* pindex = LookupBlockIndex(merkleBlock.header.GetHash()); + const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(merkleBlock.header.GetHash()); if (!pindex || !::ChainActive().Contains(pindex) || pindex->nTx == 0) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain"); } diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp index df0ea6e2610f..3de6fbe2a2fd 100644 --- a/src/test/blockfilter_index_tests.cpp +++ b/src/test/blockfilter_index_tests.cpp @@ -185,7 +185,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup) const CBlockIndex* block_index; { LOCK(cs_main); - block_index = LookupBlockIndex(block->GetHash()); + block_index = g_chainman.m_blockman.LookupBlockIndex(block->GetHash()); } BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain()); @@ -203,7 +203,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup) const CBlockIndex* block_index; { LOCK(cs_main); - block_index = LookupBlockIndex(block->GetHash()); + block_index = g_chainman.m_blockman.LookupBlockIndex(block->GetHash()); } BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain()); @@ -217,7 +217,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup) const CBlockIndex* block_index; { LOCK(cs_main); - block_index = LookupBlockIndex(block->GetHash()); + block_index = g_chainman.m_blockman.LookupBlockIndex(block->GetHash()); } BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain()); @@ -238,14 +238,14 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup) { LOCK(cs_main); - block_index = LookupBlockIndex(chainA[i]->GetHash()); + block_index = g_chainman.m_blockman.LookupBlockIndex(chainA[i]->GetHash()); } BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain()); CheckFilterLookups(filter_index, block_index, chainA_last_header); { LOCK(cs_main); - block_index = LookupBlockIndex(chainB[i]->GetHash()); + block_index = g_chainman.m_blockman.LookupBlockIndex(chainB[i]->GetHash()); } BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain()); CheckFilterLookups(filter_index, block_index, chainB_last_header); diff --git a/src/test/fuzz/load_external_block_file.cpp b/src/test/fuzz/load_external_block_file.cpp index c428a866310f..bbff8962e107 100644 --- a/src/test/fuzz/load_external_block_file.cpp +++ b/src/test/fuzz/load_external_block_file.cpp @@ -27,5 +27,5 @@ FUZZ_TARGET_INIT(load_external_block_file, initialize_load_external_block_file) return; } FlatFilePos flat_file_pos; - LoadExternalBlockFile(Params(), fuzzed_block_file, fuzzed_data_provider.ConsumeBool() ? &flat_file_pos : nullptr); + ::ChainstateActive().LoadExternalBlockFile(Params(), fuzzed_block_file, fuzzed_data_provider.ConsumeBool() ? &flat_file_pos : nullptr); } diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index baf4f17665d9..8f38c9306e85 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -254,7 +254,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector(pcoins)); - const int64_t spendheight = GetSpendHeight(mempoolDuplicate); + const int64_t spendheight = g_chainman.m_blockman.GetSpendHeight(mempoolDuplicate); std::list waitingOnDependants; for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { diff --git a/src/validation.cpp b/src/validation.cpp index 4531f02be9a5..968018a23c4e 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -173,17 +173,19 @@ namespace { std::set setDirtyFileInfo; } // anon namespace -CBlockIndex* LookupBlockIndex(const uint256& hash) +CBlockIndex* BlockManager::LookupBlockIndex(const uint256& hash) { AssertLockHeld(cs_main); - BlockMap::const_iterator it = g_chainman.BlockIndex().find(hash); - return it == g_chainman.BlockIndex().end() ? nullptr : it->second; + assert(std::addressof(g_chainman.BlockIndex()) == std::addressof(m_block_index)); + BlockMap::const_iterator it = m_block_index.find(hash); + return it == m_block_index.end() ? nullptr : it->second; } -CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator) +CBlockIndex* BlockManager::FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator) { AssertLockHeld(cs_main); + assert(std::addressof(g_chainman.m_blockman) == std::addressof(*this)); // Find the latest block common to locator and chain - we expect that // locator.vHave is sorted descending by height. for (const uint256& hash : locator.vHave) { @@ -736,7 +738,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, REJECT_NONSTANDARD, "non-BIP68-final"); CAmount nFees = 0; - if (!Consensus::CheckTxInputs(tx, state, m_view, GetSpendHeight(m_view), nFees)) { + if (!Consensus::CheckTxInputs(tx, state, m_view, g_chainman.m_blockman.GetSpendHeight(m_view), nFees)) { return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), FormatStateMessage(state)); } @@ -1281,12 +1283,12 @@ CChainState::CChainState(BlockManager& blockman, std::unique_ptr& evoDb, CTxMemPool& mempool, uint256 from_snapshot_blockhash) - : m_blockman(blockman), + : m_mempool(mempool), m_clhandler(clhandler), m_isman(isman), m_quorum_block_processor(quorum_block_processor), m_evoDb(evoDb), - m_mempool(mempool), + m_blockman(blockman), m_from_snapshot_blockhash(from_snapshot_blockhash) {} void CChainState::InitCoinsDB( @@ -1451,9 +1453,10 @@ bool CScriptCheck::operator()() { return VerifyScript(scriptSig, m_tx_out.scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, m_tx_out.nValue, txdata, cacheStore), &error); } -int GetSpendHeight(const CCoinsViewCache& inputs) +int BlockManager::GetSpendHeight(const CCoinsViewCache& inputs) { - LOCK(cs_main); + AssertLockHeld(cs_main); + assert(std::addressof(g_chainman.m_blockman) == std::addressof(*this)); CBlockIndex* pindexPrev = LookupBlockIndex(inputs.GetBestBlock()); return pindexPrev->nHeight + 1; } @@ -3105,7 +3108,7 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar return true; } -static bool NotifyHeaderTip() LOCKS_EXCLUDED(cs_main) { +static bool NotifyHeaderTip(CChainState& chainstate) LOCKS_EXCLUDED(cs_main) { bool fNotify = false; bool fInitialBlockDownload = false; static CBlockIndex* pindexHeaderOld = nullptr; @@ -3116,7 +3119,8 @@ static bool NotifyHeaderTip() LOCKS_EXCLUDED(cs_main) { if (pindexHeader != pindexHeaderOld) { fNotify = true; - fInitialBlockDownload = ::ChainstateActive().IsInitialBlockDownload(); + assert(std::addressof(::ChainstateActive()) == std::addressof(chainstate)); + fInitialBlockDownload = chainstate.IsInitialBlockDownload(); pindexHeaderOld = pindexHeader; } } @@ -3241,10 +3245,6 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams& return true; } -bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr pblock) { - return ::ChainstateActive().ActivateBestChain(state, chainparams, std::move(pblock)); -} - bool CChainState::PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex) { { @@ -3461,7 +3461,7 @@ void CChainState::EnforceBlock(CValidationState& state, const CChainParams& chai } // In case blocks from the enforced chain are invalid at the moment, reconsider them. if (!pindex->IsValid()) { - ResetBlockFailureFlags(LookupBlockIndex(pindex->GetBlockHash())); + ResetBlockFailureFlags(m_blockman.LookupBlockIndex(pindex->GetBlockHash())); } } @@ -3857,14 +3857,14 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P return true; } -//! Returns last CBlockIndex* that is a checkpoint -static CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +CBlockIndex* BlockManager::GetLastCheckpoint(const CCheckpointData& data) { const MapCheckpoints& checkpoints = data.mapCheckpoints; for (const MapCheckpoints::value_type& i : reverse_iterate(checkpoints)) { const uint256& hash = i.second; + assert(std::addressof(g_chainman.m_blockman) == std::addressof(*this)); CBlockIndex* pindex = LookupBlockIndex(hash); if (pindex) { return pindex; @@ -3882,7 +3882,7 @@ static CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOC * in ConnectBlock(). * Note that -reindex-chainstate skips the validation that happens here! */ -static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, BlockManager& blockman, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { assert(pindexPrev != nullptr); const int nHeight = pindexPrev->nHeight + 1; @@ -3908,7 +3908,8 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta // 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(). - CBlockIndex* pcheckpoint = GetLastCheckpoint(params.Checkpoints()); + assert(std::addressof(g_chainman.m_blockman) == std::addressof(blockman)); + CBlockIndex* pcheckpoint = blockman.GetLastCheckpoint(params.Checkpoints()); if (pcheckpoint && nHeight < pcheckpoint->nHeight) return state.Invalid(ValidationInvalidReason::BLOCK_CHECKPOINT, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight), REJECT_CHECKPOINT, "bad-fork-prior-to-checkpoint"); } @@ -4038,7 +4039,7 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState // it's ok-ish, the other node is probably missing the latest chainlock return state.Invalid(ValidationInvalidReason::BLOCK_CHAINLOCK, error("%s: prev block %s conflicts with chainlock", __func__, block.hashPrevBlock.ToString()), REJECT_INVALID, "bad-prevblk-chainlock"); - if (!ContextualCheckBlockHeader(block, state, chainparams, pindexPrev, GetAdjustedTime())) + if (!ContextualCheckBlockHeader(block, state, *this, chainparams, pindexPrev, GetAdjustedTime())) return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state)); /* Determine if this block descends from any block which has been found @@ -4101,6 +4102,7 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState // Exposed wrapper for AcceptBlockHeader bool ChainstateManager::ProcessNewBlockHeaders(const std::vector& headers, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex, CBlockHeader *first_invalid) { + assert(std::addressof(::ChainstateActive()) == std::addressof(ActiveChainstate())); AssertLockNotHeld(cs_main); if (first_invalid != nullptr) first_invalid->SetNull(); { @@ -4109,7 +4111,7 @@ bool ChainstateManager::ProcessNewBlockHeaders(const std::vector& CBlockIndex *pindex = nullptr; // Use a temp pindex instead of ppindex to avoid a const_cast bool accepted = m_blockman.AcceptBlockHeader( header, state, chainparams, &pindex); - ::ChainstateActive().CheckBlockIndex(chainparams.GetConsensus()); + ActiveChainstate().CheckBlockIndex(chainparams.GetConsensus()); if (!accepted) { if (first_invalid) *first_invalid = header; @@ -4120,8 +4122,8 @@ bool ChainstateManager::ProcessNewBlockHeaders(const std::vector& } } } - if (NotifyHeaderTip()) { - if (::ChainstateActive().IsInitialBlockDownload() && ppindex && *ppindex) { + if (NotifyHeaderTip(ActiveChainstate())) { + if (ActiveChainstate().IsInitialBlockDownload() && ppindex && *ppindex) { LogPrintf("Synchronizing blockheaders, height: %d (~%.2f%%)\n", (*ppindex)->nHeight, 100.0/((*ppindex)->nHeight+(GetAdjustedTime() - (*ppindex)->GetBlockTime()) / Params().GetConsensus().nPowTargetSpacing) * (*ppindex)->nHeight); } } @@ -4242,6 +4244,7 @@ bool CChainState::AcceptBlock(const std::shared_ptr& pblock, CVali bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr pblock, bool fForceProcessing, bool* fNewBlock) { AssertLockNotHeld(cs_main); + assert(std::addressof(::ChainstateActive()) == std::addressof(ActiveChainstate())); { CBlockIndex *pindex = nullptr; @@ -4257,7 +4260,7 @@ bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const s bool ret = CheckBlock(*pblock, state, chainparams.GetConsensus()); if (ret) { // Store to disk - ret = ::ChainstateActive().AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, nullptr, fNewBlock); + ret = ActiveChainstate().AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, nullptr, fNewBlock); } if (!ret) { GetMainSignals().BlockChecked(*pblock, state); @@ -4265,27 +4268,36 @@ bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const s } } - NotifyHeaderTip(); + NotifyHeaderTip(ActiveChainstate()); CValidationState state; // Only used to report errors, not invalidity - ignore it - if (!::ChainstateActive().ActivateBestChain(state, chainparams, pblock)) + if (!ActiveChainstate().ActivateBestChain(state, chainparams, pblock)) return error("%s: ActivateBestChain failed: %s", __func__, FormatStateMessage(state)); LogPrintf("%s : ACCEPTED\n", __func__); return true; } -bool TestBlockValidity(CValidationState& state, llmq::CChainLocksHandler& clhandler, CEvoDB& evoDb, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot) +bool TestBlockValidity(CValidationState& state, + llmq::CChainLocksHandler& clhandler, + CEvoDB& evoDb, + const CChainParams& chainparams, + CChainState& chainstate, + const CBlock& block, + CBlockIndex* pindexPrev, + bool fCheckPOW, + bool fCheckMerkleRoot) { AssertLockHeld(cs_main); - assert(pindexPrev && pindexPrev == ::ChainActive().Tip()); + assert(std::addressof(::ChainstateActive()) == std::addressof(chainstate)); + assert(pindexPrev && pindexPrev == chainstate.m_chain.Tip()); uint256 hash = block.GetHash(); if (clhandler.HasConflictingChainLock(pindexPrev->nHeight + 1, hash)) { return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: conflicting with chainlock", __func__), REJECT_INVALID, "bad-chainlock"); } - CCoinsViewCache viewNew(&::ChainstateActive().CoinsTip()); + CCoinsViewCache viewNew(&chainstate.CoinsTip()); uint256 block_hash(block.GetHash()); CBlockIndex indexDummy(block); indexDummy.pprev = pindexPrev; @@ -4296,13 +4308,14 @@ bool TestBlockValidity(CValidationState& state, llmq::CChainLocksHandler& clhand auto dbTx = evoDb.BeginTransaction(); // NOTE: CheckBlockHeader is called by CheckBlock - if (!ContextualCheckBlockHeader(block, state, chainparams, pindexPrev, GetAdjustedTime())) + assert(std::addressof(g_chainman.m_blockman) == std::addressof(chainstate.m_blockman)); + if (!ContextualCheckBlockHeader(block, state, chainstate.m_blockman, chainparams, pindexPrev, GetAdjustedTime())) return error("%s: Consensus::ContextualCheckBlockHeader: %s", __func__, FormatStateMessage(state)); if (!CheckBlock(block, state, chainparams.GetConsensus(), fCheckPOW, fCheckMerkleRoot)) return error("%s: Consensus::CheckBlock: %s", __func__, FormatStateMessage(state)); if (!ContextualCheckBlock(block, state, chainparams.GetConsensus(), pindexPrev)) return error("%s: Consensus::ContextualCheckBlock: %s", __func__, FormatStateMessage(state)); - if (!::ChainstateActive().ConnectBlock(block, state, &indexDummy, viewNew, chainparams, true)) + if (!chainstate.ConnectBlock(block, state, &indexDummy, viewNew, chainparams, true)) return false; assert(state.IsValid()); @@ -4666,7 +4679,7 @@ bool CChainState::LoadChainTip(const CChainParams& chainparams) } // Load pointer to end of best chain - CBlockIndex* pindex = LookupBlockIndex(coins_cache.GetBestBlock()); + CBlockIndex* pindex = m_blockman.LookupBlockIndex(coins_cache.GetBestBlock()); if (!pindex) { return false; } @@ -5008,7 +5021,7 @@ bool LoadGenesisBlock(const CChainParams& chainparams) return ::ChainstateActive().LoadGenesisBlock(chainparams); } -void LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFilePos* dbp) +void CChainState::LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFilePos* dbp) { // Map of disk positions for blocks with unknown parent (only used for reindex) static std::multimap mapBlocksUnknownParent; @@ -5058,7 +5071,8 @@ void LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFi { LOCK(cs_main); // detect out of order blocks, and store them for later - if (hash != chainparams.GetConsensus().hashGenesisBlock && !LookupBlockIndex(block.hashPrevBlock)) { + assert(std::addressof(g_chainman.m_blockman) == std::addressof(m_blockman)); + if (hash != chainparams.GetConsensus().hashGenesisBlock && !m_blockman.LookupBlockIndex(block.hashPrevBlock)) { LogPrint(BCLog::REINDEX, "%s: Out of order block %s, parent %s not known\n", __func__, hash.ToString(), block.hashPrevBlock.ToString()); if (dbp) @@ -5067,10 +5081,12 @@ void LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFi } // process in case the block isn't known yet - CBlockIndex* pindex = LookupBlockIndex(hash); + assert(std::addressof(g_chainman.m_blockman) == std::addressof(m_blockman)); + CBlockIndex* pindex = m_blockman.LookupBlockIndex(hash); if (!pindex || (pindex->nStatus & BLOCK_HAVE_DATA) == 0) { CValidationState state; - if (::ChainstateActive().AcceptBlock(pblock, state, chainparams, nullptr, true, dbp, nullptr)) { + assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); + if (AcceptBlock(pblock, state, chainparams, nullptr, true, dbp, nullptr)) { nLoaded++; } if (state.IsError()) { @@ -5084,12 +5100,14 @@ void LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFi // Activate the genesis block so normal node progress can continue if (hash == chainparams.GetConsensus().hashGenesisBlock) { CValidationState state; + assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); if (!ActivateBestChain(state, chainparams, nullptr)) { break; } } - NotifyHeaderTip(); + assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); + NotifyHeaderTip(*this); // Recursively process earlier encountered successors of this block std::deque queue; @@ -5107,7 +5125,8 @@ void LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFi head.ToString()); LOCK(cs_main); CValidationState dummy; - if (::ChainstateActive().AcceptBlock(pblockrecursive, dummy, chainparams, nullptr, true, &it->second, nullptr)) + assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); + if (AcceptBlock(pblockrecursive, dummy, chainparams, nullptr, true, &it->second, nullptr)) { nLoaded++; queue.push_back(pblockrecursive->GetHash()); @@ -5115,7 +5134,8 @@ void LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFi } range.first++; mapBlocksUnknownParent.erase(it); - NotifyHeaderTip(); + assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); + NotifyHeaderTip(*this); } } } catch (const std::exception& e) { @@ -5565,7 +5585,7 @@ double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex *pin } std::optional ChainstateManager::SnapshotBlockhash() const { - LOCK(::cs_main); + LOCK(::cs_main); // for m_active_chainstate access if (m_active_chainstate != nullptr) { // If a snapshot chainstate exists, it will always be our active. return m_active_chainstate->m_from_snapshot_blockhash; @@ -5619,6 +5639,7 @@ CChainState& ChainstateManager::InitializeChainstate(std::unique_ptr pblock = std::shared_ptr()) LOCKS_EXCLUDED(cs_main); double ConvertBitsToDouble(unsigned int nBits); CAmount GetBlockSubsidy(int nBits, int nHeight, const Consensus::Params& consensusParams, bool fSuperblockPartOnly = false); @@ -332,7 +324,15 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex); bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true, bool fCheckMerkleRoot = true); /** Check a block is completely valid from start to finish (only works on top of our current best block) */ -bool TestBlockValidity(CValidationState& state, llmq::CChainLocksHandler& clhandler, CEvoDB& evoDb, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true) EXCLUSIVE_LOCKS_REQUIRED(cs_main); +bool TestBlockValidity(CValidationState& state, + llmq::CChainLocksHandler& clhandler, + CEvoDB& evoDb, + const CChainParams& chainparams, + CChainState& chainstate, + const CBlock& block, + CBlockIndex* pindexPrev, + bool fCheckPOW = true, + bool fCheckMerkleRoot = true) EXCLUSIVE_LOCKS_REQUIRED(cs_main); /** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */ class CVerifyDB { @@ -342,11 +342,6 @@ class CVerifyDB { bool VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, CEvoDB& evoDb, int nCheckLevel, int nCheckDepth); }; -CBlockIndex* LookupBlockIndex(const uint256& hash) 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); - enum DisconnectResult { DISCONNECT_OK, // All good. DISCONNECT_UNCLEAN, // Rolled back, but UTXO set was inconsistent with block. @@ -463,6 +458,21 @@ class BlockManager const CChainParams& chainparams, CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + CBlockIndex* LookupBlockIndex(const uint256& hash) 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); + + //! Returns last CBlockIndex* that is a checkpoint + CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + + /** + * Return the spend height, which is one more than the inputs.GetBestBlock(). + * While checking, GetBestBlock() refers to the parent block. (protected by cs_main) + * This is also true for mempool checks. + */ + int GetSpendHeight(const CCoinsViewCache& inputs) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + ~BlockManager() { Unload(); } @@ -556,11 +566,6 @@ class CChainState */ mutable std::atomic m_cached_finished_ibd{false}; - //! Reference to a BlockManager instance which itself is shared across all - //! CChainState instances. Keeping a local reference allows us to test more - //! easily as opposed to referencing a global. - BlockManager& m_blockman; - //! mempool that is kept in sync with the chain CTxMemPool& m_mempool; @@ -574,6 +579,10 @@ class CChainState std::unique_ptr& m_evoDb; public: + //! Reference to a BlockManager instance which itself is shared across all + //! CChainState instances. + BlockManager& m_blockman; + explicit CChainState(BlockManager& blockman, std::unique_ptr& clhandler, std::unique_ptr& isman, @@ -656,6 +665,9 @@ class CChainState bool ResizeCoinsCaches(size_t coinstip_size, size_t coinsdb_size) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + /** Import blocks from an external file */ + void LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFilePos* dbp = nullptr); + /** * Update the on-disk chain state. * The caches and indexes are flushed depending on the mode we're called with @@ -681,9 +693,10 @@ class CChainState void PruneAndFlush(); /** - * Make the best chain active, in multiple steps. The result is either failure - * or an activated best chain. pblock is either nullptr or a pointer to a block - * that is already loaded (to avoid loading it again from disk). + * Find the best known block, and make it the tip of the block chain. The + * result is either failure or an activated best chain. pblock is either + * nullptr or a pointer to a block that is already loaded (to avoid loading + * it again from disk). * * ActivateBestChain is split into steps (see ActivateBestChainStep) so that * we avoid holding cs_main for an extended period of time; the length of this @@ -697,7 +710,7 @@ class CChainState bool ActivateBestChain( CValidationState& state, const CChainParams& chainparams, - std::shared_ptr pblock) LOCKS_EXCLUDED(cs_main); + std::shared_ptr pblock = nullptr) LOCKS_EXCLUDED(cs_main); bool AcceptBlock(const std::shared_ptr& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main); @@ -867,7 +880,7 @@ class ChainstateManager //! This is especially important when, e.g., calling ActivateBestChain() //! on all chainstates because we are not able to hold ::cs_main going into //! that call. - CChainState* m_active_chainstate{nullptr}; + CChainState* m_active_chainstate GUARDED_BY(::cs_main) {nullptr}; //! If true, the assumed-valid chainstate has been fully validated //! by the background validation chainstate. @@ -1005,13 +1018,6 @@ CChain& ChainActive(); /** Global variable that points to the active block tree (protected by cs_main) */ extern std::unique_ptr pblocktree; -/** - * Return the spend height, which is one more than the inputs.GetBestBlock(). - * While checking, GetBestBlock() refers to the parent block. (protected by cs_main) - * This is also true for mempool checks. - */ -int GetSpendHeight(const CCoinsViewCache& inputs); - extern VersionBitsCache versionbitscache; /** From 228a7fb4a109fd30ed03341873a4f82694684bb7 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kittywhiskers@users.noreply.github.com> Date: Wed, 20 Jan 2021 14:43:27 -0500 Subject: [PATCH 32/35] merge bitcoin#20972: Annotate CTxMemPool::check to require cs_main --- src/txmempool.cpp | 1 + src/txmempool.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 5413a27c7b2b..fd4fc5bb5cea 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1034,6 +1034,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const if (GetRand(m_check_ratio) >= 1) return; + AssertLockHeld(::cs_main); LOCK(cs); LogPrint(BCLog::MEMPOOL, "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size()); diff --git a/src/txmempool.h b/src/txmempool.h index ce5b4b4f6211..87efdeab93e5 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -596,7 +596,7 @@ class CTxMemPool * all inputs are in the mapNextTx array). If sanity-checking is turned off, * check does nothing. */ - void check(const CCoinsViewCache *pcoins) const; + void check(const CCoinsViewCache *pcoins) const EXCLUSIVE_LOCKS_REQUIRED(::cs_main); // addUnchecked must updated state for all ancestors of a given transaction, // to track size/count of descendant transactions. First version of From 30191be0b10ff7ba4e7b926908b4e3f19be2f3f9 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kittywhiskers@users.noreply.github.com> Date: Thu, 23 Mar 2023 07:47:33 +0000 Subject: [PATCH 33/35] merge bitcoin#20750: Prune g_chainman usage in mempool-related validation functions --- src/bench/block_assemble.cpp | 2 +- src/coinjoin/coinjoin.cpp | 2 +- src/coinjoin/server.cpp | 4 +- src/interfaces/chain.cpp | 2 +- src/net_processing.cpp | 4 +- src/node/transaction.cpp | 2 +- src/rpc/rawtransaction.cpp | 2 +- src/test/miner_tests.cpp | 12 +-- src/test/txvalidation_tests.cpp | 2 +- src/test/txvalidationcache_tests.cpp | 2 +- src/test/validation_block_tests.cpp | 1 + src/txmempool.cpp | 10 +- src/txmempool.h | 3 +- src/validation.cpp | 138 +++++++++++++++++---------- src/validation.h | 15 ++- 15 files changed, 121 insertions(+), 80 deletions(-) diff --git a/src/bench/block_assemble.cpp b/src/bench/block_assemble.cpp index 222f57c8c214..1afedc9963f7 100644 --- a/src/bench/block_assemble.cpp +++ b/src/bench/block_assemble.cpp @@ -41,7 +41,7 @@ static void AssembleBlock(benchmark::Bench& bench) for (const auto& txr : txs) { CValidationState state; - bool ret{::AcceptToMemoryPool(*test_setup.m_node.mempool, state, txr, nullptr /* pfMissingInputs */, false /* bypass_limits */, /* nAbsurdFee */ 0)}; + bool ret{::AcceptToMemoryPool(::ChainstateActive(), *test_setup.m_node.mempool, state, txr, nullptr /* pfMissingInputs */, false /* bypass_limits */, /* nAbsurdFee */ 0)}; assert(ret); } } diff --git a/src/coinjoin/coinjoin.cpp b/src/coinjoin/coinjoin.cpp index 92acfa664cab..c18c72d148a5 100644 --- a/src/coinjoin/coinjoin.cpp +++ b/src/coinjoin/coinjoin.cpp @@ -352,7 +352,7 @@ bool CCoinJoin::IsCollateralValid(CTxMemPool& mempool, const CTransaction& txCol { LOCK(cs_main); CValidationState validationState; - if (!AcceptToMemoryPool(mempool, validationState, MakeTransactionRef(txCollateral), /*pfMissingInputs=*/nullptr, /*bypass_limits=*/false, /*nAbsurdFee=*/DEFAULT_MAX_RAW_TX_FEE, /*test_accept=*/true)) { + if (!AcceptToMemoryPool(::ChainstateActive(), mempool, validationState, MakeTransactionRef(txCollateral), /*pfMissingInputs=*/nullptr, /*bypass_limits=*/false, /*nAbsurdFee=*/DEFAULT_MAX_RAW_TX_FEE, /*test_accept=*/true)) { LogPrint(BCLog::COINJOIN, "CCoinJoin::IsCollateralValid -- didn't pass AcceptToMemoryPool()\n"); return false; } diff --git a/src/coinjoin/server.cpp b/src/coinjoin/server.cpp index 52dc6fea226c..1ebcc36b35bf 100644 --- a/src/coinjoin/server.cpp +++ b/src/coinjoin/server.cpp @@ -322,7 +322,7 @@ void CCoinJoinServer::CommitFinalTransaction() TRY_LOCK(cs_main, lockMain); CValidationState validationState; mempool.PrioritiseTransaction(hashTx, 0.1 * COIN); - if (!lockMain || !AcceptToMemoryPool(mempool, validationState, finalTransaction, nullptr /* pfMissingInputs */, false /* bypass_limits */, DEFAULT_MAX_RAW_TX_FEE /* nAbsurdFee */)) { + if (!lockMain || !AcceptToMemoryPool(::ChainstateActive(), mempool, validationState, finalTransaction, nullptr /* pfMissingInputs */, false /* bypass_limits */, DEFAULT_MAX_RAW_TX_FEE /* nAbsurdFee */)) { LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CommitFinalTransaction -- AcceptToMemoryPool() error: Transaction not valid\n"); WITH_LOCK(cs_coinjoin, SetNull()); // not much we can do in this case, just notify clients @@ -455,7 +455,7 @@ void CCoinJoinServer::ConsumeCollateral(const CTransactionRef& txref) const { LOCK(cs_main); CValidationState validationState; - if (!AcceptToMemoryPool(mempool, validationState, txref, nullptr /* pfMissingInputs */, false /* bypass_limits */, 0 /* nAbsurdFee */)) { + if (!AcceptToMemoryPool(::ChainstateActive(), mempool, validationState, txref, nullptr /* pfMissingInputs */, false /* bypass_limits */, 0 /* nAbsurdFee */)) { LogPrint(BCLog::COINJOIN, "%s -- AcceptToMemoryPool failed\n", __func__); } else { connman.RelayTransaction(*txref); diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp index c8ae63cb2f89..e5684485640c 100644 --- a/src/interfaces/chain.cpp +++ b/src/interfaces/chain.cpp @@ -239,7 +239,7 @@ class ChainImpl : public Chain bool checkFinalTx(const CTransaction& tx) override { LOCK(cs_main); - return CheckFinalTx(tx); + return CheckFinalTx(::ChainActive().Tip(), tx); } bool findBlock(const uint256& hash, CBlock* block, int64_t* time, int64_t* time_max) override { diff --git a/src/net_processing.cpp b/src/net_processing.cpp index f8223a41d5d4..5b9882a6dcb2 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -2272,7 +2272,7 @@ void static ProcessOrphanTx(CConnman& connman, CTxMemPool& mempool, std::set& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs); bool TestSequenceLocks(const CTransaction& tx, int flags) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs) { - return CheckSequenceLocks(*m_node.mempool, tx, flags); + return CheckSequenceLocks(::ChainstateActive(), *m_node.mempool, tx, flags); } BlockAssembler AssemblerForTest(const CChainParams& params); }; @@ -456,7 +456,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.nLockTime = 0; hash = tx.GetHash(); m_node.mempool->addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); - BOOST_CHECK(CheckFinalTx(CTransaction(tx), flags)); // Locktime passes + BOOST_CHECK(CheckFinalTx(::ChainActive().Tip(), CTransaction(tx), flags)); // Locktime passes BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks fail BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, prevheights, CreateBlockIndex(::ChainActive().Tip()->nHeight + 2))); // Sequence locks pass on 2nd block @@ -466,7 +466,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) prevheights[0] = baseheight + 2; hash = tx.GetHash(); m_node.mempool->addUnchecked(entry.Time(GetTime()).FromTx(tx)); - BOOST_CHECK(CheckFinalTx(CTransaction(tx), flags)); // Locktime passes + BOOST_CHECK(CheckFinalTx(::ChainActive().Tip(), CTransaction(tx), flags)); // Locktime passes BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks fail for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) @@ -482,7 +482,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.nLockTime = ::ChainActive().Tip()->nHeight + 1; hash = tx.GetHash(); m_node.mempool->addUnchecked(entry.Time(GetTime()).FromTx(tx)); - BOOST_CHECK(!CheckFinalTx(CTransaction(tx), flags)); // Locktime fails + BOOST_CHECK(!CheckFinalTx(::ChainActive().Tip(), CTransaction(tx), flags)); // Locktime fails BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks pass BOOST_CHECK(IsFinalTx(CTransaction(tx), ::ChainActive().Tip()->nHeight + 2, ::ChainActive().Tip()->GetMedianTimePast())); // Locktime passes on 2nd block @@ -493,7 +493,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) prevheights[0] = baseheight + 4; hash = tx.GetHash(); m_node.mempool->addUnchecked(entry.Time(GetTime()).FromTx(tx)); - BOOST_CHECK(!CheckFinalTx(CTransaction(tx), flags)); // Locktime fails + BOOST_CHECK(!CheckFinalTx(::ChainActive().Tip(), CTransaction(tx), flags)); // Locktime fails BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks pass BOOST_CHECK(IsFinalTx(CTransaction(tx), ::ChainActive().Tip()->nHeight + 2, ::ChainActive().Tip()->GetMedianTimePast() + 1)); // Locktime passes 1 second later @@ -502,7 +502,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) prevheights[0] = ::ChainActive().Tip()->nHeight + 1; tx.nLockTime = 0; tx.vin[0].nSequence = 0; - BOOST_CHECK(CheckFinalTx(CTransaction(tx), flags)); // Locktime passes + BOOST_CHECK(CheckFinalTx(::ChainActive().Tip(), CTransaction(tx), flags)); // Locktime passes BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks pass tx.vin[0].nSequence = 1; BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks fail diff --git a/src/test/txvalidation_tests.cpp b/src/test/txvalidation_tests.cpp index 7c597fe2b62c..fdb2b4a8c0f5 100644 --- a/src/test/txvalidation_tests.cpp +++ b/src/test/txvalidation_tests.cpp @@ -38,7 +38,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup) BOOST_CHECK_EQUAL( false, - AcceptToMemoryPool(*m_node.mempool, state, MakeTransactionRef(coinbaseTx), + AcceptToMemoryPool(::ChainstateActive(), *m_node.mempool, state, MakeTransactionRef(coinbaseTx), nullptr /* pfMissingInputs */, true /* bypass_limits */, 0 /* nAbsurdFee */)); diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index 3c0747066319..39f74e4acfb4 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -28,7 +28,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) LOCK(cs_main); CValidationState state; - return AcceptToMemoryPool(*m_node.mempool, state, MakeTransactionRef(tx), nullptr /* pfMissingInputs */, + return AcceptToMemoryPool(::ChainstateActive(), *m_node.mempool, state, MakeTransactionRef(tx), nullptr /* pfMissingInputs */, true /* bypass_limits */, 0 /* nAbsurdFee */); }; diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp index 01be24a24aae..b6cd6db433a5 100644 --- a/src/test/validation_block_tests.cpp +++ b/src/test/validation_block_tests.cpp @@ -299,6 +299,7 @@ BOOST_AUTO_TEST_CASE(mempool_locks_reorg) CValidationState state; for (const auto& tx : txs) { BOOST_REQUIRE(AcceptToMemoryPool( + ::ChainstateActive(), *m_node.mempool, state, tx, diff --git a/src/txmempool.cpp b/src/txmempool.cpp index fd4fc5bb5cea..a9a202991e34 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -752,7 +752,7 @@ void CTxMemPool::removeRecursive(const CTransaction &origTx, MemPoolRemovalReaso RemoveStaged(setAllRemoves, false, reason); } -void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +void CTxMemPool::removeForReorg(CChainState& active_chainstate, int flags) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { // Remove transactions spending a coinbase which are now immature and no-longer-final transactions AssertLockHeld(cs); @@ -760,8 +760,9 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { const CTransaction& tx = it->GetTx(); LockPoints lp = it->GetLockPoints(); - bool validLP = TestLockPointValidity(&lp); - if (!CheckFinalTx(tx, flags) || !CheckSequenceLocks(*this, tx, flags, &lp, validLP)) { + assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate)); + bool validLP = TestLockPointValidity(active_chainstate.m_chain, &lp); + if (!CheckFinalTx(active_chainstate.m_chain.Tip(), tx, flags) || !CheckSequenceLocks(active_chainstate, *this, tx, flags, &lp, validLP)) { // Note if CheckSequenceLocks fails the LockPoints may still be invalid // So it's critical that we remove the tx and not depend on the LockPoints. txToRemove.insert(it); @@ -770,8 +771,9 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash); if (it2 != mapTx.end()) continue; - const Coin &coin = pcoins->AccessCoin(txin.prevout); + const Coin &coin = active_chainstate.CoinsTip().AccessCoin(txin.prevout); if (m_check_ratio != 0) assert(!coin.IsSpent()); + unsigned int nMemPoolHeight = active_chainstate.m_chain.Tip()->nHeight + 1; if (coin.IsSpent() || (coin.IsCoinBase() && ((signed long)nMemPoolHeight) - coin.nHeight < COINBASE_MATURITY)) { txToRemove.insert(it); break; diff --git a/src/txmempool.h b/src/txmempool.h index 87efdeab93e5..e093a6733c73 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -36,6 +36,7 @@ class CBLSPublicKey; class CBlockIndex; +class CChainState; extern CCriticalSection cs_main; /** Fake height value used in Coin to signify they are only in the memory pool (since 0.8) */ @@ -618,7 +619,7 @@ class CTxMemPool bool removeSpentIndex(const uint256 txhash); void removeRecursive(const CTransaction& tx, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs); - void removeForReorg(const CCoinsViewCache* pcoins, unsigned int nMemPoolHeight, int flags) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main); + void removeForReorg(CChainState& active_chainstate, int flags) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main); void removeConflicts(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(cs); void removeProTxPubKeyConflicts(const CTransaction &tx, const CKeyID &keyId) EXCLUSIVE_LOCKS_REQUIRED(cs); void removeProTxPubKeyConflicts(const CTransaction &tx, const CBLSPublicKey &pubKey) EXCLUSIVE_LOCKS_REQUIRED(cs); diff --git a/src/validation.cpp b/src/validation.cpp index 968018a23c4e..f3a590bd7cec 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -205,9 +205,10 @@ static FILE* OpenUndoFile(const FlatFilePos &pos, bool fReadOnly = false); static FlatFileSeq BlockFileSeq(); static FlatFileSeq UndoFileSeq(); -bool CheckFinalTx(const CTransaction &tx, int flags) +bool CheckFinalTx(const CBlockIndex* active_chain_tip, const CTransaction &tx, int flags) { AssertLockHeld(cs_main); + assert(std::addressof(*::ChainActive().Tip()) == std::addressof(*active_chain_tip)); // By convention a negative value for flags indicates that the // current network-enforced consensus rules should be used. In @@ -223,7 +224,7 @@ bool CheckFinalTx(const CTransaction &tx, int flags) // evaluated is what is used. Thus if we want to know if a // transaction can be part of the *next* block, we need to call // IsFinalTx() with one more than ::ChainActive().Height(). - const int nBlockHeight = ::ChainActive().Height() + 1; + const int nBlockHeight = active_chain_tip->nHeight + 1; // BIP113 requires that time-locked transactions have nLockTime set to // less than the median time of the previous block they're contained in. @@ -231,13 +232,13 @@ bool CheckFinalTx(const CTransaction &tx, int flags) // chain tip, so we use that to calculate the median time passed to // IsFinalTx() if LOCKTIME_MEDIAN_TIME_PAST is set. const int64_t nBlockTime = (flags & LOCKTIME_MEDIAN_TIME_PAST) - ? ::ChainActive().Tip()->GetMedianTimePast() + ? active_chain_tip->GetMedianTimePast() : GetAdjustedTime(); return IsFinalTx(tx, nBlockHeight, nBlockTime); } -bool TestLockPointValidity(const LockPoints* lp) +bool TestLockPointValidity(CChain& active_chain, const LockPoints* lp) { AssertLockHeld(cs_main); assert(lp); @@ -246,7 +247,8 @@ bool TestLockPointValidity(const LockPoints* lp) if (lp->maxInputBlock) { // Check whether ::ChainActive() is an extension of the block at which the LockPoints // calculation was valid. If not LockPoints are no longer valid - if (!::ChainActive().Contains(lp->maxInputBlock)) { + assert(std::addressof(::ChainActive()) == std::addressof(active_chain)); + if (!active_chain.Contains(lp->maxInputBlock)) { return false; } } @@ -255,22 +257,28 @@ bool TestLockPointValidity(const LockPoints* lp) return true; } -bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flags, LockPoints* lp, bool useExistingLockPoints) +bool CheckSequenceLocks(CChainState& active_chainstate, + const CTxMemPool& pool, + const CTransaction& tx, + int flags, + LockPoints* lp, + bool useExistingLockPoints) { AssertLockHeld(cs_main); AssertLockHeld(pool.cs); + assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate)); - CBlockIndex* tip = ::ChainActive().Tip(); + CBlockIndex* tip = active_chainstate.m_chain.Tip(); assert(tip != nullptr); CBlockIndex index; index.pprev = tip; - // CheckSequenceLocks() uses ::ChainActive().Height()+1 to evaluate + // CheckSequenceLocks() uses active_chainstate.m_chain.Height()+1 to evaluate // height based locks because when SequenceLocks() is called within // ConnectBlock(), the height of the block *being* // evaluated is what is used. // Thus if we want to know if a transaction can be part of the - // *next* block, we need to use one more than ::ChainActive().Height() + // *next* block, we need to use one more than active_chainstate.m_chain.Height() index.nHeight = tip->nHeight + 1; std::pair lockPair; @@ -280,8 +288,8 @@ bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flag lockPair.second = lp->time; } else { - // CoinsTip() contains the UTXO set for ::ChainActive().Tip() - CCoinsViewMemPool viewMemPool(&::ChainstateActive().CoinsTip(), pool); + // CoinsTip() contains the UTXO set for active_chainstate.m_chain.Tip() + CCoinsViewMemPool viewMemPool(&active_chainstate.CoinsTip(), pool); std::vector prevheights; prevheights.resize(tx.vin.size()); for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) { @@ -389,7 +397,8 @@ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, // Returns the script flags which should be checked for a given block static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& chainparams); -static void LimitMempoolSize(CTxMemPool& pool, size_t limit, std::chrono::seconds age) EXCLUSIVE_LOCKS_REQUIRED(pool.cs, ::cs_main) +static void LimitMempoolSize(CTxMemPool& pool, CCoinsViewCache& coins_cache, size_t limit, std::chrono::seconds age) + EXCLUSIVE_LOCKS_REQUIRED(pool.cs, ::cs_main) { int expired = pool.Expire(GetTime() - age); if (expired != 0) { @@ -398,18 +407,20 @@ static void LimitMempoolSize(CTxMemPool& pool, size_t limit, std::chrono::second std::vector vNoSpendsRemaining; pool.TrimToSize(limit, &vNoSpendsRemaining); + assert(std::addressof(::ChainstateActive().CoinsTip()) == std::addressof(coins_cache)); for (const COutPoint& removed : vNoSpendsRemaining) - ::ChainstateActive().CoinsTip().Uncache(removed); + coins_cache.Uncache(removed); } -static bool IsCurrentForFeeEstimation() EXCLUSIVE_LOCKS_REQUIRED(cs_main) +static bool IsCurrentForFeeEstimation(CChainState& active_chainstate) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { AssertLockHeld(cs_main); - if (::ChainstateActive().IsInitialBlockDownload()) + assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate)); + if (active_chainstate.IsInitialBlockDownload()) return false; - if (::ChainActive().Tip()->GetBlockTime() < count_seconds(GetTime() - MAX_FEE_ESTIMATION_TIP_AGE)) + if (active_chainstate.m_chain.Tip()->GetBlockTime() < count_seconds(GetTime() - MAX_FEE_ESTIMATION_TIP_AGE)) return false; - if (::ChainActive().Height() < pindexBestHeader->nHeight - 1) + if (active_chainstate.m_chain.Height() < pindexBestHeader->nHeight - 1) return false; return true; } @@ -427,10 +438,11 @@ static bool IsCurrentForFeeEstimation() EXCLUSIVE_LOCKS_REQUIRED(cs_main) * and instead just erase from the mempool as needed. */ -static void UpdateMempoolForReorg(CTxMemPool& mempool, DisconnectedBlockTransactions& disconnectpool, bool fAddToMempool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, mempool.cs) +static void UpdateMempoolForReorg(CChainState& active_chainstate, CTxMemPool& mempool, DisconnectedBlockTransactions& disconnectpool, bool fAddToMempool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, mempool.cs) { AssertLockHeld(cs_main); AssertLockHeld(mempool.cs); + assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate)); std::vector vHashUpdate; // disconnectpool's insertion_order index sorts the entries from // oldest to newest, but the oldest entry will be the last tx from the @@ -443,7 +455,7 @@ static void UpdateMempoolForReorg(CTxMemPool& mempool, DisconnectedBlockTransact // ignore validation errors in resurrected transactions CValidationState stateDummy; if (!fAddToMempool || (*it)->IsCoinBase() || - !AcceptToMemoryPool(mempool, stateDummy, *it, nullptr /* pfMissingInputs */, + !AcceptToMemoryPool(active_chainstate, mempool, stateDummy, *it, nullptr /* pfMissingInputs */, true /* bypass_limits */, 0 /* nAbsurdFee */)) { // If the transaction doesn't make it in to the mempool, remove any // transactions that depend on it (which would now be orphans). @@ -462,16 +474,18 @@ static void UpdateMempoolForReorg(CTxMemPool& mempool, DisconnectedBlockTransact mempool.UpdateTransactionsFromBlock(vHashUpdate); // We also need to remove any now-immature transactions - mempool.removeForReorg(&::ChainstateActive().CoinsTip(), ::ChainActive().Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); - + mempool.removeForReorg(active_chainstate, STANDARD_LOCKTIME_VERIFY_FLAGS); // Re-limit mempool size, in case we added any transactions - LimitMempoolSize(mempool, gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, std::chrono::hours{gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)}); + LimitMempoolSize(mempool, active_chainstate.CoinsTip(), gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, std::chrono::hours{gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)}); } // Used to avoid mempool polluting consensus critical paths if CCoinsViewMempool // were somehow broken and returning the wrong scriptPubKeys -static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& view, const CTxMemPool& pool, - unsigned int flags, PrecomputedTransactionData& txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { +static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, CValidationState& state, + const CCoinsViewCache& view, const CTxMemPool& pool, + unsigned int flags, PrecomputedTransactionData& txdata, CCoinsViewCache& coins_tip) + EXCLUSIVE_LOCKS_REQUIRED(cs_main) +{ AssertLockHeld(cs_main); // pool.cs should be locked already, but go ahead and re-take the lock here @@ -495,7 +509,8 @@ static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, CValidationSt assert(txFrom->vout.size() > txin.prevout.n); assert(txFrom->vout[txin.prevout.n] == coin.out); } else { - const Coin& coinFromDisk = ::ChainstateActive().CoinsTip().AccessCoin(txin.prevout); + assert(std::addressof(::ChainstateActive().CoinsTip()) == std::addressof(coins_tip)); + const Coin& coinFromDisk = coins_tip.AccessCoin(txin.prevout); assert(!coinFromDisk.IsSpent()); assert(coinFromDisk.out == coin.out); } @@ -510,11 +525,13 @@ namespace { class MemPoolAccept { public: - MemPoolAccept(CTxMemPool& mempool) : m_pool(mempool), m_view(&m_dummy), m_viewmempool(&::ChainstateActive().CoinsTip(), m_pool), + explicit MemPoolAccept(CTxMemPool& mempool, CChainState& active_chainstate) : m_pool(mempool), m_view(&m_dummy), m_viewmempool(&active_chainstate.CoinsTip(), m_pool), m_active_chainstate(active_chainstate), m_limit_ancestors(gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT)), m_limit_ancestor_size(gArgs.GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000), m_limit_descendants(gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT)), - m_limit_descendant_size(gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT)*1000) {} + m_limit_descendant_size(gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT)*1000) { + assert(std::addressof(::ChainstateActive()) == std::addressof(m_active_chainstate)); + } // We put the arguments we're handed into a struct, so we can pass them // around easier. @@ -593,6 +610,7 @@ class MemPoolAccept CCoinsViewCache m_view; CCoinsViewMemPool m_viewmempool; CCoinsView m_dummy; + CChainState& m_active_chainstate; // The package limits in effect at the time of invocation. const size_t m_limit_ancestors; @@ -630,7 +648,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) if (!CheckTransaction(tx, state)) return false; // state filled in by CheckTransaction - if (!ContextualCheckTransaction(tx, state, chainparams.GetConsensus(), ::ChainActive().Tip())) + assert(std::addressof(::ChainstateActive()) == std::addressof(m_active_chainstate)); + if (!ContextualCheckTransaction(tx, state, chainparams.GetConsensus(), m_active_chainstate.m_chain.Tip())) return error("%s: ContextualCheckTransaction: %s, %s", __func__, hash.ToString(), FormatStateMessage(state)); if (tx.nVersion == 3 && tx.nType == TRANSACTION_QUORUM_COMMITMENT) { @@ -657,7 +676,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) // Only accept nLockTime-using transactions that can be mined in the next // block; we don't want our mempool filled up with transactions that can't // be mined yet. - if (!CheckFinalTx(tx, STANDARD_LOCKTIME_VERIFY_FLAGS)) + if (!CheckFinalTx(m_active_chainstate.m_chain.Tip(), tx, STANDARD_LOCKTIME_VERIFY_FLAGS)) return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, REJECT_NONSTANDARD, "non-final"); // is it already in the memory pool? @@ -695,7 +714,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) LockPoints lp; m_view.SetBackend(m_viewmempool); - CCoinsViewCache& coins_cache = ::ChainstateActive().CoinsTip(); + assert(std::addressof(::ChainstateActive().CoinsTip()) == std::addressof(m_active_chainstate.CoinsTip())); + CCoinsViewCache& coins_cache = m_active_chainstate.CoinsTip(); // do all inputs exist? for (const CTxIn& txin : tx.vin) { if (!coins_cache.HaveCoinInCache(txin.prevout)) { @@ -734,11 +754,13 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) // be mined yet. // Must keep pool.cs for this unless we change CheckSequenceLocks to take a // CoinsViewCache instead of create its own - if (!CheckSequenceLocks(m_pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp)) + assert(std::addressof(::ChainstateActive()) == std::addressof(m_active_chainstate)); + if (!CheckSequenceLocks(m_active_chainstate, m_pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp)) return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, REJECT_NONSTANDARD, "non-BIP68-final"); + assert(std::addressof(g_chainman.m_blockman) == std::addressof(m_active_chainstate.m_blockman)); CAmount nFees = 0; - if (!Consensus::CheckTxInputs(tx, state, m_view, g_chainman.m_blockman.GetSpendHeight(m_view), nFees)) { + if (!Consensus::CheckTxInputs(tx, state, m_view, m_active_chainstate.m_blockman.GetSpendHeight(m_view), nFees)) { return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), FormatStateMessage(state)); } @@ -763,7 +785,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) } } - entry.reset(new CTxMemPoolEntry(ptx, nFees, nAcceptTime, ::ChainActive().Height(), + assert(std::addressof(::ChainActive()) == std::addressof(m_active_chainstate.m_chain)); + entry.reset(new CTxMemPoolEntry(ptx, nFees, nAcceptTime, m_active_chainstate.m_chain.Height(), fSpendsCoinbase, nSigOps, lp)); unsigned int nSize = entry->GetTxSize(); @@ -806,7 +829,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) // DoS scoring a node for non-critical errors, e.g. duplicate keys because a TX is received that was already // mined // NOTE: we use UTXO here and do NOT allow mempool txes as masternode collaterals - if (!CheckSpecialTx(tx, ::ChainActive().Tip(), state, ::ChainstateActive().CoinsTip(), true)) + if (!CheckSpecialTx(tx, m_active_chainstate.m_chain.Tip(), state, m_active_chainstate.CoinsTip(), true)) return false; if (m_pool.existsProviderTxConflict(tx)) { @@ -857,8 +880,10 @@ bool MemPoolAccept::ConsensusScriptChecks(ATMPArgs& args, Workspace& ws, Precomp // 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(::ChainActive().Tip(), chainparams.GetConsensus()); - if (!CheckInputsFromMempoolAndCache(tx, state, m_view, m_pool, currentBlockScriptVerifyFlags, txdata)) { + assert(std::addressof(::ChainActive()) == std::addressof(m_active_chainstate.m_chain)); + unsigned int currentBlockScriptVerifyFlags = GetBlockScriptFlags(m_active_chainstate.m_chain.Tip(), chainparams.GetConsensus()); + assert(std::addressof(::ChainstateActive().CoinsTip()) == std::addressof(m_active_chainstate.CoinsTip())); + if (!CheckInputsFromMempoolAndCache(tx, state, m_view, m_pool, currentBlockScriptVerifyFlags, txdata, m_active_chainstate.CoinsTip())) { return error("%s: BUG! PLEASE REPORT THIS! CheckInputs failed against latest-block but not STANDARD flags %s, %s", __func__, hash.ToString(), FormatStateMessage(state)); } @@ -881,7 +906,8 @@ bool MemPoolAccept::Finalize(ATMPArgs& args, Workspace& ws) // - the node is not behind // - the transaction is not dependent on any other transactions in the mempool // - the transaction is not a zero fee transaction - bool validForFeeEstimation = (nModifiedFees != 0) && !bypass_limits && IsCurrentForFeeEstimation() && m_pool.HasNoInputsOf(tx); + assert(std::addressof(::ChainstateActive()) == std::addressof(m_active_chainstate)); + bool validForFeeEstimation = (nModifiedFees != 0) && !bypass_limits && IsCurrentForFeeEstimation(m_active_chainstate) && m_pool.HasNoInputsOf(tx); // Store transaction in memory m_pool.addUnchecked(*entry, setAncestors, validForFeeEstimation); @@ -905,7 +931,8 @@ bool MemPoolAccept::Finalize(ATMPArgs& args, Workspace& ws) } if (!bypass_limits) { - LimitMempoolSize(m_pool, gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, std::chrono::hours{gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)}); + assert(std::addressof(::ChainstateActive().CoinsTip()) == std::addressof(m_active_chainstate.CoinsTip())); + LimitMempoolSize(m_pool, m_active_chainstate.CoinsTip(), gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, std::chrono::hours{gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)}); if (!m_pool.exists(hash)) return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "mempool full"); } @@ -954,13 +981,15 @@ bool MemPoolAccept::AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs } // anon namespace /** (try to) add transaction to memory pool with a specified acceptance time **/ -static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, +static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool, CChainState& active_chainstate, CValidationState &state, const CTransactionRef &tx, bool* pfMissingInputs, int64_t nAcceptTime, bool bypass_limits, const CAmount nAbsurdFee, bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { std::vector coins_to_uncache; MemPoolAccept::ATMPArgs args { chainparams, state, pfMissingInputs, nAcceptTime, bypass_limits, nAbsurdFee, coins_to_uncache, test_accept }; - bool res = MemPoolAccept(pool).AcceptSingleTransaction(tx, args); + + assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate)); + bool res = MemPoolAccept(pool, active_chainstate).AcceptSingleTransaction(tx, args); if (!res || test_accept) { if (!res) LogPrint(BCLog::MEMPOOL, "%s: %s %s (%s)\n", __func__, tx->GetHash().ToString(), state.GetRejectReason(), state.GetDebugMessage()); @@ -970,19 +999,20 @@ static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPo // (`CCoinsViewCache::cacheCoins`). for (const COutPoint& hashTx : coins_to_uncache) - ::ChainstateActive().CoinsTip().Uncache(hashTx); + active_chainstate.CoinsTip().Uncache(hashTx); } // After we've (potentially) uncached entries, ensure our coins cache is still within its size limits CValidationState stateDummy; - ::ChainstateActive().FlushStateToDisk(chainparams, stateDummy, FlushStateMode::PERIODIC); + active_chainstate.FlushStateToDisk(chainparams, stateDummy, FlushStateMode::PERIODIC); return res; } -bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, +bool AcceptToMemoryPool(CChainState& active_chainstate, CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, bool* pfMissingInputs, bool bypass_limits, const CAmount nAbsurdFee, bool test_accept) { const CChainParams& chainparams = Params(); - return AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, pfMissingInputs, GetTime(), bypass_limits, nAbsurdFee, test_accept); + assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate)); + return AcceptToMemoryPoolWithTime(chainparams, pool, active_chainstate, state, tx, pfMissingInputs, GetTime(), bypass_limits, nAbsurdFee, test_accept); } bool GetTimestampIndex(const unsigned int &high, const unsigned int &low, std::vector &hashes) @@ -3038,7 +3068,7 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar if (!DisconnectTip(state, chainparams, &disconnectpool)) { // This is likely a fatal error, but keep the mempool consistent, // just in case. Only remove from the mempool in this case. - UpdateMempoolForReorg(m_mempool, disconnectpool, false); + UpdateMempoolForReorg(::ChainstateActive(), m_mempool, disconnectpool, false); // If we're unable to disconnect a block during normal operation, // then that is a failure of our local system -- we should abort @@ -3082,7 +3112,7 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar // A system error occurred (disk space, database error, ...). // Make the mempool consistent with the current tip, just in case // any observers try to use it before shutdown. - UpdateMempoolForReorg(m_mempool, disconnectpool, false); + UpdateMempoolForReorg(::ChainstateActive(), m_mempool, disconnectpool, false); return false; } } else { @@ -3099,7 +3129,7 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar if (fBlocksDisconnected) { // If any blocks were disconnected, disconnectpool may be non empty. Add // any disconnected transactions back to the mempool. - UpdateMempoolForReorg(m_mempool, disconnectpool, true); + UpdateMempoolForReorg(::ChainstateActive(), m_mempool, disconnectpool, true); } m_mempool.check(&CoinsTip()); @@ -3347,7 +3377,7 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c // transactions back to the mempool if disconnecting was successful, // and we're not doing a very deep invalidation (in which case // keeping the mempool up to date is probably futile anyway). - UpdateMempoolForReorg(m_mempool, disconnectpool, /* fAddToMempool = */ (++disconnected <= 10) && ret); + UpdateMempoolForReorg(::ChainstateActive(), m_mempool, disconnectpool, /* fAddToMempool = */ (++disconnected <= 10) && ret); if (!ret) return false; assert(invalid_walk_tip->pprev == m_chain.Tip()); @@ -3493,7 +3523,7 @@ bool CChainState::MarkConflictingBlock(CValidationState& state, const CChainPara if (!DisconnectTip(state, chainparams, &disconnectpool)) { // It's probably hopeless to try to make the mempool consistent // here if DisconnectTip failed, but we can try. - UpdateMempoolForReorg(m_mempool, disconnectpool, false); + UpdateMempoolForReorg(::ChainstateActive(), m_mempool, disconnectpool, false); return false; } if (pindexOldTip == pindexBestHeader) { @@ -3515,7 +3545,7 @@ bool CChainState::MarkConflictingBlock(CValidationState& state, const CChainPara // DisconnectTip will add transactions to disconnectpool; try to add these // back to the mempool. - UpdateMempoolForReorg(m_mempool, disconnectpool, true); + UpdateMempoolForReorg(::ChainstateActive(), m_mempool, disconnectpool, true); } // m_mempool.cs // The resulting new best tip may not be in setBlockIndexCandidates anymore, so @@ -4662,7 +4692,8 @@ bool static LoadBlockIndexDB(ChainstateManager& chainman, const CChainParams& ch void CChainState::LoadMempool(const ArgsManager& args) { if (args.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) { - ::LoadMempool(m_mempool); + assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); + ::LoadMempool(m_mempool, *this); } m_mempool.SetIsLoaded(!ShutdownRequested()); } @@ -5411,7 +5442,7 @@ int VersionBitsTipStateSinceHeight(const Consensus::Params& params, Consensus::D static const uint64_t MEMPOOL_DUMP_VERSION = 1; -bool LoadMempool(CTxMemPool& pool) +bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate) { const CChainParams& chainparams = Params(); int64_t nExpiryTimeout = gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60; @@ -5453,7 +5484,8 @@ bool LoadMempool(CTxMemPool& pool) CValidationState state; if (nTime + nExpiryTimeout > nNow) { LOCK(cs_main); - AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, nullptr /* pfMissingInputs */, nTime, + assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate)); + AcceptToMemoryPoolWithTime(chainparams, pool, active_chainstate, state, tx, nullptr /* pfMissingInputs */, nTime, false /* bypass_limits */, 0 /* nAbsurdFee */, false /* test_accept */); if (state.IsValid()) { ++count; diff --git a/src/validation.h b/src/validation.h index f6cb13cce079..6e79d4a829e9 100644 --- a/src/validation.h +++ b/src/validation.h @@ -217,7 +217,7 @@ void UnlinkPrunedFiles(const std::set& setFilesToPrune); void PruneBlockFilesManual(int nManualPruneHeight); /** (try to) add transaction to memory pool */ -bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, +bool AcceptToMemoryPool(CChainState& active_chainstate, CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, bool* pfMissingInputs, bool bypass_limits, const CAmount nAbsurdFee, bool test_accept=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main); @@ -246,12 +246,12 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight); * * See consensus/consensus.h for flag definitions. */ -bool CheckFinalTx(const CTransaction &tx, int flags = -1) EXCLUSIVE_LOCKS_REQUIRED(cs_main); +bool CheckFinalTx(const CBlockIndex* active_chain_tip, const CTransaction &tx, int flags = -1) EXCLUSIVE_LOCKS_REQUIRED(cs_main); /** * Test whether the LockPoints height and time are still valid on the current chain */ -bool TestLockPointValidity(const LockPoints* lp) EXCLUSIVE_LOCKS_REQUIRED(cs_main); +bool TestLockPointValidity(CChain& active_chain, const LockPoints* lp) EXCLUSIVE_LOCKS_REQUIRED(cs_main); /** * Check if transaction will be BIP 68 final in the next block to be created. @@ -264,7 +264,12 @@ bool TestLockPointValidity(const LockPoints* lp) EXCLUSIVE_LOCKS_REQUIRED(cs_mai * * See consensus/consensus.h for flag definitions. */ -bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flags, LockPoints* lp = nullptr, bool useExistingLockPoints = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main); +bool CheckSequenceLocks(CChainState& active_chainstate, + const CTxMemPool& pool, + const CTransaction& tx, + int flags, + LockPoints* lp = nullptr, + bool useExistingLockPoints = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main); /** * Closure representing one script verification @@ -1046,7 +1051,7 @@ CBlockFileInfo* GetBlockFileInfo(size_t n); bool DumpMempool(const CTxMemPool& pool); /** Load the mempool from disk. */ -bool LoadMempool(CTxMemPool& pool); +bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate); //! Check whether the block associated with this index entry is pruned or not. inline bool IsBlockPruned(const CBlockIndex* pblockindex) From 548e8704c58c861e2e1ecee5d24167b29d5ba3ed Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kittywhiskers@users.noreply.github.com> Date: Mon, 13 Mar 2023 15:37:00 +0000 Subject: [PATCH 34/35] merge bitcoin#21055: Prune remaining g_chainman usage in validation functions Co-authored-by: UdjinM6 --- src/evo/specialtxman.cpp | 2 +- src/governance/classes.cpp | 2 +- src/governance/governance.cpp | 4 +- src/governance/object.cpp | 4 +- src/init.cpp | 8 +- src/llmq/chainlocks.cpp | 2 +- src/llmq/instantsend.cpp | 4 +- src/net_processing.cpp | 4 +- src/rpc/blockchain.cpp | 16 +- src/rpc/governance.cpp | 8 +- src/test/block_reward_reallocation_tests.cpp | 26 +-- .../dynamic_activation_thresholds_tests.cpp | 20 +-- src/test/evo_deterministicmns_tests.cpp | 2 +- src/test/miner_tests.cpp | 2 +- src/test/util/setup_common.cpp | 2 +- src/txmempool.cpp | 11 +- src/txmempool.h | 2 +- src/validation.cpp | 166 ++++++++---------- src/validation.h | 42 ++--- src/versionbits.h | 3 + 20 files changed, 153 insertions(+), 177 deletions(-) diff --git a/src/evo/specialtxman.cpp b/src/evo/specialtxman.cpp index 7a85c790bbbf..54dd69e63c89 100644 --- a/src/evo/specialtxman.cpp +++ b/src/evo/specialtxman.cpp @@ -42,7 +42,7 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVali case TRANSACTION_QUORUM_COMMITMENT: return llmq::CheckLLMQCommitment(tx, pindexPrev, state); case TRANSACTION_MNHF_SIGNAL: - return VersionBitsTipState(Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024) == ThresholdState::ACTIVE && CheckMNHFTx(tx, pindexPrev, state); + return VersionBitsState(::ChainActive().Tip(), Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024, versionbitscache) == ThresholdState::ACTIVE && CheckMNHFTx(tx, pindexPrev, state); } } catch (const std::exception& e) { LogPrintf("%s -- failed: %s\n", __func__, e.what()); diff --git a/src/governance/classes.cpp b/src/governance/classes.cpp index eb0b75c4eedb..c4e305165cb1 100644 --- a/src/governance/classes.cpp +++ b/src/governance/classes.cpp @@ -525,7 +525,7 @@ void CSuperblock::ParsePaymentSchedule(const std::string& strPaymentAddresses, c // TODO: script addresses limit here and cs_main lock in // CGovernanceManager::InitOnLoad()once DIP0024 is active - bool fAllowScript = (VersionBitsTipState(Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024) == ThresholdState::ACTIVE); + bool fAllowScript = (VersionBitsState(::ChainActive().Tip(), Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024, versionbitscache) == ThresholdState::ACTIVE); for (int i = 0; i < (int)vecParsed1.size(); i++) { CTxDestination dest = DecodeDestination(vecParsed1[i]); if (!IsValidDestination(dest)) { diff --git a/src/governance/governance.cpp b/src/governance/governance.cpp index b584f4a0de18..d4c0b37336fb 100644 --- a/src/governance/governance.cpp +++ b/src/governance/governance.cpp @@ -395,7 +395,7 @@ void CGovernanceManager::UpdateCachesAndClean() } else { // NOTE: triggers are handled via triggerman if (pObj->GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) { - bool fAllowScript = (VersionBitsTipState(Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024) == ThresholdState::ACTIVE); + bool fAllowScript = (VersionBitsState(::ChainActive().Tip(), Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024, versionbitscache) == ThresholdState::ACTIVE); CProposalValidator validator(pObj->GetDataAsHexString(), fAllowScript); if (!validator.Validate()) { LogPrint(BCLog::GOBJECT, "CGovernanceManager::UpdateCachesAndClean -- set for deletion expired obj %s\n", strHash); @@ -635,7 +635,7 @@ void CGovernanceManager::SyncObjects(CNode& peer, CConnman& connman) const LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- syncing all objects to peer=%d\n", __func__, peer.GetId()); - bool fAllowScript = WITH_LOCK(cs_main, return VersionBitsTipState(Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024) == ThresholdState::ACTIVE); + bool fAllowScript = WITH_LOCK(cs_main, return VersionBitsState(::ChainActive().Tip(), Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024, versionbitscache) == ThresholdState::ACTIVE); LOCK(cs); diff --git a/src/governance/object.cpp b/src/governance/object.cpp index b05ddd1446c6..8b267e924590 100644 --- a/src/governance/object.cpp +++ b/src/governance/object.cpp @@ -469,7 +469,7 @@ bool CGovernanceObject::IsValidLocally(std::string& strError, bool& fMissingConf switch (nObjectType) { case GOVERNANCE_OBJECT_PROPOSAL: { - bool fAllowScript = (VersionBitsTipState(Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024) == ThresholdState::ACTIVE); + bool fAllowScript = (VersionBitsState(::ChainActive().Tip(), Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024, versionbitscache) == ThresholdState::ACTIVE); CProposalValidator validator(GetDataAsHexString(), fAllowScript); // Note: It's ok to have expired proposals // they are going to be cleared by CGovernanceManager::UpdateCachesAndClean() @@ -692,7 +692,7 @@ void CGovernanceObject::Relay(CConnman& connman) const // But we don't want to relay it to pre-GOVSCRIPT_PROTO_VERSION peers if payment_address is p2sh // because they won't accept it anyway and will simply ban us eventually. LOCK(cs_main); - bool fAllowScript = (VersionBitsTipState(Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024) == ThresholdState::ACTIVE); + bool fAllowScript = (VersionBitsState(::ChainActive().Tip(), Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024, versionbitscache) == ThresholdState::ACTIVE); if (fAllowScript) { CProposalValidator validator(GetDataAsHexString(), false /* no script */); if (!validator.Validate(false /* ignore expiration */)) { diff --git a/src/init.cpp b/src/init.cpp index c0ac35e21831..f2888ae7bbb9 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -904,7 +904,7 @@ static void ThreadImport(ChainstateManager& chainman, std::vector vImp fReindex = false; LogPrintf("Reindexing finished\n"); // To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked): - LoadGenesisBlock(chainparams); + ::ChainstateActive().LoadGenesisBlock(chainparams); } // -loadblock= @@ -2094,7 +2094,7 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc // If we're not mid-reindex (based on disk + args), add a genesis block on disk // (otherwise we use the one already on disk). // This is called again in ThreadImport after the reindex completes. - if (!fReindex && !LoadGenesisBlock(chainparams)) { + if (!fReindex && !::ChainstateActive().LoadGenesisBlock(chainparams)) { strLoadError = _("Error initializing block database"); break; } @@ -2194,7 +2194,7 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc // work when we allow VerifyDB to be parameterized by chainstate. if (&::ChainstateActive() == chainstate && !CVerifyDB().VerifyDB( - chainparams, &chainstate->CoinsDB(), + chainparams, *chainstate, &chainstate->CoinsDB(), *node.evodb, args.GetArg("-checklevel", DEFAULT_CHECKLEVEL), args.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) { @@ -2215,7 +2215,7 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc } if (args.GetArg("-checklevel", DEFAULT_CHECKLEVEL) >= 3) { - ResetBlockFailureFlags(nullptr); + ::ChainstateActive().ResetBlockFailureFlags(nullptr); } } } catch (const std::exception& e) { diff --git a/src/llmq/chainlocks.cpp b/src/llmq/chainlocks.cpp index bcdb89d34840..746a36de4f80 100644 --- a/src/llmq/chainlocks.cpp +++ b/src/llmq/chainlocks.cpp @@ -501,7 +501,7 @@ void CChainLocksHandler::EnforceBestChainLock() // For each of these blocks, check if there are children that are NOT part of the chain referenced by clsig // and mark all of them as conflicting. LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- enforcing block %s via CLSIG (%s)\n", __func__, pindex->GetBlockHash().ToString(), clsig->ToString()); - EnforceBlock(state, params, pindex); + ::ChainstateActive().EnforceBlock(state, params, pindex); bool activateNeeded = WITH_LOCK(::cs_main, return ::ChainActive().Tip()->GetAncestor(currentBestChainLockBlockIndex->nHeight)) != currentBestChainLockBlockIndex; diff --git a/src/llmq/instantsend.cpp b/src/llmq/instantsend.cpp index 7ee02db87cee..d39fb1db88ae 100644 --- a/src/llmq/instantsend.cpp +++ b/src/llmq/instantsend.cpp @@ -1480,7 +1480,7 @@ void CInstantSendManager::ResolveBlockConflicts(const uint256& islockHash, const CValidationState state; // need non-const pointer auto pindex2 = WITH_LOCK(::cs_main, return g_chainman.m_blockman.LookupBlockIndex(pindex->GetBlockHash())); - if (!InvalidateBlock(state, Params(), pindex2)) { + if (!::ChainstateActive().InvalidateBlock(state, Params(), pindex2)) { LogPrintf("CInstantSendManager::%s -- InvalidateBlock failed: %s\n", __func__, FormatStateMessage(state)); // This should not have happened and we are in a state were it's not safe to continue anymore assert(false); @@ -1490,7 +1490,7 @@ void CInstantSendManager::ResolveBlockConflicts(const uint256& islockHash, const } else { LogPrintf("CInstantSendManager::%s -- resetting block %s\n", __func__, pindex2->GetBlockHash().ToString()); LOCK(cs_main); - ResetBlockFailureFlags(pindex2); + ::ChainstateActive().ResetBlockFailureFlags(pindex2); } } diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 5b9882a6dcb2..f6001796eb12 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -2303,7 +2303,7 @@ void static ProcessOrphanTx(CConnman& connman, CTxMemPool& mempool, std::setpprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) { @@ -1420,7 +1420,7 @@ static UniValue verifychain(const JSONRPCRequest& request) const NodeContext& node_context = EnsureNodeContext(request.context); return CVerifyDB().VerifyDB( - Params(), &::ChainstateActive().CoinsTip(), *node_context.evodb, check_level, check_depth); + Params(), ::ChainstateActive(), &::ChainstateActive().CoinsTip(), *node_context.evodb, check_level, check_depth); } /** Implementation of IsSuperMajority with better feedback */ @@ -1456,7 +1456,7 @@ static UniValue SoftForkDesc(const std::string &name, int version, const CBlockI static UniValue BIP9SoftForkDesc(const Consensus::Params& consensusParams, Consensus::DeploymentPos id) { UniValue rv(UniValue::VOBJ); - const ThresholdState thresholdState = VersionBitsTipState(consensusParams, id); + const ThresholdState thresholdState = VersionBitsState(::ChainActive().Tip(), consensusParams, id, versionbitscache); switch (thresholdState) { case ThresholdState::DEFINED: rv.pushKV("status", "defined"); break; case ThresholdState::STARTED: rv.pushKV("status", "started"); break; @@ -1470,11 +1470,11 @@ static UniValue BIP9SoftForkDesc(const Consensus::Params& consensusParams, Conse } rv.pushKV("start_time", consensusParams.vDeployments[id].nStartTime); rv.pushKV("timeout", consensusParams.vDeployments[id].nTimeout); - rv.pushKV("since", VersionBitsTipStateSinceHeight(consensusParams, id)); + rv.pushKV("since", VersionBitsStateSinceHeight(::ChainActive().Tip(), consensusParams, id, versionbitscache)); if (ThresholdState::STARTED == thresholdState) { UniValue statsUV(UniValue::VOBJ); - BIP9Stats statsStruct = VersionBitsTipStatistics(consensusParams, id); + BIP9Stats statsStruct = VersionBitsStatistics(::ChainActive().Tip(), consensusParams, id, versionbitscache); statsUV.pushKV("period", statsStruct.period); statsUV.pushKV("threshold", statsStruct.threshold); statsUV.pushKV("elapsed", statsStruct.elapsed); @@ -1818,7 +1818,7 @@ static UniValue preciousblock(const JSONRPCRequest& request) } CValidationState state; - PreciousBlock(state, Params(), pblockindex); + ::ChainstateActive().PreciousBlock(state, Params(), pblockindex); if (!state.IsValid()) { throw JSONRPCError(RPC_DATABASE_ERROR, FormatStateMessage(state)); @@ -1853,7 +1853,7 @@ static UniValue invalidateblock(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } } - InvalidateBlock(state, Params(), pblockindex); + ::ChainstateActive().InvalidateBlock(state, Params(), pblockindex); if (state.IsValid()) { ::ChainstateActive().ActivateBestChain(state, Params()); @@ -1891,7 +1891,7 @@ static UniValue reconsiderblock(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } - ResetBlockFailureFlags(pblockindex); + ::ChainstateActive().ResetBlockFailureFlags(pblockindex); } CValidationState state; diff --git a/src/rpc/governance.cpp b/src/rpc/governance.cpp index 585d79530eb8..e79eb3251b23 100644 --- a/src/rpc/governance.cpp +++ b/src/rpc/governance.cpp @@ -110,7 +110,7 @@ static UniValue gobject_check(const JSONRPCRequest& request) if (govobj.GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) { LOCK(cs_main); - bool fAllowScript = (VersionBitsTipState(Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024) == ThresholdState::ACTIVE); + bool fAllowScript = (VersionBitsState(::ChainActive().Tip(), Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024, versionbitscache) == ThresholdState::ACTIVE); CProposalValidator validator(strDataHex, fAllowScript); if (!validator.Validate()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid proposal data, error messages:" + validator.GetErrorMessages()); @@ -185,7 +185,7 @@ static UniValue gobject_prepare(const JSONRPCRequest& request) if (govobj.GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) { LOCK(cs_main); - bool fAllowScript = (VersionBitsTipState(Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024) == ThresholdState::ACTIVE); + bool fAllowScript = (VersionBitsState(::ChainActive().Tip(), Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024, versionbitscache) == ThresholdState::ACTIVE); CProposalValidator validator(strDataHex, fAllowScript); if (!validator.Validate()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid proposal data, error messages:" + validator.GetErrorMessages()); @@ -223,7 +223,7 @@ static UniValue gobject_prepare(const JSONRPCRequest& request) CTransactionRef tx; - bool fork_active = WITH_LOCK(cs_main, return VersionBitsTipState(Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024) == ThresholdState::ACTIVE); + bool fork_active = WITH_LOCK(cs_main, return VersionBitsState(::ChainActive().Tip(), Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024, versionbitscache) == ThresholdState::ACTIVE); if (!wallet->GetBudgetSystemCollateralTX(tx, govobj.GetHash(), govobj.GetMinCollateralFee(fork_active), outpoint)) { std::string err = "Error making collateral transaction for governance object. Please check your wallet balance and make sure your wallet is unlocked."; @@ -350,7 +350,7 @@ static UniValue gobject_submit(const JSONRPCRequest& request) if (govobj.GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) { LOCK(cs_main); - bool fAllowScript = (VersionBitsTipState(Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024) == ThresholdState::ACTIVE); + bool fAllowScript = (VersionBitsState(::ChainActive().Tip(), Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024, versionbitscache) == ThresholdState::ACTIVE); CProposalValidator validator(strDataHex, fAllowScript); if (!validator.Validate()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid proposal data, error messages:" + validator.GetErrorMessages()); diff --git a/src/test/block_reward_reallocation_tests.cpp b/src/test/block_reward_reallocation_tests.cpp index 8c457d79237e..81a093136fc1 100644 --- a/src/test/block_reward_reallocation_tests.cpp +++ b/src/test/block_reward_reallocation_tests.cpp @@ -182,9 +182,9 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS } LOCK(cs_main); if (expected_lockin) { - BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::LOCKED_IN); + BOOST_CHECK_EQUAL(VersionBitsState(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache), ThresholdState::LOCKED_IN); } else { - BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::STARTED); + BOOST_CHECK_EQUAL(VersionBitsState(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache), ThresholdState::STARTED); } }; @@ -205,7 +205,7 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS BOOST_ASSERT(deterministicMNManager->GetListAtChainTip().HasMN(tx.GetHash())); BOOST_CHECK_EQUAL(::ChainActive().Height(), 498); - BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::DEFINED); + BOOST_CHECK_EQUAL(VersionBitsState(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache), ThresholdState::DEFINED); } CreateAndProcessBlock({}, coinbaseKey); @@ -216,8 +216,8 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS BOOST_CHECK_EQUAL(::ChainActive().Height(), 499); deterministicMNManager->UpdatedBlockTip(::ChainActive().Tip()); BOOST_ASSERT(deterministicMNManager->GetListAtChainTip().HasMN(tx.GetHash())); - BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::STARTED); - BOOST_CHECK_EQUAL(VersionBitsTipStatistics(consensus_params, deployment_id).threshold, threshold(0)); + BOOST_CHECK_EQUAL(VersionBitsState(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache), ThresholdState::STARTED); + BOOST_CHECK_EQUAL(VersionBitsStatistics(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache).threshold, threshold(0)); // Next block should be signaling by default const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, *m_node.mempool, Params()).CreateNewBlock(coinbasePubKey); const uint32_t bitmask = ((uint32_t)1) << consensus_params.vDeployments[deployment_id].bit; @@ -233,8 +233,8 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS BOOST_CHECK_EQUAL(::ChainActive().Height(), 999); deterministicMNManager->UpdatedBlockTip(::ChainActive().Tip()); BOOST_ASSERT(deterministicMNManager->GetListAtChainTip().HasMN(tx.GetHash())); - BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::STARTED); - BOOST_CHECK_EQUAL(VersionBitsTipStatistics(consensus_params, deployment_id).threshold, threshold(1)); + BOOST_CHECK_EQUAL(VersionBitsState(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache), ThresholdState::STARTED); + BOOST_CHECK_EQUAL(VersionBitsStatistics(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache).threshold, threshold(1)); } signal(threshold(1) - 1, false); // 1 block short again @@ -245,8 +245,8 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS BOOST_CHECK_EQUAL(::ChainActive().Height(), 1499); deterministicMNManager->UpdatedBlockTip(::ChainActive().Tip()); BOOST_ASSERT(deterministicMNManager->GetListAtChainTip().HasMN(tx.GetHash())); - BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::STARTED); - BOOST_CHECK_EQUAL(VersionBitsTipStatistics(consensus_params, deployment_id).threshold, threshold(2)); + BOOST_CHECK_EQUAL(VersionBitsState(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache), ThresholdState::STARTED); + BOOST_CHECK_EQUAL(VersionBitsStatistics(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache).threshold, threshold(2)); } signal(threshold(2), true); // just enough to lock in @@ -257,14 +257,14 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS BOOST_CHECK_EQUAL(::ChainActive().Height(), 1999); deterministicMNManager->UpdatedBlockTip(::ChainActive().Tip()); BOOST_ASSERT(deterministicMNManager->GetListAtChainTip().HasMN(tx.GetHash())); - BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::LOCKED_IN); + BOOST_CHECK_EQUAL(VersionBitsState(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache), ThresholdState::LOCKED_IN); } for ([[maybe_unused]] auto _ : irange::range(499)) { // Still LOCKED_IN at height = 2498 CreateAndProcessBlock({}, coinbaseKey); LOCK(cs_main); - BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::LOCKED_IN); + BOOST_CHECK_EQUAL(VersionBitsState(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache), ThresholdState::LOCKED_IN); } CreateAndProcessBlock({}, coinbaseKey); @@ -274,8 +274,8 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS BOOST_CHECK_EQUAL(::ChainActive().Height(), 2499); deterministicMNManager->UpdatedBlockTip(::ChainActive().Tip()); BOOST_ASSERT(deterministicMNManager->GetListAtChainTip().HasMN(tx.GetHash())); - BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::ACTIVE); - BOOST_CHECK_EQUAL(VersionBitsTipStateSinceHeight(consensus_params, deployment_id), 2500); + BOOST_CHECK_EQUAL(VersionBitsState(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache), ThresholdState::ACTIVE); + BOOST_CHECK_EQUAL(VersionBitsStateSinceHeight(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache), 2500); } { diff --git a/src/test/dynamic_activation_thresholds_tests.cpp b/src/test/dynamic_activation_thresholds_tests.cpp index 1078c2c6f267..bf0ae6793111 100644 --- a/src/test/dynamic_activation_thresholds_tests.cpp +++ b/src/test/dynamic_activation_thresholds_tests.cpp @@ -53,9 +53,9 @@ struct TestChainDATSetup : public TestChainSetup } LOCK(cs_main); if (expected_lockin) { - BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::LOCKED_IN); + BOOST_CHECK_EQUAL(VersionBitsState(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache), ThresholdState::LOCKED_IN); } else { - BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::STARTED); + BOOST_CHECK_EQUAL(VersionBitsState(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache), ThresholdState::STARTED); } } @@ -67,7 +67,7 @@ struct TestChainDATSetup : public TestChainSetup { LOCK(cs_main); BOOST_CHECK_EQUAL(::ChainActive().Height(), window - 2); - BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::DEFINED); + BOOST_CHECK_EQUAL(VersionBitsState(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache), ThresholdState::DEFINED); } CreateAndProcessBlock({}, coinbaseKey); @@ -76,8 +76,8 @@ struct TestChainDATSetup : public TestChainSetup LOCK(cs_main); // Advance from DEFINED to STARTED at height = window - 1 BOOST_CHECK_EQUAL(::ChainActive().Height(), window - 1); - BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::STARTED); - BOOST_CHECK_EQUAL(VersionBitsTipStatistics(consensus_params, deployment_id).threshold, threshold(0)); + BOOST_CHECK_EQUAL(VersionBitsState(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache), ThresholdState::STARTED); + BOOST_CHECK_EQUAL(VersionBitsStatistics(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache).threshold, threshold(0)); // Next block should be signaling by default const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, *m_node.mempool, Params()).CreateNewBlock(coinbasePubKey); const uint32_t bitmask = ((uint32_t)1) << consensus_params.vDeployments[deployment_id].bit; @@ -93,17 +93,17 @@ struct TestChainDATSetup : public TestChainSetup // Still STARTED but with a (potentially) new threshold LOCK(cs_main); BOOST_CHECK_EQUAL(::ChainActive().Height(), window * (i + 2) - 1); - BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::STARTED); - const auto vbts = VersionBitsTipStatistics(consensus_params, deployment_id); + BOOST_CHECK_EQUAL(VersionBitsState(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache), ThresholdState::STARTED); + const auto vbts = VersionBitsStatistics(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache); BOOST_CHECK_EQUAL(vbts.threshold, threshold(i + 1)); BOOST_CHECK(vbts.threshold <= th_start); BOOST_CHECK(vbts.threshold >= th_end); } } if (LOCK(cs_main); check_activation_at_min) { - BOOST_CHECK_EQUAL(VersionBitsTipStatistics(consensus_params, deployment_id).threshold, th_end); + BOOST_CHECK_EQUAL(VersionBitsStatistics(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache).threshold, th_end); } else { - BOOST_CHECK(VersionBitsTipStatistics(consensus_params, deployment_id).threshold > th_end); + BOOST_CHECK(VersionBitsStatistics(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache).threshold > th_end); } // activate @@ -113,7 +113,7 @@ struct TestChainDATSetup : public TestChainSetup } { LOCK(cs_main); - BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::ACTIVE); + BOOST_CHECK_EQUAL(VersionBitsState(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache), ThresholdState::ACTIVE); } } diff --git a/src/test/evo_deterministicmns_tests.cpp b/src/test/evo_deterministicmns_tests.cpp index 20528bc7875c..da8fef5f36fe 100644 --- a/src/test/evo_deterministicmns_tests.cpp +++ b/src/test/evo_deterministicmns_tests.cpp @@ -655,7 +655,7 @@ void FuncVerifyDB(TestChainSetup& setup) // Verify db consistency LOCK(cs_main); - BOOST_ASSERT(CVerifyDB().VerifyDB(Params(), &::ChainstateActive().CoinsTip(), *(setup.m_node.evodb), 4, 2)); + BOOST_ASSERT(CVerifyDB().VerifyDB(Params(), ::ChainstateActive(), &::ChainstateActive().CoinsTip(), *(setup.m_node.evodb), 4, 2)); } BOOST_AUTO_TEST_SUITE(evo_dip3_activation_tests) diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 8244b5d464e8..c14f3f3d19bd 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -537,7 +537,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) } // unlock cs_main while calling InvalidateBlock CValidationState state; - InvalidateBlock(state, chainparams, WITH_LOCK(cs_main, return ::ChainActive().Tip())); + ::ChainstateActive().InvalidateBlock(state, chainparams, WITH_LOCK(cs_main, return ::ChainActive().Tip())); SetMockTime(0); m_node.mempool->clear(); diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 8f38c9306e85..9ff2a2badf75 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -239,7 +239,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector::max()); } -void CTxMemPool::check(const CCoinsViewCache *pcoins) const +void CTxMemPool::check(CChainState& active_chainstate) const { if (m_check_ratio == 0) return; @@ -1043,8 +1043,11 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const uint64_t checkTotal = 0; uint64_t innerUsage = 0; - CCoinsViewCache mempoolDuplicate(const_cast(pcoins)); - const int64_t spendheight = g_chainman.m_blockman.GetSpendHeight(mempoolDuplicate); + CCoinsViewCache& active_coins_tip = active_chainstate.CoinsTip(); + assert(std::addressof(::ChainstateActive().CoinsTip()) == std::addressof(active_coins_tip)); // TODO: REVIEW-ONLY, REMOVE IN FUTURE COMMIT + CCoinsViewCache mempoolDuplicate(const_cast(&active_coins_tip)); + const int64_t spendheight = active_chainstate.m_chain.Height() + 1; + assert(g_chainman.m_blockman.GetSpendHeight(mempoolDuplicate) == spendheight); // TODO: REVIEW-ONLY, REMOVE IN FUTURE COMMIT std::list waitingOnDependants; for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { @@ -1067,7 +1070,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const fDependsWait = true; setParentCheck.insert(it2); } else { - assert(pcoins->HaveCoin(txin.prevout)); + assert(active_coins_tip.HaveCoin(txin.prevout)); } // Check whether its inputs are marked in mapNextTx. auto it3 = mapNextTx.find(txin.prevout); diff --git a/src/txmempool.h b/src/txmempool.h index e093a6733c73..6fa21023a867 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -597,7 +597,7 @@ class CTxMemPool * all inputs are in the mapNextTx array). If sanity-checking is turned off, * check does nothing. */ - void check(const CCoinsViewCache *pcoins) const EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + void check(CChainState& active_chainstate) const EXCLUSIVE_LOCKS_REQUIRED(::cs_main); // addUnchecked must updated state for all ancestors of a given transaction, // to track size/count of descendant transactions. First version of diff --git a/src/validation.cpp b/src/validation.cpp index f3a590bd7cec..b725cc1dd952 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -208,6 +208,7 @@ static FlatFileSeq UndoFileSeq(); bool CheckFinalTx(const CBlockIndex* active_chain_tip, const CTransaction &tx, int flags) { AssertLockHeld(cs_main); + assert(active_chain_tip); // TODO: Make active_chain_tip a reference assert(std::addressof(*::ChainActive().Tip()) == std::addressof(*active_chain_tip)); // By convention a negative value for flags indicates that the @@ -218,12 +219,12 @@ bool CheckFinalTx(const CBlockIndex* active_chain_tip, const CTransaction &tx, i // scheduled, so no flags are set. flags = std::max(flags, 0); - // CheckFinalTx() uses ::ChainActive().Height()+1 to evaluate + // CheckFinalTx() uses active_chain_tip.Height()+1 to evaluate // nLockTime because when IsFinalTx() is called within // CBlock::AcceptBlock(), the height of the block *being* // evaluated is what is used. Thus if we want to know if a // transaction can be part of the *next* block, we need to call - // IsFinalTx() with one more than ::ChainActive().Height(). + // IsFinalTx() with one more than active_chain_tip.Height(). const int nBlockHeight = active_chain_tip->nHeight + 1; // BIP113 requires that time-locked transactions have nLockTime set to @@ -1389,16 +1390,18 @@ static void AlertNotify(const std::string& strMessage) #endif } -static void CheckForkWarningConditions() EXCLUSIVE_LOCKS_REQUIRED(cs_main) +void CChainState::CheckForkWarningConditions() { AssertLockHeld(cs_main); + assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); + // Before we get past initial download, we cannot reliably alert about forks // (we assume we don't get stuck on a fork before finishing our initial sync) - if (::ChainstateActive().IsInitialBlockDownload()) { + if (IsInitialBlockDownload()) { return; } - if (pindexBestInvalid && pindexBestInvalid->nChainWork > ::ChainActive().Tip()->nChainWork + (GetBlockProof(*::ChainActive().Tip()) * 6)) { + if (pindexBestInvalid && pindexBestInvalid->nChainWork > m_chain.Tip()->nChainWork + (GetBlockProof(*m_chain.Tip()) * 6)) { LogPrintf("%s: Warning: Found invalid chain which has higher work (at least ~6 blocks worth of work) than our best chain.\nChain state database corruption likely.\n", __func__); SetfLargeWorkInvalidChainFound(true); } else { @@ -1407,38 +1410,42 @@ static void CheckForkWarningConditions() EXCLUSIVE_LOCKS_REQUIRED(cs_main) } // Called both upon regular invalid block discovery *and* InvalidateBlock -void static InvalidChainFound(CBlockIndex* pindexNew) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +void CChainState::InvalidChainFound(CBlockIndex* pindexNew) { + assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); + statsClient.inc("warnings.InvalidChainFound", 1.0f); if (!pindexBestInvalid || pindexNew->nChainWork > pindexBestInvalid->nChainWork) pindexBestInvalid = pindexNew; if (pindexBestHeader != nullptr && pindexBestHeader->GetAncestor(pindexNew->nHeight) == pindexNew) { - pindexBestHeader = ::ChainActive().Tip(); + pindexBestHeader = m_chain.Tip(); } LogPrintf("%s: invalid block=%s height=%d log2_work=%.8f date=%s\n", __func__, pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, log(pindexNew->nChainWork.getdouble())/log(2.0), FormatISO8601DateTime(pindexNew->GetBlockTime())); - CBlockIndex *tip = ::ChainActive().Tip(); + CBlockIndex *tip = m_chain.Tip(); assert (tip); LogPrintf("%s: current best=%s height=%d log2_work=%.8f date=%s\n", __func__, - tip->GetBlockHash().ToString(), ::ChainActive().Height(), log(tip->nChainWork.getdouble())/log(2.0), + tip->GetBlockHash().ToString(), m_chain.Height(), log(tip->nChainWork.getdouble())/log(2.0), FormatISO8601DateTime(tip->GetBlockTime())); CheckForkWarningConditions(); } -void static ConflictingChainFound(CBlockIndex* pindexNew) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +void CChainState::ConflictingChainFound(CBlockIndex* pindexNew) { + assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); + statsClient.inc("warnings.ConflictingChainFound", 1.0f); LogPrintf("%s: conflicting block=%s height=%d log2_work=%.8f date=%s\n", __func__, pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, log(pindexNew->nChainWork.getdouble())/log(2.0), FormatISO8601DateTime(pindexNew->GetBlockTime())); - CBlockIndex *tip = ::ChainActive().Tip(); + CBlockIndex *tip = m_chain.Tip(); assert (tip); LogPrintf("%s: current best=%s height=%d log2_work=%.8f date=%s\n", __func__, - tip->GetBlockHash().ToString(), ::ChainActive().Height(), log(tip->nChainWork.getdouble())/log(2.0), + tip->GetBlockHash().ToString(), m_chain.Height(), log(tip->nChainWork.getdouble())/log(2.0), FormatISO8601DateTime(tip->GetBlockTime())); CheckForkWarningConditions(); } @@ -2742,7 +2749,7 @@ static void AppendWarning(std::string& res, const std::string& warn) } /** Check warning conditions and do some notifications on new chain tip set. */ -void static UpdateTip(CTxMemPool& mempool, const CBlockIndex *pindexNew, const CChainParams& chainParams, const CEvoDB& evoDb) +static void UpdateTip(CTxMemPool& mempool, const CBlockIndex* pindexNew, const CChainParams& chainParams, CChainState& active_chainstate, const CEvoDB& evoDb) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { // New best block @@ -2755,7 +2762,8 @@ void static UpdateTip(CTxMemPool& mempool, const CBlockIndex *pindexNew, const C } std::string warningMessages; - if (!::ChainstateActive().IsInitialBlockDownload()) + assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate)); + if (!active_chainstate.IsInitialBlockDownload()) { int nUpgraded = 0; const CBlockIndex* pindex = pindexNew; @@ -2782,11 +2790,12 @@ void static UpdateTip(CTxMemPool& mempool, const CBlockIndex *pindexNew, const C if (nUpgraded > 0) AppendWarning(warningMessages, strprintf(_("%d of last 100 blocks have unexpected version").translated, nUpgraded)); } + assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate)); LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu date='%s' progress=%f cache=%.1fMiB(%utxo) evodb_cache=%.1fMiB%s\n", __func__, pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, pindexNew->nVersion, log(pindexNew->nChainWork.getdouble())/log(2.0), (unsigned long)pindexNew->nChainTx, FormatISO8601DateTime(pindexNew->GetBlockTime()), - GuessVerificationProgress(chainParams.TxData(), pindexNew), ::ChainstateActive().CoinsTip().DynamicMemoryUsage() * (1.0 / (1<<20)), ::ChainstateActive().CoinsTip().GetCacheSize(), + GuessVerificationProgress(chainParams.TxData(), pindexNew), active_chainstate.CoinsTip().DynamicMemoryUsage() * (1.0 / (1<<20)), active_chainstate.CoinsTip().GetCacheSize(), evoDb.GetMemoryUsage() * (1.0 / (1<<20)), !warningMessages.empty() ? strprintf(" warning='%s'", warningMessages) : ""); } @@ -2846,7 +2855,7 @@ bool CChainState::DisconnectTip(CValidationState& state, const CChainParams& cha m_chain.SetTip(pindexDelete->pprev); - UpdateTip(m_mempool, pindexDelete->pprev, chainparams, *m_evoDb); + UpdateTip(m_mempool, pindexDelete->pprev, chainparams, *this, *m_evoDb); // Let wallets know transactions went from 1-confirmed to // 0-confirmed or conflicted: GetMainSignals().BlockDisconnected(pblock, pindexDelete); @@ -2958,7 +2967,7 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp disconnectpool.removeForBlock(blockConnecting.vtx); // Update m_chain & related variables. m_chain.SetTip(pindexNew); - UpdateTip(m_mempool, pindexNew, chainparams, *m_evoDb); + UpdateTip(m_mempool, pindexNew, chainparams, *this, *m_evoDb); int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1; LogPrint(BCLog::BENCHMARK, " - Connect postprocess: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime6 - nTime5) * MILLI, nTimePostConnect * MICRO, nTimePostConnect * MILLI / nBlocksTotal); @@ -3057,6 +3066,7 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar { AssertLockHeld(cs_main); AssertLockHeld(m_mempool.cs); + assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); const CBlockIndex* pindexOldTip = m_chain.Tip(); const CBlockIndex* pindexFork = m_chain.FindFork(pindexMostWork); @@ -3068,7 +3078,7 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar if (!DisconnectTip(state, chainparams, &disconnectpool)) { // This is likely a fatal error, but keep the mempool consistent, // just in case. Only remove from the mempool in this case. - UpdateMempoolForReorg(::ChainstateActive(), m_mempool, disconnectpool, false); + UpdateMempoolForReorg(*this, m_mempool, disconnectpool, false); // If we're unable to disconnect a block during normal operation, // then that is a failure of our local system -- we should abort @@ -3112,7 +3122,7 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar // A system error occurred (disk space, database error, ...). // Make the mempool consistent with the current tip, just in case // any observers try to use it before shutdown. - UpdateMempoolForReorg(::ChainstateActive(), m_mempool, disconnectpool, false); + UpdateMempoolForReorg(*this, m_mempool, disconnectpool, false); return false; } } else { @@ -3129,9 +3139,9 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar if (fBlocksDisconnected) { // If any blocks were disconnected, disconnectpool may be non empty. Add // any disconnected transactions back to the mempool. - UpdateMempoolForReorg(::ChainstateActive(), m_mempool, disconnectpool, true); + UpdateMempoolForReorg(*this, m_mempool, disconnectpool, true); } - m_mempool.check(&CoinsTip()); + m_mempool.check(*this); CheckForkWarningConditions(); @@ -3303,9 +3313,6 @@ bool CChainState::PreciousBlock(CValidationState& state, const CChainParams& par return ActivateBestChain(state, params, std::shared_ptr()); } -bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex) { - return ::ChainstateActive().PreciousBlock(state, params, pindex); -} bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex) { @@ -3377,7 +3384,8 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c // transactions back to the mempool if disconnecting was successful, // and we're not doing a very deep invalidation (in which case // keeping the mempool up to date is probably futile anyway). - UpdateMempoolForReorg(::ChainstateActive(), m_mempool, disconnectpool, /* fAddToMempool = */ (++disconnected <= 10) && ret); + assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); + UpdateMempoolForReorg(*this, m_mempool, disconnectpool, /* fAddToMempool = */ (++disconnected <= 10) && ret); if (!ret) return false; assert(invalid_walk_tip->pprev == m_chain.Tip()); @@ -3460,19 +3468,16 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c return true; } -bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex) { - return ::ChainstateActive().InvalidateBlock(state, chainparams, pindex); -} - void CChainState::EnforceBlock(CValidationState& state, const CChainParams& chainparams, const CBlockIndex *pindex) { AssertLockNotHeld(::cs_main); LOCK2(m_cs_chainstate, ::cs_main); + assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); const CBlockIndex* pindex_walk = pindex; - while (pindex_walk && !::ChainActive().Contains(pindex_walk)) { + while (pindex_walk && !m_chain.Contains(pindex_walk)) { // Mark all blocks that have the same prevBlockHash but are not equal to blockHash as conflicting auto itp = g_chainman.PrevBlockIndex().equal_range(pindex_walk->pprev->GetBlockHash()); for (auto jt = itp.first; jt != itp.second; ++jt) { @@ -3495,13 +3500,10 @@ void CChainState::EnforceBlock(CValidationState& state, const CChainParams& chai } } -void EnforceBlock(CValidationState& state, const CChainParams& chainparams, const CBlockIndex *pindex) { - return ::ChainstateActive().EnforceBlock(state, chainparams, pindex); -} - bool CChainState::MarkConflictingBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex) { AssertLockHeld(cs_main); + assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); // We first disconnect backwards and then mark the blocks as conflicting. @@ -3523,7 +3525,7 @@ bool CChainState::MarkConflictingBlock(CValidationState& state, const CChainPara if (!DisconnectTip(state, chainparams, &disconnectpool)) { // It's probably hopeless to try to make the mempool consistent // here if DisconnectTip failed, but we can try. - UpdateMempoolForReorg(::ChainstateActive(), m_mempool, disconnectpool, false); + UpdateMempoolForReorg(*this, m_mempool, disconnectpool, false); return false; } if (pindexOldTip == pindexBestHeader) { @@ -3545,7 +3547,7 @@ bool CChainState::MarkConflictingBlock(CValidationState& state, const CChainPara // DisconnectTip will add transactions to disconnectpool; try to add these // back to the mempool. - UpdateMempoolForReorg(::ChainstateActive(), m_mempool, disconnectpool, true); + UpdateMempoolForReorg(*this, m_mempool, disconnectpool, true); } // m_mempool.cs // The resulting new best tip may not be in setBlockIndexCandidates anymore, so @@ -3630,10 +3632,6 @@ void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) { } } -void ResetBlockFailureFlags(CBlockIndex *pindex) { - return ::ChainstateActive().ResetBlockFailureFlags(pindex); -} - CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block, enum BlockStatus nStatus) { assert(!(nStatus & BLOCK_FAILED_MASK)); // no failed blocks allowed @@ -3727,7 +3725,7 @@ void CChainState::ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pi } } -static bool FindBlockPos(FlatFilePos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false) +static bool FindBlockPos(FlatFilePos &pos, unsigned int nAddSize, unsigned int nHeight, CChain& active_chain, uint64_t nTime, bool fKnown = false) { LOCK(cs_LastBlockFile); @@ -3742,7 +3740,8 @@ static bool FindBlockPos(FlatFilePos &pos, unsigned int nAddSize, unsigned int n // when the undo file is keeping up with the block file, we want to flush it explicitly // when it is lagging behind (more blocks arrive than are being connected), we let the // undo block write case handle it - finalize_undo = (vinfoBlockFile[nFile].nHeightLast == (unsigned int)::ChainActive().Tip()->nHeight); + assert(std::addressof(::ChainActive()) == std::addressof(active_chain)); + finalize_undo = (vinfoBlockFile[nFile].nHeightLast == (unsigned int)active_chain.Tip()->nHeight); nFile++; if (vinfoBlockFile.size() <= nFile) { vinfoBlockFile.resize(nFile + 1); @@ -4161,12 +4160,12 @@ bool ChainstateManager::ProcessNewBlockHeaders(const std::vector& } /** Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */ -static FlatFilePos SaveBlockToDisk(const CBlock& block, int nHeight, const CChainParams& chainparams, const FlatFilePos* dbp) { +static FlatFilePos SaveBlockToDisk(const CBlock& block, int nHeight, CChain& active_chain, const CChainParams& chainparams, const FlatFilePos* dbp) { unsigned int nBlockSize = ::GetSerializeSize(block, CLIENT_VERSION); FlatFilePos blockPos; if (dbp != nullptr) blockPos = *dbp; - if (!FindBlockPos(blockPos, nBlockSize+8, nHeight, block.GetBlockTime(), dbp != nullptr)) { + if (!FindBlockPos(blockPos, nBlockSize+8, nHeight, active_chain, block.GetBlockTime(), dbp != nullptr)) { error("%s: FindBlockPos failed", __func__); return FlatFilePos(); } @@ -4247,8 +4246,9 @@ bool CChainState::AcceptBlock(const std::shared_ptr& pblock, CVali // Write block to history file if (fNewBlock) *fNewBlock = true; + assert(std::addressof(::ChainActive()) == std::addressof(m_chain)); try { - FlatFilePos blockPos = SaveBlockToDisk(block, pindex->nHeight, chainparams, dbp); + FlatFilePos blockPos = SaveBlockToDisk(block, pindex->nHeight, m_chain, chainparams, dbp); if (blockPos.IsNull()) { state.Error(strprintf("%s: Failed to find position to write new block to disk", __func__)); return false; @@ -4437,11 +4437,12 @@ void BlockManager::FindFilesToPruneManual(std::set& setFilesToPrune, int nM } /* This function is called from the RPC code for pruneblockchain */ -void PruneBlockFilesManual(int nManualPruneHeight) +void PruneBlockFilesManual(CChainState& active_chainstate, int nManualPruneHeight) { CValidationState state; const CChainParams& chainparams = Params(); - if (!::ChainstateActive().FlushStateToDisk( + assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate)); + if (!active_chainstate.FlushStateToDisk( chainparams, state, FlushStateMode::NONE, nManualPruneHeight)) { LogPrintf("%s: failed to flush state (%s)\n", __func__, FormatStateMessage(state)); } @@ -4622,11 +4623,12 @@ void BlockManager::Unload() { m_prev_block_index.clear(); } -bool static LoadBlockIndexDB(ChainstateManager& chainman, const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +bool CChainState::LoadBlockIndexDB(const CChainParams& chainparams) { - if (!chainman.m_blockman.LoadBlockIndex( + assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); + if (!m_blockman.LoadBlockIndex( chainparams.GetConsensus(), *pblocktree, - ::ChainstateActive().setBlockIndexCandidates)) { + setBlockIndexCandidates)) { return false; } @@ -4650,7 +4652,7 @@ bool static LoadBlockIndexDB(ChainstateManager& chainman, const CChainParams& ch // Check presence of blk files LogPrintf("Checking all blk files are present...\n"); std::set setBlkDataFiles; - for (const std::pair& item : chainman.BlockIndex()) { + for (const std::pair& item : m_blockman.m_block_index) { CBlockIndex* pindex = item.second; if (pindex->nStatus & BLOCK_HAVE_DATA) { setBlkDataFiles.insert(pindex->nFile); @@ -4736,18 +4738,20 @@ CVerifyDB::~CVerifyDB() uiInterface.ShowProgress("", 100, false); } -bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, CEvoDB& evoDb, int nCheckLevel, int nCheckDepth) +bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CChainState& active_chainstate, CCoinsView *coinsview, CEvoDB& evoDb, int nCheckLevel, int nCheckDepth) { - LOCK(cs_main); - if (::ChainActive().Tip() == nullptr || ::ChainActive().Tip()->pprev == nullptr) + AssertLockHeld(cs_main); + + assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate)); + if (active_chainstate.m_chain.Tip() == nullptr || active_chainstate.m_chain.Tip()->pprev == nullptr) return true; // begin tx and let it rollback auto dbTx = evoDb.BeginTransaction(); // Verify blocks in the best chain - if (nCheckDepth <= 0 || nCheckDepth > ::ChainActive().Height()) - nCheckDepth = ::ChainActive().Height(); + if (nCheckDepth <= 0 || nCheckDepth > active_chainstate.m_chain.Height()) + nCheckDepth = active_chainstate.m_chain.Height(); nCheckLevel = std::max(0, std::min(4, nCheckLevel)); LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel); CCoinsViewCache coins(coinsview); @@ -4757,15 +4761,15 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, CValidationState state; int reportDone = 0; LogPrintf("[0%%]..."); /* Continued */ - for (pindex = ::ChainActive().Tip(); pindex && pindex->pprev; pindex = pindex->pprev) { - const int percentageDone = std::max(1, std::min(99, (int)(((double)(::ChainActive().Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100)))); + for (pindex = active_chainstate.m_chain.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) { + const int percentageDone = std::max(1, std::min(99, (int)(((double)(active_chainstate.m_chain.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100)))); if (reportDone < percentageDone/10) { // report every 10% step LogPrintf("[%d%%]...", percentageDone); /* Continued */ reportDone = percentageDone/10; } uiInterface.ShowProgress(_("Verifying blocks...").translated, percentageDone, false); - if (pindex->nHeight <= ::ChainActive().Height()-nCheckDepth) + if (pindex->nHeight <= active_chainstate.m_chain.Height()-nCheckDepth) break; if (fPruneMode && !(pindex->nStatus & BLOCK_HAVE_DATA)) { // If pruning, only go back as far as we have data. @@ -4790,9 +4794,9 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, } } // check level 3: check for inconsistencies during memory-only disconnect of tip blocks - if (nCheckLevel >= 3 && (coins.DynamicMemoryUsage() + ::ChainstateActive().CoinsTip().DynamicMemoryUsage()) <= ::ChainstateActive().m_coinstip_cache_size_bytes) { + if (nCheckLevel >= 3 && (coins.DynamicMemoryUsage() + active_chainstate.CoinsTip().DynamicMemoryUsage()) <= active_chainstate.m_coinstip_cache_size_bytes) { assert(coins.GetBestBlock() == pindex->GetBlockHash()); - DisconnectResult res = ::ChainstateActive().DisconnectBlock(block, pindex, coins); + DisconnectResult res = active_chainstate.DisconnectBlock(block, pindex, coins); if (res == DISCONNECT_FAILED) { return error("VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); } @@ -4806,26 +4810,26 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, if (ShutdownRequested()) return true; } if (pindexFailure) - return error("VerifyDB(): *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", ::ChainActive().Height() - pindexFailure->nHeight + 1, nGoodTransactions); + return error("VerifyDB(): *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", active_chainstate.m_chain.Height() - pindexFailure->nHeight + 1, nGoodTransactions); // store block count as we move pindex at check level >= 4 - int block_count = ::ChainActive().Height() - pindex->nHeight; + int block_count = active_chainstate.m_chain.Height() - pindex->nHeight; // check level 4: try reconnecting blocks if (nCheckLevel >= 4) { - while (pindex != ::ChainActive().Tip()) { - const int percentageDone = std::max(1, std::min(99, 100 - (int)(((double)(::ChainActive().Height() - pindex->nHeight)) / (double)nCheckDepth * 50))); + while (pindex != active_chainstate.m_chain.Tip()) { + const int percentageDone = std::max(1, std::min(99, 100 - (int)(((double)(active_chainstate.m_chain.Height() - pindex->nHeight)) / (double)nCheckDepth * 50))); if (reportDone < percentageDone/10) { // report every 10% step LogPrintf("[%d%%]...", percentageDone); /* Continued */ reportDone = percentageDone/10; } uiInterface.ShowProgress(_("Verifying blocks...").translated, percentageDone, false); - pindex = ::ChainActive().Next(pindex); + pindex = active_chainstate.m_chain.Next(pindex); CBlock block; if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); - if (!::ChainstateActive().ConnectBlock(block, state, pindex, coins, chainparams)) + if (!active_chainstate.ConnectBlock(block, state, pindex, coins, chainparams)) return error("VerifyDB(): *** found unconnectable block at %d, hash=%s (%s)", pindex->nHeight, pindex->GetBlockHash().ToString(), FormatStateMessage(state)); if (ShutdownRequested()) return true; } @@ -4975,7 +4979,7 @@ bool ChainstateManager::LoadBlockIndex(const CChainParams& chainparams) // Load block index from databases bool needs_init = fReindex; if (!fReindex) { - bool ret = LoadBlockIndexDB(*this, chainparams); + bool ret = ActiveChainstate().LoadBlockIndexDB(chainparams); if (!ret) return false; needs_init = m_blockman.m_block_index.empty(); } @@ -5006,7 +5010,8 @@ bool ChainstateManager::LoadBlockIndex(const CChainParams& chainparams) bool CChainState::AddGenesisBlock(const CChainParams& chainparams, const CBlock& block, CValidationState& state) { - FlatFilePos blockPos = SaveBlockToDisk(block, 0, chainparams, nullptr); + assert(std::addressof(::ChainActive()) == std::addressof(m_chain)); + FlatFilePos blockPos = SaveBlockToDisk(block, 0, m_chain, chainparams, nullptr); if (blockPos.IsNull()) return error("%s: writing genesis block to disk failed (%s)", __func__, FormatStateMessage(state)); CBlockIndex* pindex = m_blockman.AddToBlockIndex(block); @@ -5047,11 +5052,6 @@ bool CChainState::LoadGenesisBlock(const CChainParams& chainparams) return true; } -bool LoadGenesisBlock(const CChainParams& chainparams) -{ - return ::ChainstateActive().LoadGenesisBlock(chainparams); -} - void CChainState::LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFilePos* dbp) { // Map of disk positions for blocks with unknown parent (only used for reindex) @@ -5422,24 +5422,6 @@ CBlockFileInfo* GetBlockFileInfo(size_t n) return &vinfoBlockFile.at(n); } -ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos) -{ - AssertLockHeld(cs_main); - return VersionBitsState(::ChainActive().Tip(), params, pos, versionbitscache); -} - -BIP9Stats VersionBitsTipStatistics(const Consensus::Params& params, Consensus::DeploymentPos pos) -{ - LOCK(cs_main); - return VersionBitsStatistics(::ChainActive().Tip(), params, pos, versionbitscache); -} - -int VersionBitsTipStateSinceHeight(const Consensus::Params& params, Consensus::DeploymentPos pos) -{ - LOCK(cs_main); - return VersionBitsStateSinceHeight(::ChainActive().Tip(), params, pos, versionbitscache); -} - static const uint64_t MEMPOOL_DUMP_VERSION = 1; bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate) diff --git a/src/validation.h b/src/validation.h index 6e79d4a829e9..d3e94f155377 100644 --- a/src/validation.h +++ b/src/validation.h @@ -214,7 +214,7 @@ uint64_t CalculateCurrentUsage(); void UnlinkPrunedFiles(const std::set& setFilesToPrune); /** Prune block files up to a given height */ -void PruneBlockFilesManual(int nManualPruneHeight); +void PruneBlockFilesManual(CChainState& active_chainstate, int nManualPruneHeight); /** (try to) add transaction to memory pool */ bool AcceptToMemoryPool(CChainState& active_chainstate, CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, @@ -225,15 +225,6 @@ bool GetUTXOCoin(const COutPoint& outpoint, Coin& coin); int GetUTXOHeight(const COutPoint& outpoint); int GetUTXOConfirmations(const COutPoint& outpoint); -/** Get the BIP9 state for a given deployment at the current tip. */ -ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos); - -/** Get the numerical statistics for the BIP9 state for a given deployment at the current tip. */ -BIP9Stats VersionBitsTipStatistics(const Consensus::Params& params, Consensus::DeploymentPos pos); - -/** Get the block height at which the BIP9 deployment switched into the state for the block building on the current tip. */ -int VersionBitsTipStateSinceHeight(const Consensus::Params& params, Consensus::DeploymentPos pos); - /** Apply the effects of this transaction on the UTXO set represented by view */ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight); @@ -344,7 +335,7 @@ class CVerifyDB { public: CVerifyDB(); ~CVerifyDB(); - bool VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, CEvoDB& evoDb, int nCheckLevel, int nCheckDepth); + bool VerifyDB(const CChainParams& chainparams, CChainState& active_chainstate, CCoinsView *coinsview, CEvoDB& evoDb, int nCheckLevel, int nCheckDepth) EXCLUSIVE_LOCKS_REQUIRED(cs_main); }; enum DisconnectResult { @@ -727,9 +718,16 @@ class CChainState bool DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions* disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool.cs); // Manual block validity manipulation: + /** Mark a block as precious and reorganize. + * + * May not be called in a validationinterface callback. + */ bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main); + /** Mark a block as invalid. */ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main); + /** Enforce a block marking all the other chains as conflicting. */ void EnforceBlock(CValidationState& state, const CChainParams& chainparams, const CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main); + /** Remove invalidity status from a block and its descendants. */ void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); /** Replay blocks that aren't fully applied to the database. */ @@ -787,24 +785,14 @@ class CChainState //! Mark a block as not having block data void EraseBlockData(CBlockIndex* index) EXCLUSIVE_LOCKS_REQUIRED(cs_main); - friend ChainstateManager; -}; + void CheckForkWarningConditions() EXCLUSIVE_LOCKS_REQUIRED(cs_main); + void InvalidChainFound(CBlockIndex* pindexNew) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + void ConflictingChainFound(CBlockIndex* pindexNew) EXCLUSIVE_LOCKS_REQUIRED(cs_main); -/** Mark a block as precious and reorganize. - * - * May not be called in a - * validationinterface callback. - */ -bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex) LOCKS_EXCLUDED(cs_main); - -/** Mark a block as invalid. */ -bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main); + bool LoadBlockIndexDB(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main); -/** Enforce a block marking all the other chains as conflicting. */ -void EnforceBlock(CValidationState& state, const CChainParams& chainparams, const CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main); - -/** Remove invalidity status from a block and its descendants. */ -void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + friend ChainstateManager; +}; /** * Provides an interface for creating and interacting with one or two diff --git a/src/versionbits.h b/src/versionbits.h index cba2bae77703..cd34d2ecb5b4 100644 --- a/src/versionbits.h +++ b/src/versionbits.h @@ -79,8 +79,11 @@ struct VersionBitsCache void Clear(); }; +/** Get the BIP9 state for a given deployment at the current tip. */ ThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache); +/** Get the numerical statistics for the BIP9 state for a given deployment at the current tip. */ BIP9Stats VersionBitsStatistics(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache); +/** Get the block height at which the BIP9 deployment switched into the state for the block building on the current tip. */ int VersionBitsStateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache); uint32_t VersionBitsMask(const Consensus::Params& params, Consensus::DeploymentPos pos); From 24a5552918e434178e4cf608b73a9d224056b49a Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kittywhiskers@users.noreply.github.com> Date: Mon, 8 Mar 2021 15:48:42 -0500 Subject: [PATCH 35/35] partial bitcoin#21270: Prune g_chainman usage in validation-adjacent modules contains: - a04aac493fd564894166d58ed4cdfd9ad4f561cb - d0de61b764fc7e9c670b69d8210705da296dd245 - 46b7f29340acb399fbd2378508a204d8d8ee8fca - 2afcf24408b4453e4418ebfb326b141f6ea8647c --- src/miner.cpp | 9 +++-- src/miner.h | 2 +- src/rpc/mining.cpp | 6 +-- src/test/block_reward_reallocation_tests.cpp | 14 +++---- src/test/blockfilter_index_tests.cpp | 2 +- .../dynamic_activation_thresholds_tests.cpp | 2 +- src/test/miner_tests.cpp | 38 +++++++++---------- src/test/util.cpp | 2 +- src/test/util/setup_common.cpp | 2 +- src/test/validation_block_tests.cpp | 2 +- src/validation.h | 3 +- 11 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 92ed3c6a2b4a..3e4b4171ec52 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -108,7 +108,7 @@ void BlockAssembler::resetBlock() nFees = 0; } -std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn) +std::unique_ptr BlockAssembler::CreateNewBlock(CChainState& chainstate, const CScript& scriptPubKeyIn) { int64_t nTimeStart = GetTimeMicros(); @@ -126,8 +126,8 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc pblocktemplate->vTxSigOps.push_back(-1); // updated at end LOCK2(cs_main, m_mempool.cs); - - CBlockIndex* pindexPrev = ::ChainActive().Tip(); + assert(std::addressof(*::ChainActive().Tip()) == std::addressof(*chainstate.m_chain.Tip())); + CBlockIndex* pindexPrev = chainstate.m_chain.Tip(); assert(pindexPrev != nullptr); nHeight = pindexPrev->nHeight + 1; @@ -234,7 +234,8 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(*pblock->vtx[0]); CValidationState state; - if (!TestBlockValidity(state, m_clhandler, m_evoDb, chainparams, ::ChainstateActive(), *pblock, pindexPrev, false, false)) { + assert(std::addressof(::ChainstateActive()) == std::addressof(chainstate)); + if (!TestBlockValidity(state, m_clhandler, m_evoDb, chainparams, chainstate, *pblock, pindexPrev, false, false)) { throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state))); } int64_t nTime2 = GetTimeMicros(); diff --git a/src/miner.h b/src/miner.h index e44dbcdf0db7..097e1bb67b39 100644 --- a/src/miner.h +++ b/src/miner.h @@ -177,7 +177,7 @@ class BlockAssembler llmq::CInstantSendManager& isman, CEvoDB& evoDb, const CTxMemPool& mempool, const CChainParams& params, const Options& options); /** Construct a new block template with coinbase to scriptPubKeyIn */ - std::unique_ptr CreateNewBlock(const CScript& scriptPubKeyIn); + std::unique_ptr CreateNewBlock(CChainState& chainstate, const CScript& scriptPubKeyIn); inline static std::optional m_last_block_num_txs{}; inline static std::optional m_last_block_size{}; diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index cd862c836679..c65a4512c265 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -161,7 +161,7 @@ static UniValue generateBlocks(ChainstateManager& chainman, const CTxMemPool& me UniValue blockHashes(UniValue::VARR); while (nHeight < nHeightEnd && !ShutdownRequested()) { - std::unique_ptr pblocktemplate(BlockAssembler(*sporkManager, *governance, quorum_block_processor, clhandler, isman, evodb, mempool, Params()).CreateNewBlock(coinbase_script)); + std::unique_ptr pblocktemplate(BlockAssembler(*sporkManager, *governance, quorum_block_processor, clhandler, isman, evodb, mempool, Params()).CreateNewBlock(::ChainstateActive(), coinbase_script)); if (!pblocktemplate.get()) throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); CBlock *pblock = &pblocktemplate->block; @@ -367,7 +367,7 @@ static UniValue generateblock(const JSONRPCRequest& request) LOCK(cs_main); CTxMemPool empty_mempool; - std::unique_ptr blocktemplate(BlockAssembler(*sporkManager, *governance, *llmq_ctx.quorum_block_processor, *llmq_ctx.clhandler, *llmq_ctx.isman, *node_context.evodb, empty_mempool, chainparams).CreateNewBlock(coinbase_script)); + std::unique_ptr blocktemplate(BlockAssembler(*sporkManager, *governance, *llmq_ctx.quorum_block_processor, *llmq_ctx.clhandler, *llmq_ctx.isman, *node_context.evodb, empty_mempool, chainparams).CreateNewBlock(::ChainstateActive(), coinbase_script)); if (!blocktemplate) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); } @@ -779,7 +779,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) // Create new block CScript scriptDummy = CScript() << OP_TRUE; LLMQContext& llmq_ctx = EnsureLLMQContext(request.context); - pblocktemplate = BlockAssembler(*sporkManager, *governance, *llmq_ctx.quorum_block_processor, *llmq_ctx.clhandler, *llmq_ctx.isman, *node_context.evodb, mempool, Params()).CreateNewBlock(scriptDummy); + pblocktemplate = BlockAssembler(*sporkManager, *governance, *llmq_ctx.quorum_block_processor, *llmq_ctx.clhandler, *llmq_ctx.isman, *node_context.evodb, mempool, Params()).CreateNewBlock(::ChainstateActive(), scriptDummy); if (!pblocktemplate) throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); diff --git a/src/test/block_reward_reallocation_tests.cpp b/src/test/block_reward_reallocation_tests.cpp index 81a093136fc1..9ea366407059 100644 --- a/src/test/block_reward_reallocation_tests.cpp +++ b/src/test/block_reward_reallocation_tests.cpp @@ -219,7 +219,7 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS BOOST_CHECK_EQUAL(VersionBitsState(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache), ThresholdState::STARTED); BOOST_CHECK_EQUAL(VersionBitsStatistics(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache).threshold, threshold(0)); // Next block should be signaling by default - const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, *m_node.mempool, Params()).CreateNewBlock(coinbasePubKey); + const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, *m_node.mempool, Params()).CreateNewBlock(::ChainstateActive(), coinbasePubKey); const uint32_t bitmask = ((uint32_t)1) << consensus_params.vDeployments[deployment_id].bit; BOOST_CHECK_EQUAL(::ChainActive().Tip()->nVersion & bitmask, 0); BOOST_CHECK_EQUAL(pblocktemplate->block.nVersion & bitmask, bitmask); @@ -286,7 +286,7 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS deterministicMNManager->UpdatedBlockTip(::ChainActive().Tip()); BOOST_ASSERT(deterministicMNManager->GetListAtChainTip().HasMN(tx.GetHash())); auto masternode_payment = GetMasternodePayment(::ChainActive().Height(), GetBlockSubsidy(::ChainActive().Tip()->nBits, ::ChainActive().Height(), consensus_params), 2500); - const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, *m_node.mempool, Params()).CreateNewBlock(coinbasePubKey); + const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, *m_node.mempool, Params()).CreateNewBlock(::ChainstateActive(), coinbasePubKey); BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment); } @@ -297,7 +297,7 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS { LOCK(cs_main); auto masternode_payment = GetMasternodePayment(::ChainActive().Height(), GetBlockSubsidy(::ChainActive().Tip()->nBits, ::ChainActive().Height(), consensus_params), 2500); - const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, *m_node.mempool, Params()).CreateNewBlock(coinbasePubKey); + const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, *m_node.mempool, Params()).CreateNewBlock(::ChainstateActive(), coinbasePubKey); BOOST_CHECK_EQUAL(pblocktemplate->block.vtx[0]->GetValueOut(), 13748571607); BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment); BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, 6874285801); // 0.4999999998 @@ -312,7 +312,7 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS } LOCK(cs_main); auto masternode_payment = GetMasternodePayment(::ChainActive().Height(), GetBlockSubsidy(::ChainActive().Tip()->nBits, ::ChainActive().Height(), consensus_params), 2500); - const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, *m_node.mempool, Params()).CreateNewBlock(coinbasePubKey); + const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, *m_node.mempool, Params()).CreateNewBlock(::ChainstateActive(), coinbasePubKey); BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment); } } @@ -321,7 +321,7 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS // Reward split should reach ~60/40 after reallocation is done LOCK(cs_main); auto masternode_payment = GetMasternodePayment(::ChainActive().Height(), GetBlockSubsidy(::ChainActive().Tip()->nBits, ::ChainActive().Height(), consensus_params), 2500); - const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, *m_node.mempool, Params()).CreateNewBlock(coinbasePubKey); + const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, *m_node.mempool, Params()).CreateNewBlock(::ChainstateActive(), coinbasePubKey); BOOST_CHECK_EQUAL(pblocktemplate->block.vtx[0]->GetValueOut(), 10221599170); BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment); BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, 6132959502); // 0.6 @@ -335,7 +335,7 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS } LOCK(cs_main); auto masternode_payment = GetMasternodePayment(::ChainActive().Height(), GetBlockSubsidy(::ChainActive().Tip()->nBits, ::ChainActive().Height(), consensus_params), 2500); - const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, *m_node.mempool, Params()).CreateNewBlock(coinbasePubKey); + const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, *m_node.mempool, Params()).CreateNewBlock(::ChainstateActive(), coinbasePubKey); BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment); } @@ -343,7 +343,7 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS // Reward split should reach ~60/40 after reallocation is done LOCK(cs_main); auto masternode_payment = GetMasternodePayment(::ChainActive().Height(), GetBlockSubsidy(::ChainActive().Tip()->nBits, ::ChainActive().Height(), consensus_params), 2500); - const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, *m_node.mempool, Params()).CreateNewBlock(coinbasePubKey); + const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, *m_node.mempool, Params()).CreateNewBlock(::ChainstateActive(), coinbasePubKey); BOOST_CHECK_EQUAL(pblocktemplate->block.vtx[0]->GetValueOut(), 9491484944); BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment); BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, 5694890966); // 0.6 diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp index 3de6fbe2a2fd..63fb2e39a2ff 100644 --- a/src/test/blockfilter_index_tests.cpp +++ b/src/test/blockfilter_index_tests.cpp @@ -69,7 +69,7 @@ CBlock BuildChainTestingSetup::CreateBlock(const CBlockIndex* prev, const CScript& scriptPubKey) { const CChainParams& chainparams = Params(); - std::unique_ptr pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, *m_node.mempool, chainparams).CreateNewBlock(scriptPubKey); + std::unique_ptr pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, *m_node.mempool, chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey); CBlock& block = pblocktemplate->block; block.hashPrevBlock = prev->GetBlockHash(); block.nTime = prev->nTime + 1; diff --git a/src/test/dynamic_activation_thresholds_tests.cpp b/src/test/dynamic_activation_thresholds_tests.cpp index bf0ae6793111..fad2518b261f 100644 --- a/src/test/dynamic_activation_thresholds_tests.cpp +++ b/src/test/dynamic_activation_thresholds_tests.cpp @@ -79,7 +79,7 @@ struct TestChainDATSetup : public TestChainSetup BOOST_CHECK_EQUAL(VersionBitsState(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache), ThresholdState::STARTED); BOOST_CHECK_EQUAL(VersionBitsStatistics(::ChainActive().Tip(), consensus_params, deployment_id, versionbitscache).threshold, threshold(0)); // Next block should be signaling by default - const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, *m_node.mempool, Params()).CreateNewBlock(coinbasePubKey); + const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, *m_node.mempool, Params()).CreateNewBlock(::ChainstateActive(), coinbasePubKey); const uint32_t bitmask = ((uint32_t)1) << consensus_params.vDeployments[deployment_id].bit; BOOST_CHECK_EQUAL(::ChainActive().Tip()->nVersion & bitmask, 0); BOOST_CHECK_EQUAL(pblocktemplate->block.nVersion & bitmask, bitmask); diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index c14f3f3d19bd..91f3a1061371 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -135,7 +135,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 pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); + std::unique_ptr pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey); BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashParentTx); BOOST_CHECK(pblocktemplate->block.vtx[2]->GetHash() == hashHighFeeTx); BOOST_CHECK(pblocktemplate->block.vtx[3]->GetHash() == hashMediumFeeTx); @@ -155,7 +155,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(scriptPubKey); + pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey); // Verify that the free tx and the low fee tx didn't get selected for (size_t i=0; iblock.vtx.size(); ++i) { BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashFreeTx); @@ -169,7 +169,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(scriptPubKey); + pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey); BOOST_CHECK(pblocktemplate->block.vtx[4]->GetHash() == hashFreeTx); BOOST_CHECK(pblocktemplate->block.vtx[5]->GetHash() == hashLowFeeTx); @@ -190,7 +190,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(scriptPubKey); + pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey); // Verify that this tx isn't selected. for (size_t i=0; iblock.vtx.size(); ++i) { @@ -203,7 +203,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(scriptPubKey); + pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey); BOOST_CHECK(pblocktemplate->block.vtx[8]->GetHash() == hashLowFeeTx2); } @@ -224,7 +224,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) fCheckpointsEnabled = false; // Simple block creation, nothing special yet: - BOOST_CHECK(pemptyblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pemptyblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey)); // We can't make transactions until we have inputs // Therefore, load 100 blocks :) @@ -272,7 +272,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(scriptPubKey)); + BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey)); const CAmount BLOCKSUBSIDY = 500*COIN; const CAmount LOWFEE = CENT; @@ -297,7 +297,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[0].prevout.hash = hash; } - BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-blk-sigops")); + BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey), std::runtime_error, HasReason("bad-blk-sigops")); m_node.mempool->clear(); tx.vin[0].prevout.hash = txFirst[0]->GetHash(); @@ -311,7 +311,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).SigOps(20).FromTx(tx)); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey)); m_node.mempool->clear(); // block size > limit @@ -331,13 +331,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(scriptPubKey)); + BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), 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(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); + BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); m_node.mempool->clear(); // child with higher feerate than parent @@ -354,7 +354,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(scriptPubKey)); + BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey)); m_node.mempool->clear(); // coinbase in *m_node.mempool, template creation fails @@ -366,7 +366,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(scriptPubKey), std::runtime_error, HasReason("bad-cb-multiple")); + BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey), std::runtime_error, HasReason("bad-cb-multiple")); m_node.mempool->clear(); // invalid (pre-p2sh) txn in *m_node.mempool, template creation fails @@ -384,7 +384,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(scriptPubKey), std::runtime_error, HasReason("block-validation-failed")); + BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey), std::runtime_error, HasReason("block-validation-failed")); m_node.mempool->clear(); // double spend txn pair in *m_node.mempool, template creation fails @@ -397,7 +397,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(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); + BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); m_node.mempool->clear(); // subsidy changing @@ -413,7 +413,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) // next->BuildSkip(); // ::ChainActive().SetTip(next); // } - //BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey)); + //BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey)); // // Extend to a 210000-long block chain. // while (::ChainActive().Tip()->nHeight < 210000) { // CBlockIndex* prev = ::ChainActive().Tip(); @@ -425,7 +425,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) // next->BuildSkip(); // ::ChainActive().SetTip(next); // } - //BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey)); + //BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey)); // // Delete the dummy blocks again. // while (::ChainActive().Tip()->nHeight > nHeight) { // CBlockIndex* del = ::ChainActive().Tip(); @@ -511,7 +511,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(scriptPubKey)); + BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), 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, @@ -532,7 +532,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) SetMockTime(::ChainActive().Tip()->GetMedianTimePast() + 1); - BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey)); BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5U); } // unlock cs_main while calling InvalidateBlock diff --git a/src/test/util.cpp b/src/test/util.cpp index 4933f52426d1..7c265630248b 100644 --- a/src/test/util.cpp +++ b/src/test/util.cpp @@ -81,7 +81,7 @@ std::shared_ptr PrepareBlock(const NodeContext& node, const CScript& coi assert(node.mempool); auto block = std::make_shared( BlockAssembler{*sporkManager, *governance, *node.llmq_ctx->quorum_block_processor, *node.llmq_ctx->clhandler, *node.llmq_ctx->isman, *node.evodb, *node.mempool, Params()} - .CreateNewBlock(coinbase_scriptPubKey) + .CreateNewBlock(::ChainstateActive(), coinbase_scriptPubKey) ->block); block->nTime = ::ChainActive().Tip()->GetMedianTimePast() + 1; diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 9ff2a2badf75..36f7156f1250 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -312,7 +312,7 @@ CBlock TestChainSetup::CreateBlock(const std::vector& txns, *sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, empty_pool, chainparams - ).CreateNewBlock(scriptPubKey)->block; + ).CreateNewBlock(::ChainstateActive(), scriptPubKey)->block; std::vector llmqCommitments; for (const auto& tx : block.vtx) { diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp index b6cd6db433a5..becce21a2bba 100644 --- a/src/test/validation_block_tests.cpp +++ b/src/test/validation_block_tests.cpp @@ -75,7 +75,7 @@ std::shared_ptr MinerTestingSetup::Block(const uint256& prev_hash) CScript pubKey; pubKey << i++ << OP_TRUE; - auto ptemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, *m_node.mempool, Params()).CreateNewBlock(pubKey); + auto ptemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx->quorum_block_processor, *m_node.llmq_ctx->clhandler, *m_node.llmq_ctx->isman, *m_node.evodb, *m_node.mempool, Params()).CreateNewBlock(::ChainstateActive(), pubKey); auto pblock = std::make_shared(ptemplate->block); pblock->hashPrevBlock = prev_hash; pblock->nTime = ++time; diff --git a/src/validation.h b/src/validation.h index d3e94f155377..ccba0b5bec86 100644 --- a/src/validation.h +++ b/src/validation.h @@ -176,8 +176,6 @@ extern uint64_t nPruneTarget; FILE* OpenBlockFile(const FlatFilePos &pos, bool fReadOnly = false); /** Translation to a filesystem path */ fs::path GetBlockPosFilename(const FlatFilePos &pos); -/** Ensures we have a genesis block in the block tree, possibly writing one to disk. */ -bool LoadGenesisBlock(const CChainParams& chainparams); /** Unload database information */ void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman); /** Run instances of script checking worker threads */ @@ -732,6 +730,7 @@ class CChainState /** Replay blocks that aren't fully applied to the database. */ bool ReplayBlocks(const CChainParams& params); + /** Ensures we have a genesis block in the block tree, possibly writing one to disk. */ bool LoadGenesisBlock(const CChainParams& chainparams); bool AddGenesisBlock(const CChainParams& chainparams, const CBlock& block, CValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);