#include <chain.h>
#include <chainparams.h>
#include <consensus/params.h>
#include <headerssync.h>
#include <pow.h>
#include <test/util/setup_common.h>
#include <validation.h>
#include <vector>
#include <boost/test/unit_test.hpp>
struct HeadersGeneratorSetup : public RegTestingSetup {
void FindProofOfWork(CBlockHeader& starting_header);
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);
};
void HeadersGeneratorSetup::FindProofOfWork(CBlockHeader& starting_header)
{
while (!CheckProofOfWork(starting_header.GetHash(), starting_header.nBits, Params().GetConsensus())) {
++(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)
{
uint256 prev_hash = starting_hash;
while (headers.size() < count) {
headers.emplace_back();
CBlockHeader& next_header = headers.back();;
next_header.nVersion = nVersion;
next_header.hashPrevBlock = prev_hash;
next_header.hashMerkleRoot = merkle_root;
next_header.nTime = prev_time+1;
next_header.nBits = nBits;
FindProofOfWork(next_header);
prev_hash = next_header.GetHash();
prev_time = next_header.nTime;
}
return;
}
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;
std::unique_ptr<HeadersSyncState> hss;
const int target_blocks = 15000;
arith_uint256 chain_work = target_blocks*2;
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;
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));
(void)hss->ProcessNextHeaders({first_chain.front()}, true);
auto result = hss->ProcessNextHeaders(headers_batch, true);
BOOST_CHECK(result.success);
BOOST_CHECK(result.request_more);
BOOST_CHECK(hss->GetState() == HeadersSyncState::State::REDOWNLOAD);
result = hss->ProcessNextHeaders(second_chain, true);
BOOST_CHECK(!result.success); BOOST_CHECK(hss->GetState() == HeadersSyncState::State::FINAL);
hss.reset(new HeadersSyncState(0, Params().GetConsensus(), chain_start, chain_work));
(void)hss->ProcessNextHeaders(first_chain, true);
BOOST_CHECK(hss->GetState() == HeadersSyncState::State::REDOWNLOAD);
result = hss->ProcessNextHeaders(first_chain, true);
BOOST_CHECK(result.success);
BOOST_CHECK(!result.request_more);
BOOST_CHECK(result.pow_validated_headers.size() == first_chain.size());
BOOST_CHECK(hss->GetState() == HeadersSyncState::State::FINAL);
hss.reset(new HeadersSyncState(0, Params().GetConsensus(), chain_start, chain_work));
BOOST_CHECK(hss->GetState() == HeadersSyncState::State::PRESYNC);
(void)hss->ProcessNextHeaders({second_chain.front()}, true);
BOOST_CHECK(hss->GetState() == HeadersSyncState::State::PRESYNC);
headers_batch.clear();
headers_batch.insert(headers_batch.end(), std::next(second_chain.begin(), 1), second_chain.end());
result = hss->ProcessNextHeaders(headers_batch, false);
BOOST_CHECK(hss->GetState() == HeadersSyncState::State::FINAL);
BOOST_CHECK(result.pow_validated_headers.empty());
BOOST_CHECK(!result.request_more);
BOOST_CHECK(result.success);
}
BOOST_AUTO_TEST_SUITE_END()