Skip to content

Commit ee9befe

Browse files
committed
Merge bitcoin#21584: Fix assumeutxo crash due to invalid base_blockhash
fa340b8 refactor: Avoid magic value of all-zeros in assumeutxo base_blockhash (MarcoFalke) fae33f9 Fix assumeutxo crash due to invalid base_blockhash (MarcoFalke) fa5668b refactor: Use type-safe assumeutxo hash (MarcoFalke) 0000007 refactor: Remove unused code (MarcoFalke) faa921f move-only: Add util/hash_type (MarcoFalke) Pull request description: Starting with commit d6af06d, a block hash of all-zeros is invalid and will lead to a crash of the node. Can be tested by cherry-picking the test changes without the other changes. Stack trace (copied from bitcoin#21584 (comment)): ``` #0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51 bitcoin#1 0x00007ffff583c8b1 in __GI_abort () at abort.c:79 #2 0x00007ffff582c42a in __assert_fail_base (fmt=0x7ffff59b3a38 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", assertion=assertion@entry=0x555556c8b450 "!hashBlock.IsNull()", file=file@entry=0x555556c8b464 "txdb.cpp", line=line@entry=89, function=function@entry=0x555556c8b46d "virtual bool CCoinsViewDB::BatchWrite(CCoinsMap &, const uint256 &)") at assert.c:92 #3 0x00007ffff582c4a2 in __GI___assert_fail (assertion=0x555556c8b450 "!hashBlock.IsNull()", file=0x555556c8b464 "txdb.cpp", line=89, function=0x555556c8b46d "virtual bool CCoinsViewDB::BatchWrite(CCoinsMap &, const uint256 &)") at assert.c:101 #4 0x000055555636738b in CCoinsViewDB::BatchWrite (this=0x5555577975c0, mapCoins=std::unordered_map with 110 elements = {...}, hashBlock=...) at txdb.cpp:89 #5 0x00005555564a2e80 in CCoinsViewBacked::BatchWrite (this=0x5555577975f8, mapCoins=std::unordered_map with 110 elements = {...}, hashBlock=...) at coins.cpp:30 #6 0x00005555564a43de in CCoinsViewCache::Flush (this=0x55555778eaf0) at coins.cpp:223 #7 0x00005555563fc11d in ChainstateManager::PopulateAndValidateSnapshot (this=0x55555740b038 <g_chainman>, snapshot_chainstate=..., coins_file=..., metadata=...) at validation.cpp:5422 #8 0x00005555563fab3d in ChainstateManager::ActivateSnapshot (this=0x55555740b038 <g_chainman>, coins_file=..., metadata=..., in_memory=true) at validation.cpp:5299 #9 0x0000555555e8c893 in validation_chainstatemanager_tests::CreateAndActivateUTXOSnapshot<validation_chainstatemanager_tests::chainstatemanager_activate_snapshot::test_method()::$_12>(NodeContext&, boost::filesystem::path, validation_chainstatemanager_tests::chainstatemanager_activate_snapshot::test_method()::$_12) (node=..., root=..., malleation=...) at test/validation_chainstatemanager_tests.cpp:199 #10 0x0000555555e8877a in validation_chainstatemanager_tests::chainstatemanager_activate_snapshot::test_method (this=0x7fffffffc8d0) at test/validation_chainstatemanager_tests.cpp:262 ACKs for top commit: laanwj: Code review re-ACK fa340b8 jamesob: ACK fa340b8 ([`jamesob/ackr/21584.1.MarcoFalke.fix_assumeutxo_crash_due`](https://github.com/jamesob/bitcoin/tree/ackr/21584.1.MarcoFalke.fix_assumeutxo_crash_due)) Tree-SHA512: c2c4e66c1abfd400ef18a04f22fec1f302f1ff4d27a18050f492f688319deb4ccdd165ff792eee0a1f816e7b69fb64080662b79517ab669e3d26b9eb77802851
2 parents 79da18a + fa340b8 commit ee9befe

File tree

10 files changed

+130
-123
lines changed

10 files changed

+130
-123
lines changed

src/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ BITCOIN_CORE_H = \
246246
util/fees.h \
247247
util/getuniquepath.h \
248248
util/golombrice.h \
249+
util/hash_type.h \
249250
util/hasher.h \
250251
util/macros.h \
251252
util/message.h \

src/chainparams.cpp

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -451,11 +451,11 @@ class CRegTestParams : public CChainParams {
451451
m_assumeutxo_data = MapAssumeutxo{
452452
{
453453
110,
454-
{uint256S("0x1ebbf5850204c0bdb15bf030f47c7fe91d45c44c712697e4509ba67adb01c618"), 110},
454+
{AssumeutxoHash{uint256S("0x1ebbf5850204c0bdb15bf030f47c7fe91d45c44c712697e4509ba67adb01c618")}, 110},
455455
},
456456
{
457457
210,
458-
{uint256S("0x9c5ed99ef98544b34f8920b6d1802f72ac28ae6e2bd2bd4c316ff10c230df3f2"), 210},
458+
{AssumeutxoHash{uint256S("0x9c5ed99ef98544b34f8920b6d1802f72ac28ae6e2bd2bd4c316ff10c230df3f2")}, 210},
459459
},
460460
};
461461

@@ -559,9 +559,3 @@ void SelectParams(const std::string& network)
559559
SelectBaseParams(network);
560560
globalChainParams = CreateChainParams(gArgs, network);
561561
}
562-
563-
std::ostream& operator<<(std::ostream& o, const AssumeutxoData& aud)
564-
{
565-
o << strprintf("AssumeutxoData(%s, %s)", aud.hash_serialized.ToString(), aud.nChainTx);
566-
return o;
567-
}

src/chainparams.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <consensus/params.h>
1111
#include <primitives/block.h>
1212
#include <protocol.h>
13+
#include <util/hash_type.h>
1314

1415
#include <memory>
1516
#include <vector>
@@ -25,14 +26,18 @@ struct CCheckpointData {
2526
}
2627
};
2728

29+
struct AssumeutxoHash : public BaseHash<uint256> {
30+
explicit AssumeutxoHash(const uint256& hash) : BaseHash(hash) {}
31+
};
32+
2833
/**
2934
* Holds configuration for use during UTXO snapshot load and validation. The contents
3035
* here are security critical, since they dictate which UTXO snapshots are recognized
3136
* as valid.
3237
*/
3338
struct AssumeutxoData {
3439
//! The expected hash of the deserialized UTXO set.
35-
const uint256 hash_serialized;
40+
const AssumeutxoHash hash_serialized;
3641

3742
//! Used to populate the nChainTx value, which is used during BlockManager::LoadBlockIndex().
3843
//!
@@ -41,8 +46,6 @@ struct AssumeutxoData {
4146
const unsigned int nChainTx;
4247
};
4348

44-
std::ostream& operator<<(std::ostream& o, const AssumeutxoData& aud);
45-
4649
using MapAssumeutxo = std::map<int, const AssumeutxoData>;
4750

4851
/**

src/coins.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@
2020
#include <functional>
2121
#include <unordered_map>
2222

23-
class ChainstateManager;
24-
2523
/**
2624
* A UTXO entry.
2725
*

src/script/standard.h

Lines changed: 1 addition & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <script/interpreter.h>
1010
#include <uint256.h>
11+
#include <util/hash_type.h>
1112

1213
#include <string>
1314
#include <variant>
@@ -18,70 +19,6 @@ class CKeyID;
1819
class CScript;
1920
struct ScriptHash;
2021

21-
template<typename HashType>
22-
class BaseHash
23-
{
24-
protected:
25-
HashType m_hash;
26-
27-
public:
28-
BaseHash() : m_hash() {}
29-
explicit BaseHash(const HashType& in) : m_hash(in) {}
30-
31-
unsigned char* begin()
32-
{
33-
return m_hash.begin();
34-
}
35-
36-
const unsigned char* begin() const
37-
{
38-
return m_hash.begin();
39-
}
40-
41-
unsigned char* end()
42-
{
43-
return m_hash.end();
44-
}
45-
46-
const unsigned char* end() const
47-
{
48-
return m_hash.end();
49-
}
50-
51-
operator std::vector<unsigned char>() const
52-
{
53-
return std::vector<unsigned char>{m_hash.begin(), m_hash.end()};
54-
}
55-
56-
std::string ToString() const
57-
{
58-
return m_hash.ToString();
59-
}
60-
61-
bool operator==(const BaseHash<HashType>& other) const noexcept
62-
{
63-
return m_hash == other.m_hash;
64-
}
65-
66-
bool operator!=(const BaseHash<HashType>& other) const noexcept
67-
{
68-
return !(m_hash == other.m_hash);
69-
}
70-
71-
bool operator<(const BaseHash<HashType>& other) const noexcept
72-
{
73-
return m_hash < other.m_hash;
74-
}
75-
76-
size_t size() const
77-
{
78-
return m_hash.size();
79-
}
80-
81-
unsigned char* data() { return m_hash.data(); }
82-
const unsigned char* data() const { return m_hash.data(); }
83-
};
84-
8522
/** A reference to a CScript: the Hash160 of its serialization (see script.h) */
8623
class CScriptID : public BaseHash<uint160>
8724
{

src/test/validation_chainstatemanager_tests.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -226,10 +226,8 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup)
226226

227227
// Snapshot should refuse to load at this height.
228228
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(m_node, m_path_root));
229-
BOOST_CHECK(chainman.ActiveChainstate().m_from_snapshot_blockhash.IsNull());
230-
BOOST_CHECK_EQUAL(
231-
chainman.ActiveChainstate().m_from_snapshot_blockhash,
232-
chainman.SnapshotBlockhash().value_or(uint256()));
229+
BOOST_CHECK(!chainman.ActiveChainstate().m_from_snapshot_blockhash);
230+
BOOST_CHECK(!chainman.SnapshotBlockhash());
233231

234232
// Mine 10 more blocks, putting at us height 110 where a valid assumeutxo value can
235233
// be found.
@@ -260,6 +258,11 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup)
260258
// Coins count is smaller than coins in file
261259
metadata.m_coins_count -= 1;
262260
}));
261+
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
262+
m_node, m_path_root, [](CAutoFile& auto_infile, SnapshotMetadata& metadata) {
263+
// Wrong hash
264+
metadata.m_base_blockhash = uint256::ZERO;
265+
}));
263266
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
264267
m_node, m_path_root, [](CAutoFile& auto_infile, SnapshotMetadata& metadata) {
265268
// Wrong hash
@@ -269,9 +272,9 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup)
269272
BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(m_node, m_path_root));
270273

271274
// Ensure our active chain is the snapshot chainstate.
272-
BOOST_CHECK(!chainman.ActiveChainstate().m_from_snapshot_blockhash.IsNull());
275+
BOOST_CHECK(!chainman.ActiveChainstate().m_from_snapshot_blockhash->IsNull());
273276
BOOST_CHECK_EQUAL(
274-
chainman.ActiveChainstate().m_from_snapshot_blockhash,
277+
*chainman.ActiveChainstate().m_from_snapshot_blockhash,
275278
*chainman.SnapshotBlockhash());
276279

277280
const AssumeutxoData& au_data = *ExpectedAssumeutxo(snapshot_height, ::Params());
@@ -347,7 +350,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup)
347350

348351
// Snapshot blockhash should be unchanged.
349352
BOOST_CHECK_EQUAL(
350-
chainman.ActiveChainstate().m_from_snapshot_blockhash,
353+
*chainman.ActiveChainstate().m_from_snapshot_blockhash,
351354
loaded_snapshot_blockhash);
352355
}
353356

src/test/validation_tests.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,11 @@ BOOST_AUTO_TEST_CASE(test_assumeutxo)
135135
}
136136

137137
const auto out110 = *ExpectedAssumeutxo(110, *params);
138-
BOOST_CHECK_EQUAL(out110.hash_serialized, uint256S("1ebbf5850204c0bdb15bf030f47c7fe91d45c44c712697e4509ba67adb01c618"));
138+
BOOST_CHECK_EQUAL(out110.hash_serialized.ToString(), "1ebbf5850204c0bdb15bf030f47c7fe91d45c44c712697e4509ba67adb01c618");
139139
BOOST_CHECK_EQUAL(out110.nChainTx, (unsigned int)110);
140140

141141
const auto out210 = *ExpectedAssumeutxo(210, *params);
142-
BOOST_CHECK_EQUAL(out210.hash_serialized, uint256S("9c5ed99ef98544b34f8920b6d1802f72ac28ae6e2bd2bd4c316ff10c230df3f2"));
142+
BOOST_CHECK_EQUAL(out210.hash_serialized.ToString(), "9c5ed99ef98544b34f8920b6d1802f72ac28ae6e2bd2bd4c316ff10c230df3f2");
143143
BOOST_CHECK_EQUAL(out210.nChainTx, (unsigned int)210);
144144
}
145145

src/util/hash_type.h

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright (c) 2020-2021 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#ifndef BITCOIN_UTIL_HASH_TYPE_H
6+
#define BITCOIN_UTIL_HASH_TYPE_H
7+
8+
template <typename HashType>
9+
class BaseHash
10+
{
11+
protected:
12+
HashType m_hash;
13+
14+
public:
15+
BaseHash() : m_hash() {}
16+
explicit BaseHash(const HashType& in) : m_hash(in) {}
17+
18+
unsigned char* begin()
19+
{
20+
return m_hash.begin();
21+
}
22+
23+
const unsigned char* begin() const
24+
{
25+
return m_hash.begin();
26+
}
27+
28+
unsigned char* end()
29+
{
30+
return m_hash.end();
31+
}
32+
33+
const unsigned char* end() const
34+
{
35+
return m_hash.end();
36+
}
37+
38+
operator std::vector<unsigned char>() const
39+
{
40+
return std::vector<unsigned char>{m_hash.begin(), m_hash.end()};
41+
}
42+
43+
std::string ToString() const
44+
{
45+
return m_hash.ToString();
46+
}
47+
48+
bool operator==(const BaseHash<HashType>& other) const noexcept
49+
{
50+
return m_hash == other.m_hash;
51+
}
52+
53+
bool operator!=(const BaseHash<HashType>& other) const noexcept
54+
{
55+
return !(m_hash == other.m_hash);
56+
}
57+
58+
bool operator<(const BaseHash<HashType>& other) const noexcept
59+
{
60+
return m_hash < other.m_hash;
61+
}
62+
63+
size_t size() const
64+
{
65+
return m_hash.size();
66+
}
67+
68+
unsigned char* data() { return m_hash.data(); }
69+
const unsigned char* data() const { return m_hash.data(); }
70+
};
71+
72+
#endif // BITCOIN_UTIL_HASH_TYPE_H

0 commit comments

Comments
 (0)