Skip to content

Commit 0d3b2f6

Browse files
committed
rpc: Add hash_type MUHASH to gettxoutsetinfo
Also small style fix in rpc/util.cpp
1 parent 2474645 commit 0d3b2f6

File tree

6 files changed

+59
-23
lines changed

6 files changed

+59
-23
lines changed

src/node/coinstats.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <node/coinstats.h>
77

88
#include <coins.h>
9+
#include <crypto/muhash.h>
910
#include <hash.h>
1011
#include <serialize.h>
1112
#include <uint256.h>
@@ -42,8 +43,20 @@ static void ApplyHash(CCoinsStats& stats, CHashWriter& ss, const uint256& hash,
4243

4344
static void ApplyHash(CCoinsStats& stats, std::nullptr_t, const uint256& hash, const std::map<uint32_t, Coin>& outputs, std::map<uint32_t, Coin>::const_iterator it) {}
4445

46+
static void ApplyHash(CCoinsStats& stats, MuHash3072& muhash, const uint256& hash, const std::map<uint32_t, Coin>& outputs, std::map<uint32_t, Coin>::const_iterator it)
47+
{
48+
COutPoint outpoint = COutPoint(hash, it->first);
49+
Coin coin = it->second;
50+
51+
CDataStream ss(SER_DISK, PROTOCOL_VERSION);
52+
ss << outpoint;
53+
ss << static_cast<uint32_t>(coin.nHeight * 2 + coin.fCoinBase);
54+
ss << coin.out;
55+
muhash.Insert(MakeUCharSpan(ss));
56+
}
57+
4558
template <typename T>
46-
static void ApplyStats(CCoinsStats &stats, T& hash_obj, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
59+
static void ApplyStats(CCoinsStats& stats, T& hash_obj, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
4760
{
4861
assert(!outputs.empty());
4962
stats.nTransactions++;
@@ -108,6 +121,10 @@ bool GetUTXOStats(CCoinsView* view, CCoinsStats& stats, CoinStatsHashType hash_t
108121
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
109122
return GetUTXOStats(view, stats, ss, interruption_point);
110123
}
124+
case(CoinStatsHashType::MUHASH): {
125+
MuHash3072 muhash;
126+
return GetUTXOStats(view, stats, muhash, interruption_point);
127+
}
111128
case(CoinStatsHashType::NONE): {
112129
return GetUTXOStats(view, stats, nullptr, interruption_point);
113130
}
@@ -120,10 +137,18 @@ static void PrepareHash(CHashWriter& ss, const CCoinsStats& stats)
120137
{
121138
ss << stats.hashBlock;
122139
}
140+
// MuHash does not need the prepare step
141+
static void PrepareHash(MuHash3072& muhash, CCoinsStats& stats) {}
123142
static void PrepareHash(std::nullptr_t, CCoinsStats& stats) {}
124143

125144
static void FinalizeHash(CHashWriter& ss, CCoinsStats& stats)
126145
{
127146
stats.hashSerialized = ss.GetHash();
128147
}
148+
static void FinalizeHash(MuHash3072& muhash, CCoinsStats& stats)
149+
{
150+
uint256 out;
151+
muhash.Finalize(out);
152+
stats.hashSerialized = out;
153+
}
129154
static void FinalizeHash(std::nullptr_t, CCoinsStats& stats) {}

src/node/coinstats.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class CCoinsView;
1616

1717
enum class CoinStatsHashType {
1818
HASH_SERIALIZED,
19+
MUHASH,
1920
NONE,
2021
};
2122

src/rpc/blockchain.cpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,13 +1047,26 @@ static RPCHelpMan pruneblockchain()
10471047
};
10481048
}
10491049

1050+
CoinStatsHashType ParseHashType(const std::string& hash_type_input)
1051+
{
1052+
if (hash_type_input == "hash_serialized_2") {
1053+
return CoinStatsHashType::HASH_SERIALIZED;
1054+
} else if (hash_type_input == "muhash") {
1055+
return CoinStatsHashType::MUHASH;
1056+
} else if (hash_type_input == "none") {
1057+
return CoinStatsHashType::NONE;
1058+
} else {
1059+
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s is not a valid hash_type", hash_type_input));
1060+
}
1061+
}
1062+
10501063
static RPCHelpMan gettxoutsetinfo()
10511064
{
10521065
return RPCHelpMan{"gettxoutsetinfo",
10531066
"\nReturns statistics about the unspent transaction output set.\n"
10541067
"Note this call may take some time.\n",
10551068
{
1056-
{"hash_type", RPCArg::Type::STR, /* default */ "hash_serialized_2", "Which UTXO set hash should be calculated. Options: 'hash_serialized_2' (the legacy algorithm), 'none'."},
1069+
{"hash_type", RPCArg::Type::STR, /* default */ "hash_serialized_2", "Which UTXO set hash should be calculated. Options: 'hash_serialized_2' (the legacy algorithm), 'muhash', 'none'."},
10571070
},
10581071
RPCResult{
10591072
RPCResult::Type::OBJ, "", "",
@@ -1063,7 +1076,8 @@ static RPCHelpMan gettxoutsetinfo()
10631076
{RPCResult::Type::NUM, "transactions", "The number of transactions with unspent outputs"},
10641077
{RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs"},
10651078
{RPCResult::Type::NUM, "bogosize", "A meaningless metric for UTXO set size"},
1066-
{RPCResult::Type::STR_HEX, "hash_serialized_2", "The serialized hash (only present if 'hash_serialized_2' hash_type is chosen)"},
1079+
{RPCResult::Type::STR_HEX, "hash_serialized_2", /* optional */ true, "The serialized hash (only present if 'hash_serialized_2' hash_type is chosen)"},
1080+
{RPCResult::Type::STR_HEX, "muhash", /* optional */ true, "The serialized hash (only present if 'muhash' hash_type is chosen)"},
10671081
{RPCResult::Type::NUM, "disk_size", "The estimated size of the chainstate on disk"},
10681082
{RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount"},
10691083
}},
@@ -1078,7 +1092,7 @@ static RPCHelpMan gettxoutsetinfo()
10781092
CCoinsStats stats;
10791093
::ChainstateActive().ForceFlushStateToDisk();
10801094

1081-
const CoinStatsHashType hash_type = ParseHashType(request.params[0], CoinStatsHashType::HASH_SERIALIZED);
1095+
const CoinStatsHashType hash_type{request.params[0].isNull() ? CoinStatsHashType::HASH_SERIALIZED : ParseHashType(request.params[0].get_str())};
10821096

10831097
CCoinsView* coins_view = WITH_LOCK(cs_main, return &ChainstateActive().CoinsDB());
10841098
NodeContext& node = EnsureNodeContext(request.context);
@@ -1091,6 +1105,9 @@ static RPCHelpMan gettxoutsetinfo()
10911105
if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
10921106
ret.pushKV("hash_serialized_2", stats.hashSerialized.GetHex());
10931107
}
1108+
if (hash_type == CoinStatsHashType::MUHASH) {
1109+
ret.pushKV("muhash", stats.hashSerialized.GetHex());
1110+
}
10941111
ret.pushKV("disk_size", stats.nDiskSize);
10951112
ret.pushKV("total_amount", ValueFromAmount(stats.nTotalAmount));
10961113
} else {

src/rpc/util.cpp

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -113,23 +113,6 @@ std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey)
113113
return ParseHexV(find_value(o, strKey), strKey);
114114
}
115115

116-
CoinStatsHashType ParseHashType(const UniValue& param, const CoinStatsHashType default_type)
117-
{
118-
if (param.isNull()) {
119-
return default_type;
120-
} else {
121-
std::string hash_type_input = param.get_str();
122-
123-
if (hash_type_input == "hash_serialized_2") {
124-
return CoinStatsHashType::HASH_SERIALIZED;
125-
} else if (hash_type_input == "none") {
126-
return CoinStatsHashType::NONE;
127-
} else {
128-
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%d is not a valid hash_type", hash_type_input));
129-
}
130-
}
131-
}
132-
133116
std::string HelpExampleCli(const std::string& methodname, const std::string& args)
134117
{
135118
return "> bitcoin-cli " + methodname + " " + args + "\n";

src/rpc/util.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,6 @@ extern uint256 ParseHashO(const UniValue& o, std::string strKey);
7777
extern std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName);
7878
extern std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey);
7979

80-
CoinStatsHashType ParseHashType(const UniValue& param, const CoinStatsHashType default_type);
81-
8280
extern CAmount AmountFromValue(const UniValue& value);
8381
extern std::string HelpExampleCli(const std::string& methodname, const std::string& args);
8482
extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args);

test/functional/rpc_blockchain.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,18 @@ def _test_gettxoutsetinfo(self):
268268
res5 = node.gettxoutsetinfo(hash_type='none')
269269
assert 'hash_serialized_2' not in res5
270270

271+
# hash_type muhash should return a different UTXO set hash.
272+
res6 = node.gettxoutsetinfo(hash_type='muhash')
273+
assert 'muhash' in res6
274+
assert(res['hash_serialized_2'] != res6['muhash'])
275+
276+
# muhash should not be included in gettxoutset unless requested.
277+
for r in [res, res2, res3, res4, res5]:
278+
assert 'muhash' not in r
279+
280+
# Unknown hash_type raises an error
281+
assert_raises_rpc_error(-8, "foohash is not a valid hash_type", node.gettxoutsetinfo, "foohash")
282+
271283
def _test_getblockheader(self):
272284
node = self.nodes[0]
273285

0 commit comments

Comments
 (0)