Skip to content

Commit c1de83b

Browse files
Merge #6083: refactor: move Get*Index to rpc/index_util.cpp, const-ify functions and arguments, add lock annotations and some minor housekeeping
8fb8630 refactor: inline sorting and make available through argument (Kittywhiskers Van Gogh) 3e0fcf4 refactor: move accessing CBlockTreeDB global out of Get*Index (Kittywhiskers Van Gogh) ee9d112 refactor: move pair value swapping out of CTxMemPool::getAddressIndex() (Kittywhiskers Van Gogh) 808842b refactor: define all key/value pairings as *Entry and use them instead (Kittywhiskers Van Gogh) 488f047 rpc: extend error-on-failure to GetSpentIndex (Kittywhiskers Van Gogh) 9a6503d refactor: make CBlockTreeDB::Read*Index arguments const (Kittywhiskers Van Gogh) 625982e refactor: make CTxMemPool::get*Index functions and arguments const (Kittywhiskers Van Gogh) 5ad49ad refactor: move Get{Address*, Timestamp, Spent}Index out of validation (Kittywhiskers Van Gogh) Pull request description: ## Additional Information This pull request is motivated by [bitcoin#22371](bitcoin#22371), which gets rid of the `pblocktree` global. The sole usage of `pblocktree` introduced by Dash is for managing our {address, spent, timestamp} indexes with most of invocations within `BlockManager` or `CChainState`, granting them internal access to `pblocktree` (now `m_block_tree_db`). The sole exception being `Get*Index`, that relies on accessing the global and has no direct internal access. This pull request aims to refactor code associated with `Get*Index` with the eventual aim of moving gaining access to the global out of the function. `Get*Index` is called exclusively called through RPC, which makes giving it access to `ChainstateManager` quite easy, which makes switching from the global to accessing it through `ChainstateManager` when backporting [bitcoin#22371](bitcoin#22371) a drop-in replacement. Alongside that, the surrounding code has been given some TLC: * Moving code out of `validation.cpp` and into `rpc/index_util.cpp`. The code is exclusively used in RPC logic and doesn't aid in validation. * Add lock annotations for accessing `pblocktree` (while already protected by `::cs_main`, said protection is currently not enforced but will be once moved into `BlockManager` in the backport) * `const`-ing input arguments and using pass-by-value for input arguments that can be written inline (i.e. types like `CSpentIndexKey` are still pass-by-ref). * While `const`ing `CTxMemPool` functions were possible (courtesy of the presence of `const_iterator`s), the same is currently not possible with `CBlockTreeDB` functions as the iterator is non-`const`. * Extend error messages to `GetSpentIndex` to bring it line with other `Get*Index`es. * Define key-value pairings as a `*Entry` typedef and replacing all explicit type constructions with it. * Make `CTxMemPool::getAddressIndex` indifferent to how `CMempoolAddressDeltaKey` is constructed. * Current behaviour is to accept a `std::pair<uint160, AddressType>` and construct the `CMempoolAddressDeltaKey` internally, this was presumably done to account for the return type of `getAddressesFromParams` in the sole call for the `CTxMemPool::getAddressIndex`. * This has been changed, moving the construction into the RPC call. * Moving {height, timestamp} sorting out of RPC and into the applicable `Get*Index` functions. ## Breaking Changes None expected. ## Checklist: - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas (note: N/A) - [x] I have added or updated relevant unit/integration/functional/e2e tests (note: N/A) - [x] I have made corresponding changes to the documentation (note: N/A) - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_ ACKs for top commit: PastaPastaPasta: utACK 8fb8630 UdjinM6: utACK 8fb8630 Tree-SHA512: 425a383e8284bbd74a5e9bcda4a9d7988221197055f43faa591e6f0d579625cee28f6a6046dab951e7afa0c3e33af1778fb4bb5f0a2e1e5792fe0d9396897a14
2 parents 3e342d7 + 8fb8630 commit c1de83b

14 files changed

+277
-166
lines changed

src/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ BITCOIN_CORE_H = \
286286
reverse_iterator.h \
287287
rpc/blockchain.h \
288288
rpc/client.h \
289+
rpc/index_util.h \
289290
rpc/mining.h \
290291
rpc/protocol.h \
291292
rpc/rawtransaction_util.h \
@@ -502,6 +503,7 @@ libbitcoin_server_a_SOURCES = \
502503
rpc/blockchain.cpp \
503504
rpc/coinjoin.cpp \
504505
rpc/evo.cpp \
506+
rpc/index_util.cpp \
505507
rpc/masternode.cpp \
506508
rpc/governance.cpp \
507509
rpc/mining.cpp \

src/addressindex.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
#include <tuple>
1818

1919
class CScript;
20+
struct CAddressIndexKey;
21+
struct CMempoolAddressDelta;
22+
struct CMempoolAddressDeltaKey;
2023

2124
enum class AddressType : uint8_t {
2225
P2PK_OR_P2PKH = 1,
@@ -26,6 +29,9 @@ enum class AddressType : uint8_t {
2629
};
2730
template<> struct is_serializable_enum<AddressType> : std::true_type {};
2831

32+
using CAddressIndexEntry = std::pair<CAddressIndexKey, CAmount>;
33+
using CMempoolAddressDeltaEntry = std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta>;
34+
2935
struct CMempoolAddressDelta
3036
{
3137
public:

src/rpc/blockchain.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <policy/fees.h>
3131
#include <policy/policy.h>
3232
#include <primitives/transaction.h>
33+
#include <rpc/index_util.h>
3334
#include <rpc/server.h>
3435
#include <rpc/server_util.h>
3536
#include <rpc/util.h>
@@ -834,7 +835,7 @@ static RPCHelpMan getblockhashes()
834835
unsigned int low = request.params[1].get_int();
835836
std::vector<uint256> blockHashes;
836837

837-
if (!GetTimestampIndex(high, low, blockHashes)) {
838+
if (LOCK(::cs_main); !GetTimestampIndex(*pblocktree, high, low, blockHashes)) {
838839
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for block hashes");
839840
}
840841

src/rpc/index_util.cpp

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// Copyright (c) 2016 BitPay, Inc.
2+
// Copyright (c) 2024 The Dash Core developers
3+
// Distributed under the MIT software license, see the accompanying
4+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
6+
#include <rpc/index_util.h>
7+
8+
#include <txmempool.h>
9+
#include <uint256.h>
10+
#include <validation.h>
11+
12+
bool GetAddressIndex(CBlockTreeDB& block_tree_db, const uint160& addressHash, const AddressType type,
13+
std::vector<CAddressIndexEntry>& addressIndex,
14+
const int32_t start, const int32_t end)
15+
{
16+
AssertLockHeld(::cs_main);
17+
18+
if (!fAddressIndex)
19+
return error("Address index not enabled");
20+
21+
if (!block_tree_db.ReadAddressIndex(addressHash, type, addressIndex, start, end))
22+
return error("Unable to get txids for address");
23+
24+
return true;
25+
}
26+
27+
bool GetAddressUnspentIndex(CBlockTreeDB& block_tree_db, const uint160& addressHash, const AddressType type,
28+
std::vector<CAddressUnspentIndexEntry>& unspentOutputs, const bool height_sort)
29+
{
30+
AssertLockHeld(::cs_main);
31+
32+
if (!fAddressIndex)
33+
return error("Address index not enabled");
34+
35+
if (!block_tree_db.ReadAddressUnspentIndex(addressHash, type, unspentOutputs))
36+
return error("Unable to get txids for address");
37+
38+
if (height_sort) {
39+
std::sort(unspentOutputs.begin(), unspentOutputs.end(),
40+
[](const CAddressUnspentIndexEntry &a, const CAddressUnspentIndexEntry &b) {
41+
return a.second.m_block_height < b.second.m_block_height;
42+
});
43+
}
44+
45+
return true;
46+
}
47+
48+
bool GetMempoolAddressDeltaIndex(const CTxMemPool& mempool,
49+
const std::vector<CMempoolAddressDeltaKey>& addressDeltaIndex,
50+
std::vector<CMempoolAddressDeltaEntry>& addressDeltaEntries,
51+
const bool timestamp_sort)
52+
{
53+
if (!fAddressIndex)
54+
return error("Address index not enabled");
55+
56+
if (!mempool.getAddressIndex(addressDeltaIndex, addressDeltaEntries))
57+
return error("Unable to get address delta information");
58+
59+
if (timestamp_sort) {
60+
std::sort(addressDeltaEntries.begin(), addressDeltaEntries.end(),
61+
[](const CMempoolAddressDeltaEntry &a, const CMempoolAddressDeltaEntry &b) {
62+
return a.second.m_time < b.second.m_time;
63+
});
64+
}
65+
66+
return true;
67+
}
68+
69+
bool GetSpentIndex(CBlockTreeDB& block_tree_db, const CTxMemPool& mempool, const CSpentIndexKey& key,
70+
CSpentIndexValue& value)
71+
{
72+
AssertLockHeld(::cs_main);
73+
74+
if (!fSpentIndex)
75+
return error("Spent index not enabled");
76+
77+
if (mempool.getSpentIndex(key, value))
78+
return true;
79+
80+
if (!block_tree_db.ReadSpentIndex(key, value))
81+
return error("Unable to get spend information");
82+
83+
return true;
84+
}
85+
86+
bool GetTimestampIndex(CBlockTreeDB& block_tree_db, const uint32_t high, const uint32_t low,
87+
std::vector<uint256>& hashes)
88+
{
89+
AssertLockHeld(::cs_main);
90+
91+
if (!fTimestampIndex)
92+
return error("Timestamp index not enabled");
93+
94+
if (!block_tree_db.ReadTimestampIndex(high, low, hashes))
95+
return error("Unable to get hashes for timestamps");
96+
97+
return true;
98+
}

src/rpc/index_util.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright (c) 2016 BitPay, Inc.
2+
// Copyright (c) 2024 The Dash Core developers
3+
// Distributed under the MIT software license, see the accompanying
4+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
6+
#ifndef BITCOIN_RPC_INDEX_UTIL_H
7+
#define BITCOIN_RPC_INDEX_UTIL_H
8+
9+
#include <cstdint>
10+
#include <vector>
11+
12+
#include <amount.h>
13+
#include <addressindex.h>
14+
#include <spentindex.h>
15+
#include <sync.h>
16+
#include <threadsafety.h>
17+
18+
class CBlockTreeDB;
19+
class CTxMemPool;
20+
class uint160;
21+
class uint256;
22+
23+
enum class AddressType : uint8_t;
24+
25+
extern RecursiveMutex cs_main;
26+
27+
bool GetAddressIndex(CBlockTreeDB& block_tree_db, const uint160& addressHash, const AddressType type,
28+
std::vector<CAddressIndexEntry>& addressIndex,
29+
const int32_t start = 0, const int32_t end = 0)
30+
EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
31+
bool GetAddressUnspentIndex(CBlockTreeDB& block_tree_db, const uint160& addressHash, const AddressType type,
32+
std::vector<CAddressUnspentIndexEntry>& unspentOutputs, const bool height_sort = false)
33+
EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
34+
bool GetMempoolAddressDeltaIndex(const CTxMemPool& mempool,
35+
const std::vector<CMempoolAddressDeltaKey>& addressDeltaIndex,
36+
std::vector<CMempoolAddressDeltaEntry>& addressDeltaEntries,
37+
const bool timestamp_sort = false);
38+
bool GetSpentIndex(CBlockTreeDB& block_tree_db, const CTxMemPool& mempool, const CSpentIndexKey& key,
39+
CSpentIndexValue& value)
40+
EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
41+
bool GetTimestampIndex(CBlockTreeDB& block_tree_db, const uint32_t high, const uint32_t low,
42+
std::vector<uint256>& hashes)
43+
EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
44+
45+
#endif // BITCOIN_RPC_CLIENT_H

src/rpc/misc.cpp

Lines changed: 53 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <net.h>
2020
#include <node/context.h>
2121
#include <rpc/blockchain.h>
22+
#include <rpc/index_util.h>
2223
#include <rpc/server.h>
2324
#include <rpc/server_util.h>
2425
#include <rpc/util.h>
@@ -700,16 +701,6 @@ static bool getAddressesFromParams(const UniValue& params, std::vector<std::pair
700701
return true;
701702
}
702703

703-
static bool heightSort(std::pair<CAddressUnspentKey, CAddressUnspentValue> a,
704-
std::pair<CAddressUnspentKey, CAddressUnspentValue> b) {
705-
return a.second.m_block_height < b.second.m_block_height;
706-
}
707-
708-
static bool timestampSort(std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> a,
709-
std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> b) {
710-
return a.second.m_time < b.second.m_time;
711-
}
712-
713704
static RPCHelpMan getaddressmempool()
714705
{
715706
return RPCHelpMan{"getaddressmempool",
@@ -741,22 +732,22 @@ static RPCHelpMan getaddressmempool()
741732
},
742733
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
743734
{
735+
CTxMemPool& mempool = EnsureAnyMemPool(request.context);
744736

745-
std::vector<std::pair<uint160, AddressType> > addresses;
746-
737+
std::vector<std::pair<uint160, AddressType>> addresses;
747738
if (!getAddressesFromParams(request.params, addresses)) {
748739
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
749740
}
750741

751-
std::vector<std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> > indexes;
752-
753-
CTxMemPool& mempool = EnsureAnyMemPool(request.context);
754-
if (!mempool.getAddressIndex(addresses, indexes)) {
742+
std::vector<CMempoolAddressDeltaKey> input_addresses;
743+
std::vector<CMempoolAddressDeltaEntry> indexes;
744+
for (const auto& [hash, type] : addresses) {
745+
input_addresses.push_back({type, hash});
746+
}
747+
if (!GetMempoolAddressDeltaIndex(mempool, input_addresses, indexes, /* timestamp_sort = */ true)) {
755748
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
756749
}
757750

758-
std::sort(indexes.begin(), indexes.end(), timestampSort);
759-
760751
UniValue result(UniValue::VARR);
761752

762753
for (const auto& [mempoolAddressKey, mempoolAddressDelta] : indexes) {
@@ -820,16 +811,18 @@ static RPCHelpMan getaddressutxos()
820811
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
821812
}
822813

823-
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
814+
std::vector<CAddressUnspentIndexEntry> unspentOutputs;
824815

825-
for (const auto& address : addresses) {
826-
if (!GetAddressUnspent(address.first, address.second, unspentOutputs)) {
827-
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
816+
{
817+
LOCK(::cs_main);
818+
for (const auto& address : addresses) {
819+
if (!GetAddressUnspentIndex(*pblocktree, address.first, address.second, unspentOutputs,
820+
/* height_sort = */ true)) {
821+
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
822+
}
828823
}
829824
}
830825

831-
std::sort(unspentOutputs.begin(), unspentOutputs.end(), heightSort);
832-
833826
UniValue result(UniValue::VARR);
834827

835828
for (const auto& [unspentKey, unspentValue] : unspentOutputs) {
@@ -905,16 +898,19 @@ static RPCHelpMan getaddressdeltas()
905898
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
906899
}
907900

908-
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
901+
std::vector<CAddressIndexEntry> addressIndex;
909902

910-
for (const auto& address : addresses) {
911-
if (start > 0 && end > 0) {
912-
if (!GetAddressIndex(address.first, address.second, addressIndex, start, end)) {
913-
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
914-
}
915-
} else {
916-
if (!GetAddressIndex(address.first, address.second, addressIndex)) {
917-
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
903+
{
904+
LOCK(::cs_main);
905+
for (const auto& address : addresses) {
906+
if (start > 0 && end > 0) {
907+
if (!GetAddressIndex(*pblocktree, address.first, address.second, addressIndex, start, end)) {
908+
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
909+
}
910+
} else {
911+
if (!GetAddressIndex(*pblocktree, address.first, address.second, addressIndex)) {
912+
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
913+
}
918914
}
919915
}
920916
}
@@ -974,16 +970,21 @@ static RPCHelpMan getaddressbalance()
974970
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
975971
}
976972

977-
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
973+
std::vector<CAddressIndexEntry> addressIndex;
978974

979-
for (const auto& address : addresses) {
980-
if (!GetAddressIndex(address.first, address.second, addressIndex)) {
981-
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
975+
ChainstateManager& chainman = EnsureAnyChainman(request.context);
976+
977+
int nHeight;
978+
{
979+
LOCK(::cs_main);
980+
for (const auto& address : addresses) {
981+
if (!GetAddressIndex(*pblocktree, address.first, address.second, addressIndex)) {
982+
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
983+
}
982984
}
985+
nHeight = chainman.ActiveChain().Height();
983986
}
984987

985-
ChainstateManager& chainman = EnsureAnyChainman(request.context);
986-
int nHeight = WITH_LOCK(cs_main, return chainman.ActiveChain().Height());
987988

988989
CAmount balance = 0;
989990
CAmount balance_spendable = 0;
@@ -1053,16 +1054,19 @@ static RPCHelpMan getaddresstxids()
10531054
}
10541055
}
10551056

1056-
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
1057+
std::vector<CAddressIndexEntry> addressIndex;
10571058

1058-
for (const auto& address : addresses) {
1059-
if (start > 0 && end > 0) {
1060-
if (!GetAddressIndex(address.first, address.second, addressIndex, start, end)) {
1061-
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
1062-
}
1063-
} else {
1064-
if (!GetAddressIndex(address.first, address.second, addressIndex)) {
1065-
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
1059+
{
1060+
LOCK(::cs_main);
1061+
for (const auto& address : addresses) {
1062+
if (start > 0 && end > 0) {
1063+
if (!GetAddressIndex(*pblocktree, address.first, address.second, addressIndex, start, end)) {
1064+
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
1065+
}
1066+
} else {
1067+
if (!GetAddressIndex(*pblocktree, address.first, address.second, addressIndex)) {
1068+
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
1069+
}
10661070
}
10671071
}
10681072
}
@@ -1134,7 +1138,7 @@ static RPCHelpMan getspentinfo()
11341138
CSpentIndexValue value;
11351139

11361140
CTxMemPool& mempool = EnsureAnyMemPool(request.context);
1137-
if (!GetSpentIndex(mempool, key, value)) {
1141+
if (LOCK(::cs_main); !GetSpentIndex(*pblocktree, mempool, key, value)) {
11381142
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to get spent info");
11391143
}
11401144

0 commit comments

Comments
 (0)