mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-04-20 11:49:07 +02:00
Merge #19328: Add gettxoutsetinfo hash_type option
40506bf93ftest: Test gettxouttsetinfo hash_type option (Fabian Jahr)f17a4d1c4drpc: Add hash_type NONE to gettxoutsetinfo (Fabian Jahr)a712cf6f68rpc: gettxoutsetinfo can specify hash_type (only legacy option for now) (Fabian Jahr)605884ef21refactor: Extract GetBogoSize function (Fabian Jahr) Pull request description: This is another intermediate part of the Coinstats Index (tracked in #18000). Sjors suggested [here](https://github.com/bitcoin/bitcoin/pull/18000#issuecomment-641423019) that the part of the changes in #19145 that don't rely on the new `hash_type` muhash, i.e. that are for `hash_type=none`, could be merged separately from everything involving muhash. So these changes are extracted from #19145 here and can be merged without any other requirements. Building the index with no UTXO set hash is still valuable because `gettxoutsetinfo` can still be used to audit the `total_amount` for example. By itself this PR is not a huge improvement, `hash_type=none` is speeding up `gettxoutsetinfo` by about 10%, but it enables the implementation of an index on top of it in a follow-up and that means large parts of the index code of Coinstats Index can be merged while reviews for the hashing algorithm might take longer. ACKs for top commit: MarcoFalke: ACK40506bf93f🖨 Sjors: tACK40506bf93fTree-SHA512: 3964c2b8eed427511b1aa9b2ef285dff27dc4d1537d72c3911e435b6e6b40912232da4acb3a09bd19a0372ddffa44103388d8a650169d95a4a727b970d210add
This commit is contained in:
@@ -8,13 +8,23 @@
|
||||
#include <coins.h>
|
||||
#include <hash.h>
|
||||
#include <serialize.h>
|
||||
#include <validation.h>
|
||||
#include <uint256.h>
|
||||
#include <util/system.h>
|
||||
#include <validation.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
static void ApplyStats(CCoinsStats &stats, CHashWriter& ss, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
|
||||
static uint64_t GetBogoSize(const CScript& scriptPubKey)
|
||||
{
|
||||
return 32 /* txid */ +
|
||||
4 /* vout index */ +
|
||||
4 /* height + coinbase */ +
|
||||
8 /* amount */ +
|
||||
2 /* scriptPubKey len */ +
|
||||
scriptPubKey.size() /* scriptPubKey */;
|
||||
}
|
||||
|
||||
static void ApplyStats(CCoinsStats& stats, CHashWriter& ss, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
|
||||
{
|
||||
assert(!outputs.empty());
|
||||
ss << hash;
|
||||
@@ -26,26 +36,38 @@ static void ApplyStats(CCoinsStats &stats, CHashWriter& ss, const uint256& hash,
|
||||
ss << VARINT_MODE(output.second.out.nValue, VarIntMode::NONNEGATIVE_SIGNED);
|
||||
stats.nTransactionOutputs++;
|
||||
stats.nTotalAmount += output.second.out.nValue;
|
||||
stats.nBogoSize += 32 /* txid */ + 4 /* vout index */ + 4 /* height + coinbase */ + 8 /* amount */ +
|
||||
2 /* scriptPubKey len */ + output.second.out.scriptPubKey.size() /* scriptPubKey */;
|
||||
stats.nBogoSize += GetBogoSize(output.second.out.scriptPubKey);
|
||||
}
|
||||
ss << VARINT(0u);
|
||||
}
|
||||
|
||||
static void ApplyStats(CCoinsStats& stats, std::nullptr_t, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
|
||||
{
|
||||
assert(!outputs.empty());
|
||||
stats.nTransactions++;
|
||||
for (const auto& output : outputs) {
|
||||
stats.nTransactionOutputs++;
|
||||
stats.nTotalAmount += output.second.out.nValue;
|
||||
stats.nBogoSize += GetBogoSize(output.second.out.scriptPubKey);
|
||||
}
|
||||
}
|
||||
|
||||
//! Calculate statistics about the unspent transaction output set
|
||||
bool GetUTXOStats(CCoinsView* view, CCoinsStats& stats, const std::function<void()>& interruption_point)
|
||||
template <typename T>
|
||||
static bool GetUTXOStats(CCoinsView* view, CCoinsStats& stats, T hash_obj, const std::function<void()>& interruption_point)
|
||||
{
|
||||
stats = CCoinsStats();
|
||||
std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor());
|
||||
assert(pcursor);
|
||||
|
||||
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
|
||||
stats.hashBlock = pcursor->GetBestBlock();
|
||||
{
|
||||
LOCK(cs_main);
|
||||
stats.nHeight = LookupBlockIndex(stats.hashBlock)->nHeight;
|
||||
}
|
||||
ss << stats.hashBlock;
|
||||
|
||||
PrepareHash(hash_obj, stats);
|
||||
|
||||
uint256 prevkey;
|
||||
std::map<uint32_t, Coin> outputs;
|
||||
while (pcursor->Valid()) {
|
||||
@@ -54,7 +76,7 @@ bool GetUTXOStats(CCoinsView* view, CCoinsStats& stats, const std::function<void
|
||||
Coin coin;
|
||||
if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
|
||||
if (!outputs.empty() && key.hash != prevkey) {
|
||||
ApplyStats(stats, ss, prevkey, outputs);
|
||||
ApplyStats(stats, hash_obj, prevkey, outputs);
|
||||
outputs.clear();
|
||||
}
|
||||
prevkey = key.hash;
|
||||
@@ -66,9 +88,38 @@ bool GetUTXOStats(CCoinsView* view, CCoinsStats& stats, const std::function<void
|
||||
pcursor->Next();
|
||||
}
|
||||
if (!outputs.empty()) {
|
||||
ApplyStats(stats, ss, prevkey, outputs);
|
||||
ApplyStats(stats, hash_obj, prevkey, outputs);
|
||||
}
|
||||
stats.hashSerialized = ss.GetHash();
|
||||
|
||||
FinalizeHash(hash_obj, stats);
|
||||
|
||||
stats.nDiskSize = view->EstimateSize();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetUTXOStats(CCoinsView* view, CCoinsStats& stats, CoinStatsHashType hash_type, const std::function<void()>& interruption_point)
|
||||
{
|
||||
switch (hash_type) {
|
||||
case(CoinStatsHashType::HASH_SERIALIZED): {
|
||||
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
|
||||
return GetUTXOStats(view, stats, ss, interruption_point);
|
||||
}
|
||||
case(CoinStatsHashType::NONE): {
|
||||
return GetUTXOStats(view, stats, nullptr, interruption_point);
|
||||
}
|
||||
} // no default case, so the compiler can warn about missing cases
|
||||
assert(false);
|
||||
}
|
||||
|
||||
// The legacy hash serializes the hashBlock
|
||||
static void PrepareHash(CHashWriter& ss, CCoinsStats& stats)
|
||||
{
|
||||
ss << stats.hashBlock;
|
||||
}
|
||||
static void PrepareHash(std::nullptr_t, CCoinsStats& stats) {}
|
||||
|
||||
static void FinalizeHash(CHashWriter& ss, CCoinsStats& stats)
|
||||
{
|
||||
stats.hashSerialized = ss.GetHash();
|
||||
}
|
||||
static void FinalizeHash(std::nullptr_t, CCoinsStats& stats) {}
|
||||
|
||||
@@ -14,6 +14,11 @@
|
||||
|
||||
class CCoinsView;
|
||||
|
||||
enum class CoinStatsHashType {
|
||||
HASH_SERIALIZED,
|
||||
NONE,
|
||||
};
|
||||
|
||||
struct CCoinsStats
|
||||
{
|
||||
int nHeight{0};
|
||||
@@ -30,6 +35,6 @@ struct CCoinsStats
|
||||
};
|
||||
|
||||
//! Calculate statistics about the unspent transaction output set
|
||||
bool GetUTXOStats(CCoinsView* view, CCoinsStats& stats, const std::function<void()>& interruption_point = {});
|
||||
bool GetUTXOStats(CCoinsView* view, CCoinsStats& stats, const CoinStatsHashType hash_type, const std::function<void()>& interruption_point = {});
|
||||
|
||||
#endif // BITCOIN_NODE_COINSTATS_H
|
||||
|
||||
Reference in New Issue
Block a user