Merge ee9befe8b4 into merged_master (Bitcoin PR bitcoin/bitcoin#21584)

This commit is contained in:
Andrew Poelstra 2021-07-09 21:14:15 +00:00
commit 1fd44e5dfc
10 changed files with 130 additions and 123 deletions

View file

@ -259,6 +259,7 @@ BITCOIN_CORE_H = \
util/fees.h \
util/getuniquepath.h \
util/golombrice.h \
util/hash_type.h \
util/hasher.h \
util/macros.h \
util/message.h \

View file

@ -551,11 +551,11 @@ public:
m_assumeutxo_data = MapAssumeutxo{
{
110,
{uint256S("0x09a3e443dbf48f3b95207c9ce529062d9764395232c482aa7d3a0bf274d282d9"), 110},
{AssumeutxoHash{uint256S("0x09a3e443dbf48f3b95207c9ce529062d9764395232c482aa7d3a0bf274d282d9")}, 110},
},
{
210,
{uint256S("0x9c5ed99ef98544b34f8920b6d1802f72ac28ae6e2bd2bd4c316ff10c230df3f2"), 210},
{AssumeutxoHash{uint256S("0x9c5ed99ef98544b34f8920b6d1802f72ac28ae6e2bd2bd4c316ff10c230df3f2")}, 210},
},
};
@ -1344,9 +1344,3 @@ void SelectParams(const std::string& network)
SelectBaseParams(network);
globalChainParams = CreateChainParams(gArgs, network);
}
std::ostream& operator<<(std::ostream& o, const AssumeutxoData& aud)
{
o << strprintf("AssumeutxoData(%s, %s)", aud.hash_serialized.ToString(), aud.nChainTx);
return o;
}

View file

@ -10,6 +10,7 @@
#include <consensus/params.h>
#include <primitives/block.h>
#include <protocol.h>
#include <util/hash_type.h>
#include <memory>
#include <vector>
@ -25,6 +26,10 @@ struct CCheckpointData {
}
};
struct AssumeutxoHash : public BaseHash<uint256> {
explicit AssumeutxoHash(const uint256& hash) : BaseHash(hash) {}
};
/**
* Holds configuration for use during UTXO snapshot load and validation. The contents
* here are security critical, since they dictate which UTXO snapshots are recognized
@ -32,7 +37,7 @@ struct CCheckpointData {
*/
struct AssumeutxoData {
//! The expected hash of the deserialized UTXO set.
const uint256 hash_serialized;
const AssumeutxoHash hash_serialized;
//! Used to populate the nChainTx value, which is used during BlockManager::LoadBlockIndex().
//!
@ -41,8 +46,6 @@ struct AssumeutxoData {
const unsigned int nChainTx;
};
std::ostream& operator<<(std::ostream& o, const AssumeutxoData& aud);
using MapAssumeutxo = std::map<int, const AssumeutxoData>;
/**

View file

@ -20,8 +20,6 @@
#include <functional>
#include <unordered_map>
class ChainstateManager;
/**
* A UTXO entry.
*

View file

@ -8,6 +8,7 @@
#include <script/interpreter.h>
#include <uint256.h>
#include <util/hash_type.h>
#include <string>
#include <variant>
@ -20,70 +21,6 @@ class CKeyID;
class CScript;
struct ScriptHash;
template<typename HashType>
class BaseHash
{
protected:
HashType m_hash;
public:
BaseHash() : m_hash() {}
explicit BaseHash(const HashType& in) : m_hash(in) {}
unsigned char* begin()
{
return m_hash.begin();
}
const unsigned char* begin() const
{
return m_hash.begin();
}
unsigned char* end()
{
return m_hash.end();
}
const unsigned char* end() const
{
return m_hash.end();
}
operator std::vector<unsigned char>() const
{
return std::vector<unsigned char>{m_hash.begin(), m_hash.end()};
}
std::string ToString() const
{
return m_hash.ToString();
}
bool operator==(const BaseHash<HashType>& other) const noexcept
{
return m_hash == other.m_hash;
}
bool operator!=(const BaseHash<HashType>& other) const noexcept
{
return !(m_hash == other.m_hash);
}
bool operator<(const BaseHash<HashType>& other) const noexcept
{
return m_hash < other.m_hash;
}
size_t size() const
{
return m_hash.size();
}
unsigned char* data() { return m_hash.data(); }
const unsigned char* data() const { return m_hash.data(); }
};
/** A reference to a CScript: the Hash160 of its serialization (see script.h) */
class CScriptID : public BaseHash<uint160>
{

View file

@ -226,10 +226,8 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup)
// Snapshot should refuse to load at this height.
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(m_node, m_path_root));
BOOST_CHECK(chainman.ActiveChainstate().m_from_snapshot_blockhash.IsNull());
BOOST_CHECK_EQUAL(
chainman.ActiveChainstate().m_from_snapshot_blockhash,
chainman.SnapshotBlockhash().value_or(uint256()));
BOOST_CHECK(!chainman.ActiveChainstate().m_from_snapshot_blockhash);
BOOST_CHECK(!chainman.SnapshotBlockhash());
// Mine 10 more blocks, putting at us height 110 where a valid assumeutxo value can
// be found.
@ -260,6 +258,11 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup)
// Coins count is smaller than coins in file
metadata.m_coins_count -= 1;
}));
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
m_node, m_path_root, [](CAutoFile& auto_infile, SnapshotMetadata& metadata) {
// Wrong hash
metadata.m_base_blockhash = uint256::ZERO;
}));
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
m_node, m_path_root, [](CAutoFile& auto_infile, SnapshotMetadata& metadata) {
// Wrong hash
@ -269,9 +272,9 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup)
BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(m_node, m_path_root));
// Ensure our active chain is the snapshot chainstate.
BOOST_CHECK(!chainman.ActiveChainstate().m_from_snapshot_blockhash.IsNull());
BOOST_CHECK(!chainman.ActiveChainstate().m_from_snapshot_blockhash->IsNull());
BOOST_CHECK_EQUAL(
chainman.ActiveChainstate().m_from_snapshot_blockhash,
*chainman.ActiveChainstate().m_from_snapshot_blockhash,
*chainman.SnapshotBlockhash());
const AssumeutxoData& au_data = *ExpectedAssumeutxo(snapshot_height, ::Params());
@ -347,7 +350,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup)
// Snapshot blockhash should be unchanged.
BOOST_CHECK_EQUAL(
chainman.ActiveChainstate().m_from_snapshot_blockhash,
*chainman.ActiveChainstate().m_from_snapshot_blockhash,
loaded_snapshot_blockhash);
}

View file

@ -136,11 +136,11 @@ BOOST_AUTO_TEST_CASE(test_assumeutxo)
}
const auto out110 = *ExpectedAssumeutxo(110, *params);
BOOST_CHECK_EQUAL(out110.hash_serialized, uint256S("09a3e443dbf48f3b95207c9ce529062d9764395232c482aa7d3a0bf274d282d9"));
BOOST_CHECK_EQUAL(out110.hash_serialized.ToString(), "09a3e443dbf48f3b95207c9ce529062d9764395232c482aa7d3a0bf274d282d9");
BOOST_CHECK_EQUAL(out110.nChainTx, (unsigned int)110);
const auto out210 = *ExpectedAssumeutxo(210, *params);
BOOST_CHECK_EQUAL(out210.hash_serialized, uint256S("9c5ed99ef98544b34f8920b6d1802f72ac28ae6e2bd2bd4c316ff10c230df3f2"));
BOOST_CHECK_EQUAL(out210.hash_serialized.ToString(), "9c5ed99ef98544b34f8920b6d1802f72ac28ae6e2bd2bd4c316ff10c230df3f2");
BOOST_CHECK_EQUAL(out210.nChainTx, (unsigned int)210);
}

72
src/util/hash_type.h Normal file
View file

@ -0,0 +1,72 @@
// Copyright (c) 2020-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_UTIL_HASH_TYPE_H
#define BITCOIN_UTIL_HASH_TYPE_H
template <typename HashType>
class BaseHash
{
protected:
HashType m_hash;
public:
BaseHash() : m_hash() {}
explicit BaseHash(const HashType& in) : m_hash(in) {}
unsigned char* begin()
{
return m_hash.begin();
}
const unsigned char* begin() const
{
return m_hash.begin();
}
unsigned char* end()
{
return m_hash.end();
}
const unsigned char* end() const
{
return m_hash.end();
}
operator std::vector<unsigned char>() const
{
return std::vector<unsigned char>{m_hash.begin(), m_hash.end()};
}
std::string ToString() const
{
return m_hash.ToString();
}
bool operator==(const BaseHash<HashType>& other) const noexcept
{
return m_hash == other.m_hash;
}
bool operator!=(const BaseHash<HashType>& other) const noexcept
{
return !(m_hash == other.m_hash);
}
bool operator<(const BaseHash<HashType>& other) const noexcept
{
return m_hash < other.m_hash;
}
size_t size() const
{
return m_hash.size();
}
unsigned char* data() { return m_hash.data(); }
const unsigned char* data() const { return m_hash.data(); }
};
#endif // BITCOIN_UTIL_HASH_TYPE_H

View file

@ -1236,7 +1236,7 @@ void CoinsViews::InitCache()
m_cacheview = std::make_unique<CCoinsViewCache>(&m_catcherview);
}
CChainState::CChainState(CTxMemPool& mempool, BlockManager& blockman, uint256 from_snapshot_blockhash)
CChainState::CChainState(CTxMemPool& mempool, BlockManager& blockman, std::optional<uint256> from_snapshot_blockhash)
: m_mempool(mempool),
m_blockman(blockman),
m_from_snapshot_blockhash(from_snapshot_blockhash) {}
@ -1247,8 +1247,8 @@ void CChainState::InitCoinsDB(
bool should_wipe,
std::string leveldb_name)
{
if (!m_from_snapshot_blockhash.IsNull()) {
leveldb_name += "_" + m_from_snapshot_blockhash.ToString();
if (m_from_snapshot_blockhash) {
leveldb_name += "_" + m_from_snapshot_blockhash->ToString();
}
m_coins_views = std::make_unique<CoinsViews>(
@ -4234,7 +4234,7 @@ bool CVerifyDB::VerifyDB(
int reportDone = 0;
LogPrintf("[0%%]..."); /* Continued */
bool is_snapshot_cs = !chainstate.m_from_snapshot_blockhash.IsNull();
const bool is_snapshot_cs{!chainstate.m_from_snapshot_blockhash};
for (pindex = chainstate.m_chain.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) {
const int percentageDone = std::max(1, std::min(99, (int)(((double)(chainstate.m_chain.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100))));
@ -4815,8 +4815,8 @@ std::string CChainState::ToString()
{
CBlockIndex* tip = m_chain.Tip();
return strprintf("Chainstate [%s] @ height %d (%s)",
m_from_snapshot_blockhash.IsNull() ? "ibd" : "snapshot",
tip ? tip->nHeight : -1, tip ? tip->GetBlockHash().ToString() : "null");
m_from_snapshot_blockhash ? "snapshot" : "ibd",
tip ? tip->nHeight : -1, tip ? tip->GetBlockHash().ToString() : "null");
}
bool CChainState::ResizeCoinsCaches(size_t coinstip_size, size_t coinsdb_size)
@ -5018,10 +5018,10 @@ double GuessVerificationProgress(const CBlockIndex* pindex, int64_t blockInterva
return std::min(1.0, progress);
}
std::optional<uint256> ChainstateManager::SnapshotBlockhash() const {
std::optional<uint256> ChainstateManager::SnapshotBlockhash() const
{
LOCK(::cs_main);
if (m_active_chainstate != nullptr &&
!m_active_chainstate->m_from_snapshot_blockhash.IsNull()) {
if (m_active_chainstate && m_active_chainstate->m_from_snapshot_blockhash) {
// If a snapshot chainstate exists, it will always be our active.
return m_active_chainstate->m_from_snapshot_blockhash;
}
@ -5044,9 +5044,9 @@ std::vector<CChainState*> ChainstateManager::GetAll()
return out;
}
CChainState& ChainstateManager::InitializeChainstate(CTxMemPool& mempool, const uint256& snapshot_blockhash)
CChainState& ChainstateManager::InitializeChainstate(CTxMemPool& mempool, const std::optional<uint256>& snapshot_blockhash)
{
bool is_snapshot = !snapshot_blockhash.IsNull();
bool is_snapshot = snapshot_blockhash.has_value();
std::unique_ptr<CChainState>& to_modify =
is_snapshot ? m_snapshot_chainstate : m_ibd_chainstate;
@ -5171,6 +5171,26 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
uint256 base_blockhash = metadata.m_base_blockhash;
CBlockIndex* snapshot_start_block = WITH_LOCK(::cs_main, return m_blockman.LookupBlockIndex(base_blockhash));
if (!snapshot_start_block) {
// Needed for GetUTXOStats and ExpectedAssumeutxo to determine the height and to avoid a crash when base_blockhash.IsNull()
LogPrintf("[snapshot] Did not find snapshot start blockheader %s\n",
base_blockhash.ToString());
return false;
}
int base_height = snapshot_start_block->nHeight;
auto maybe_au_data = ExpectedAssumeutxo(base_height, ::Params());
if (!maybe_au_data) {
LogPrintf("[snapshot] assumeutxo height in snapshot metadata not recognized " /* Continued */
"(%d) - refusing to load snapshot\n", base_height);
return false;
}
const AssumeutxoData& au_data = *maybe_au_data;
COutPoint outpoint;
Coin coin;
const uint64_t coins_count = metadata.m_coins_count;
@ -5261,15 +5281,6 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
assert(coins_cache.GetBestBlock() == base_blockhash);
CBlockIndex* snapshot_start_block = WITH_LOCK(::cs_main, return m_blockman.LookupBlockIndex(base_blockhash));
if (!snapshot_start_block) {
// Needed for GetUTXOStats to determine the height
LogPrintf("[snapshot] Did not find snapshot start blockheader %s\n",
base_blockhash.ToString());
return false;
}
CCoinsStats stats{CoinStatsHashType::HASH_SERIALIZED};
auto breakpoint_fnc = [] { /* TODO insert breakpoint here? */ };
@ -5283,19 +5294,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
}
// Assert that the deserialized chainstate contents match the expected assumeutxo value.
int base_height = snapshot_start_block->nHeight;
auto maybe_au_data = ExpectedAssumeutxo(base_height, ::Params());
if (!maybe_au_data) {
LogPrintf("[snapshot] assumeutxo height in snapshot metadata not recognized " /* Continued */
"(%d) - refusing to load snapshot\n", base_height);
return false;
}
const AssumeutxoData& au_data = *maybe_au_data;
if (stats.hashSerialized != au_data.hash_serialized) {
if (AssumeutxoHash{stats.hashSerialized} != au_data.hash_serialized) {
LogPrintf("[snapshot] bad snapshot content hash: expected %s, got %s\n",
au_data.hash_serialized.ToString(), stats.hashSerialized.ToString());
return false;

View file

@ -555,7 +555,7 @@ public:
//! CChainState instances.
BlockManager& m_blockman;
explicit CChainState(CTxMemPool& mempool, BlockManager& blockman, uint256 from_snapshot_blockhash = uint256());
explicit CChainState(CTxMemPool& mempool, BlockManager& blockman, std::optional<uint256> from_snapshot_blockhash = std::nullopt);
/**
* Initialize the CoinsViews UTXO set database management data structures. The in-memory
@ -586,9 +586,9 @@ public:
/**
* The blockhash which is the base of the snapshot this chainstate was created from.
*
* IsNull() if this chainstate was not created from a snapshot.
* std::nullopt if this chainstate was not created from a snapshot.
*/
const uint256 m_from_snapshot_blockhash{};
const std::optional<uint256> m_from_snapshot_blockhash;
/**
* The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself and all ancestors) and
@ -868,7 +868,7 @@ public:
// constructor
//! @param[in] snapshot_blockhash If given, signify that this chainstate
//! is based on a snapshot.
CChainState& InitializeChainstate(CTxMemPool& mempool, const uint256& snapshot_blockhash = uint256())
CChainState& InitializeChainstate(CTxMemPool& mempool, const std::optional<uint256>& snapshot_blockhash = std::nullopt)
EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
//! Get all chainstates currently being used.