diff --git a/src/arith_uint256.h b/src/arith_uint256.h index 5cefff53ae9..69e0aff8d3f 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 +template 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 b710ad1801e..db58970f8a5 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 #include #include + +#include #include #include +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& 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& 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& headers, size_t count, - const uint256& starting_hash, const int nVersion, int prev_time, - const uint256& merkle_root, const uint32_t nBits); + std::vector 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& headers, - size_t count, const uint256& starting_hash, const int nVersion, int prev_time, - const uint256& merkle_root, const uint32_t nBits) +std::vector 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 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 first_chain; - std::vector second_chain; + const auto& first_chain{FirstChain()}; + const auto& second_chain{SecondChain()}; std::unique_ptr 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 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);