refactor(headerssync): Extract test constants ahead of breakup into functions
What changed, and why it matters
This is a code cleanup (refactor) change in Bitcoin Core. It makes a 256-bit integer type usable in compile-time constants and reorganizes a test file so that repeated test data is generated in helper functions. There is no change to network behavior, consensus rules, or wallet handling, and no security fix.
No security action needed. Treat as ordinary code-quality/test refactor.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit marks constructors of base_uint and arith_uint256 as constexpr so they can be used for compile-time constants. It also extracts magic numbers (15,000 target blocks, chain work value) and header-generation helpers into a test fixture class in headers_sync_chainwork_tests.cpp. The test logic itself is unchanged; only structure and const-correctness are improved.
Changed components
src/arith_uint256.hsrc/test/headers_sync_chainwork_tests.cppInspect captured patch +53 / −46
diff --git a/src/arith_uint256.h b/src/arith_uint256.h
index 5cefff53..69e0aff8 100644
--- a/src/arith_uint256.h
+++ b/src/arith_uint256.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2022 The Bitcoin Core developers
+// Copyright (c) 2009-present The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -21,7 +21,7 @@ public:
};
/** Template base class for unsigned big integers. */
-template<unsigned int BITS>
+template <unsigned int BITS>
class base_uint
{
protected:
@@ -29,9 +29,9 @@ protected:
static constexpr int WIDTH = BITS / 32;
/** Big integer represented with 32-bit digits, least-significant first. */
uint32_t pn[WIDTH];
-public:
- base_uint()
+public:
+ constexpr base_uint()
{
for (int i = 0; i < WIDTH; i++)
pn[i] = 0;
@@ -40,7 +40,7 @@ public:
base_uint(const base_uint& b) = default;
base_uint& operator=(const base_uint& b) = default;
- base_uint(uint64_t b)
+ constexpr base_uint(uint64_t b)
{
pn[0] = (unsigned int)b;
pn[1] = (unsigned int)(b >> 32);
@@ -227,11 +227,12 @@ public:
};
/** 256-bit unsigned big integer. */
-class arith_uint256 : public base_uint<256> {
+class arith_uint256 : public base_uint<256>
+{
public:
- arith_uint256() = default;
- arith_uint256(const base_uint<256>& b) : base_uint<256>(b) {}
- arith_uint256(uint64_t b) : base_uint<256>(b) {}
+ constexpr arith_uint256() = default;
+ constexpr arith_uint256(const base_uint& b) : base_uint(b) {}
+ constexpr arith_uint256(uint64_t b) : base_uint(b) {}
/**
* The "compact" format is a representation of a whole
diff --git a/src/test/headers_sync_chainwork_tests.cpp b/src/test/headers_sync_chainwork_tests.cpp
index b710ad18..db58970f 100644
--- a/src/test/headers_sync_chainwork_tests.cpp
+++ b/src/test/headers_sync_chainwork_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2022 The Bitcoin Core developers
+// Copyright (c) 2022-present The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -9,11 +9,35 @@
#include <pow.h>
#include <test/util/setup_common.h>
#include <validation.h>
+
+#include <cstddef>
#include <vector>
#include <boost/test/unit_test.hpp>
+constexpr size_t TARGET_BLOCKS{15'000};
+constexpr arith_uint256 CHAIN_WORK{TARGET_BLOCKS * 2};
+
struct HeadersGeneratorSetup : public RegTestingSetup {
+ const CBlock& genesis{Params().GenesisBlock()};
+ const CBlockIndex* chain_start{WITH_LOCK(::cs_main, return m_node.chainman->m_blockman.LookupBlockIndex(genesis.GetHash()))};
+
+ // Generate headers for two different chains (using differing merkle roots
+ // to ensure the headers are different).
+ const std::vector<CBlockHeader>& FirstChain()
+ {
+ static const auto first_chain{GenerateHeaders(/*count=*/TARGET_BLOCKS - 1, genesis.GetHash(),
+ genesis.nVersion, genesis.nTime, /*merkle_root=*/uint256::ZERO, genesis.nBits)};
+ return first_chain;
+ }
+ const std::vector<CBlockHeader>& SecondChain()
+ {
+ static const auto second_chain{GenerateHeaders(/*count=*/TARGET_BLOCKS - 2, genesis.GetHash(),
+ genesis.nVersion, genesis.nTime, /*merkle_root=*/uint256::ONE, genesis.nBits)};
+ return second_chain;
+ }
+
+private:
/** Search for a nonce to meet (regtest) proof of work */
void FindProofOfWork(CBlockHeader& starting_header);
/**
@@ -21,42 +45,36 @@ struct HeadersGeneratorSetup : public RegTestingSetup {
* the given nVersion, advancing time by 1 second from the starting
* prev_time, and with a fixed merkle root hash.
*/
- void GenerateHeaders(std::vector<CBlockHeader>& headers, size_t count,
- const uint256& starting_hash, const int nVersion, int prev_time,
- const uint256& merkle_root, const uint32_t nBits);
+ std::vector<CBlockHeader> GenerateHeaders(size_t count,
+ uint256 prev_hash, int32_t nVersion, uint32_t prev_time,
+ const uint256& merkle_root, uint32_t nBits);
};
void HeadersGeneratorSetup::FindProofOfWork(CBlockHeader& starting_header)
{
while (!CheckProofOfWork(starting_header.GetHash(), starting_header.nBits, Params().GetConsensus())) {
- ++(starting_header.nNonce);
+ ++starting_header.nNonce;
}
}
-void HeadersGeneratorSetup::GenerateHeaders(std::vector<CBlockHeader>& headers,
- size_t count, const uint256& starting_hash, const int nVersion, int prev_time,
- const uint256& merkle_root, const uint32_t nBits)
+std::vector<CBlockHeader> HeadersGeneratorSetup::GenerateHeaders(
+ const size_t count, uint256 prev_hash, const int32_t nVersion,
+ uint32_t prev_time, const uint256& merkle_root, const uint32_t nBits)
{
- uint256 prev_hash = starting_hash;
-
- while (headers.size() < count) {
- headers.emplace_back();
- CBlockHeader& next_header = headers.back();;
+ std::vector<CBlockHeader> headers(count);
+ for (auto& next_header : headers) {
next_header.nVersion = nVersion;
next_header.hashPrevBlock = prev_hash;
next_header.hashMerkleRoot = merkle_root;
- next_header.nTime = prev_time+1;
+ next_header.nTime = ++prev_time;
next_header.nBits = nBits;
FindProofOfWork(next_header);
prev_hash = next_header.GetHash();
- prev_time = next_header.nTime;
}
- return;
+ return headers;
}
-BOOST_FIXTURE_TEST_SUITE(headers_sync_chainwork_tests, HeadersGeneratorSetup)
-
// In this test, we construct two sets of headers from genesis, one with
// sufficient proof of work and one without.
// 1. We deliver the first set of headers and verify that the headers sync state
@@ -65,34 +83,22 @@ BOOST_FIXTURE_TEST_SUITE(headers_sync_chainwork_tests, HeadersGeneratorSetup)
// processing (presumably due to commitments not matching).
// 3. Finally, we verify that repeating with the first set of headers in both
// phases is successful.
+BOOST_FIXTURE_TEST_SUITE(headers_sync_chainwork_tests, HeadersGeneratorSetup)
+
BOOST_AUTO_TEST_CASE(headers_sync_state)
{
- std::vector<CBlockHeader> first_chain;
- std::vector<CBlockHeader> second_chain;
+ const auto& first_chain{FirstChain()};
+ const auto& second_chain{SecondChain()};
std::unique_ptr<HeadersSyncState> hss;
- const int target_blocks = 15000;
- arith_uint256 chain_work = target_blocks*2;
-
- // Generate headers for two different chains (using differing merkle roots
- // to ensure the headers are different).
- GenerateHeaders(first_chain, target_blocks-1, Params().GenesisBlock().GetHash(),
- Params().GenesisBlock().nVersion, Params().GenesisBlock().nTime,
- ArithToUint256(0), Params().GenesisBlock().nBits);
-
- GenerateHeaders(second_chain, target_blocks-2, Params().GenesisBlock().GetHash(),
- Params().GenesisBlock().nVersion, Params().GenesisBlock().nTime,
- ArithToUint256(1), Params().GenesisBlock().nBits);
-
- const CBlockIndex* chain_start = WITH_LOCK(::cs_main, return m_node.chainman->m_blockman.LookupBlockIndex(Params().GenesisBlock().GetHash()));
std::vector<CBlockHeader> headers_batch;
// Feed the first chain to HeadersSyncState, by delivering 1 header
// initially and then the rest.
headers_batch.insert(headers_batch.end(), std::next(first_chain.begin()), first_chain.end());
- hss.reset(new HeadersSyncState(0, Params().GetConsensus(), chain_start, chain_work));
+ hss.reset(new HeadersSyncState(0, Params().GetConsensus(), chain_start, CHAIN_WORK));
(void)hss->ProcessNextHeaders({first_chain.front()}, true);
// Pretend the first header is still "full", so we don't abort.
auto result = hss->ProcessNextHeaders(headers_batch, true);
@@ -109,7 +115,7 @@ BOOST_AUTO_TEST_CASE(headers_sync_state)
BOOST_CHECK(hss->GetState() == HeadersSyncState::State::FINAL);
// Now try again, this time feeding the first chain twice.
- hss.reset(new HeadersSyncState(0, Params().GetConsensus(), chain_start, chain_work));
+ hss.reset(new HeadersSyncState(0, Params().GetConsensus(), chain_start, CHAIN_WORK));
(void)hss->ProcessNextHeaders(first_chain, true);
BOOST_CHECK(hss->GetState() == HeadersSyncState::State::REDOWNLOAD);
@@ -123,7 +129,7 @@ BOOST_AUTO_TEST_CASE(headers_sync_state)
// Finally, verify that just trying to process the second chain would not
// succeed (too little work)
- hss.reset(new HeadersSyncState(0, Params().GetConsensus(), chain_start, chain_work));
+ hss.reset(new HeadersSyncState(0, Params().GetConsensus(), chain_start, CHAIN_WORK));
BOOST_CHECK(hss->GetState() == HeadersSyncState::State::PRESYNC);
// Pretend just the first message is "full", so we don't abort.
(void)hss->ProcessNextHeaders({second_chain.front()}, true);
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.