Changeset View
Changeset View
Standalone View
Standalone View
src/test/checkpoints_tests.cpp
// Copyright (c) 2011-2015 The Bitcoin Core developers | // Copyright (c) 2011-2015 The Bitcoin Core developers | ||||
// Copyright (c) 2018 The Bitcoin developers | // Copyright (c) 2018 The Bitcoin developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
// | // | ||||
// Unit tests for block-chain checkpoints | // Unit tests for block-chain checkpoints | ||||
// | // | ||||
#include <checkpoints.h> | #include <checkpoints.h> | ||||
#include <chain.h> | |||||
#include <chainparams.h> | #include <chainparams.h> | ||||
#include <config.h> | |||||
#include <consensus/validation.h> | |||||
#include <streams.h> | |||||
#include <uint256.h> | #include <uint256.h> | ||||
#include <utilstrencodings.h> | |||||
#include <validation.h> | |||||
#include <test/test_bitcoin.h> | #include <test/test_bitcoin.h> | ||||
#include <boost/test/unit_test.hpp> | #include <boost/test/unit_test.hpp> | ||||
BOOST_FIXTURE_TEST_SUITE(checkpoints_tests, BasicTestingSetup) | BOOST_FIXTURE_TEST_SUITE(checkpoints_tests, TestingSetup) | ||||
BOOST_AUTO_TEST_CASE(sanity) { | BOOST_AUTO_TEST_CASE(sanity) { | ||||
const auto params = CreateChainParams(CBaseChainParams::MAIN); | const auto params = CreateChainParams(CBaseChainParams::MAIN); | ||||
const CCheckpointData &checkpoints = params->Checkpoints(); | const CCheckpointData &checkpoints = params->Checkpoints(); | ||||
uint256 p11111 = uint256S( | uint256 p11111 = uint256S( | ||||
"0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"); | "0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"); | ||||
uint256 p134444 = uint256S( | uint256 p134444 = uint256S( | ||||
"00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"); | "00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"); | ||||
BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 11111, p11111)); | BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 11111, p11111)); | ||||
BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 134444, p134444)); | BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 134444, p134444)); | ||||
// Wrong hashes at checkpoints should fail: | // Wrong hashes at checkpoints should fail: | ||||
BOOST_CHECK(!Checkpoints::CheckBlock(checkpoints, 11111, p134444)); | BOOST_CHECK(!Checkpoints::CheckBlock(checkpoints, 11111, p134444)); | ||||
BOOST_CHECK(!Checkpoints::CheckBlock(checkpoints, 134444, p11111)); | BOOST_CHECK(!Checkpoints::CheckBlock(checkpoints, 134444, p11111)); | ||||
// ... but any hash not at a checkpoint should succeed: | // ... but any hash not at a checkpoint should succeed: | ||||
BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 11111 + 1, p134444)); | BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 11111 + 1, p134444)); | ||||
BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 134444 + 1, p11111)); | BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 134444 + 1, p11111)); | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(ban_fork_at_genesis_block) { | |||||
DummyConfig config; | |||||
// Sanity check that a checkpoint exists at the genesis block | |||||
auto &checkpoints = config.GetChainParams().Checkpoints().mapCheckpoints; | |||||
assert(checkpoints.find(0) != checkpoints.end()); | |||||
// Another precomputed genesis block (with differing nTime) should conflict | |||||
// with the regnet genesis block checkpoint and not be accepted or stored | |||||
// in memory. | |||||
CBlockHeader header = | |||||
CreateGenesisBlock(1296688603, 2, 0x207fffff, 1, 50 * COIN); | |||||
// Header should not be accepted | |||||
CValidationState state; | |||||
CBlockHeader invalid; | |||||
const CBlockIndex *pindex = nullptr; | |||||
BOOST_CHECK( | |||||
!ProcessNewBlockHeaders(config, {header}, state, &pindex, &invalid)); | |||||
BOOST_CHECK(state.IsInvalid()); | |||||
BOOST_CHECK(pindex == nullptr); | |||||
BOOST_CHECK(invalid.GetHash() == header.GetHash()); | |||||
// Sanity check to ensure header was not saved in memory | |||||
{ | |||||
LOCK(cs_main); | |||||
BOOST_CHECK(LookupBlockIndex(header.GetHash()) == nullptr); | |||||
} | |||||
} | |||||
class ChainParamsWithCheckpoints : public CChainParams { | |||||
public: | |||||
ChainParamsWithCheckpoints(const CChainParams &chainParams, | |||||
CCheckpointData &checkpoints) | |||||
: CChainParams(chainParams) { | |||||
checkpointData = checkpoints; | |||||
} | |||||
}; | |||||
class MainnetConfigWithTestCheckpoints : public DummyConfig { | |||||
public: | |||||
MainnetConfigWithTestCheckpoints() : DummyConfig(createChainParams()) {} | |||||
static std::unique_ptr<CChainParams> createChainParams() { | |||||
CCheckpointData checkpoints = { | |||||
.mapCheckpoints = { | |||||
{2, uint256S("000000006a625f06636b8bb6ac7b960a8d0" | |||||
"3705d1ace08b1a19da3fdcc99ddbd")}, | |||||
}}; | |||||
const auto mainParams = CreateChainParams(CBaseChainParams::MAIN); | |||||
return std::make_unique<ChainParamsWithCheckpoints>(*mainParams, | |||||
checkpoints); | |||||
} | |||||
}; | |||||
/** | |||||
* This test has 4 precomputed blocks mined ontop of the genesis block: | |||||
* G ---> A ---> AA (checkpointed) | |||||
* \ \ | |||||
* \--> B \-> AB | |||||
* After the node has accepted only A and AA, these rejects should occur: | |||||
* * B should be rejected for forking prior to an accepted checkpoint | |||||
* * AB should be rejected for forking at an accepted checkpoint | |||||
*/ | |||||
BOOST_AUTO_TEST_CASE(ban_fork_prior_to_and_at_checkpoints) { | |||||
MainnetConfigWithTestCheckpoints config; | |||||
CValidationState state; | |||||
CBlockHeader invalid; | |||||
const CBlockIndex *pindex = nullptr; | |||||
// Start with mainnet genesis block | |||||
CBlockHeader headerG = config.GetChainParams().GenesisBlock(); | |||||
BOOST_CHECK(headerG.GetHash() == | |||||
uint256S("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f" | |||||
"1b60a8ce26f")); | |||||
BOOST_CHECK( | |||||
ProcessNewBlockHeaders(config, {headerG}, state, &pindex, &invalid)); | |||||
pindex = nullptr; | |||||
CBlockHeader headerA, headerB, headerAA, headerAB; | |||||
CDataStream stream = CDataStream( | |||||
ParseHex( | |||||
"010000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000" | |||||
"000000982051fd1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e85723" | |||||
"3e0e61bc6649ffff001d01e3629901010000000100000000000000000000000000" | |||||
"00000000000000000000000000000000000000ffffffff0704ffff001d0104ffff" | |||||
"ffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390" | |||||
"813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166" | |||||
"bf621e73a82cbf2342c858eeac00000000"), | |||||
SER_NETWORK, PROTOCOL_VERSION); | |||||
stream >> headerA; | |||||
BOOST_CHECK(headerA.GetHash() == | |||||
uint256S("00000000839a8e6886ab5951d76f411475428afc90947ee320161" | |||||
"bbf18eb6048")); | |||||
BOOST_CHECK(headerA.hashPrevBlock == headerG.GetHash()); | |||||
stream = CDataStream( | |||||
ParseHex( | |||||
"010000004860eb18bf1b1620e37e9490fc8a427514416fd75159ab86688e9a8300" | |||||
"000000d5fdcc541e25de1c7a5addedf24858b8bb665c9f36ef744ee42c316022c9" | |||||
"0f9bb0bc6649ffff001d08d2bd6101010000000100000000000000000000000000" | |||||
"00000000000000000000000000000000000000ffffffff0704ffff001d010bffff" | |||||
"ffff0100f2052a010000004341047211a824f55b505228e4c3d5194c1fcfaa15a4" | |||||
"56abdf37f9b9d97a4040afc073dee6c89064984f03385237d92167c13e236446b4" | |||||
"17ab79a0fcae412ae3316b77ac00000000"), | |||||
SER_NETWORK, PROTOCOL_VERSION); | |||||
stream >> headerAA; | |||||
BOOST_CHECK(headerAA.GetHash() == | |||||
uint256S("000000006a625f06636b8bb6ac7b960a8d03705d1ace08b1a19da" | |||||
"3fdcc99ddbd")); | |||||
BOOST_CHECK(headerAA.hashPrevBlock == headerA.GetHash()); | |||||
stream = CDataStream( | |||||
ParseHex( | |||||
"000000206fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000" | |||||
"000000bff4e0fd76ec3e9c8853811dec34dda8d5debb24d4113d94235fd4b24bb2" | |||||
"92981b70995cffff001d4e6e050001020000000100000000000000000000000000" | |||||
"00000000000000000000000000000000000000ffffffff0d51026302082f454233" | |||||
"322e302fffffffff0100f2052a01000000232103c91f2fa16c94c92d08629eeb8f" | |||||
"d681658d49f2b3016b13336d67d79f858dbc71ac000000001"), | |||||
SER_NETWORK, PROTOCOL_VERSION); | |||||
stream >> headerB; | |||||
BOOST_CHECK(headerB.hashPrevBlock == headerG.GetHash()); | |||||
stream = CDataStream( | |||||
ParseHex( | |||||
"000000204860eb18bf1b1620e37e9490fc8a427514416fd75159ab86688e9a8300" | |||||
"0000003800b1dd09f3f1a1c9e62ce8dca6d1e6caacc9a02d178ef6ad95527b49ff" | |||||
"863f8282995cffff001d2cc70f0001020000000100000000000000000000000000" | |||||
"00000000000000000000000000000000000000ffffffff0d52024902082f454233" | |||||
"322e302fffffffff0100f2052a010000002321020a56690eb0e2454c1f362d3599" | |||||
"89198a0b23505578be4164a65521ee7751eb1dac00000000"), | |||||
SER_NETWORK, PROTOCOL_VERSION); | |||||
stream >> headerAB; | |||||
BOOST_CHECK(headerAB.hashPrevBlock == headerA.GetHash()); | |||||
// Headers A and AA should be accepted | |||||
BOOST_CHECK( | |||||
ProcessNewBlockHeaders(config, {headerA}, state, &pindex, &invalid)); | |||||
BOOST_CHECK(state.IsValid()); | |||||
BOOST_CHECK(pindex != nullptr); | |||||
pindex = nullptr; | |||||
BOOST_CHECK(invalid.IsNull()); | |||||
BOOST_CHECK( | |||||
ProcessNewBlockHeaders(config, {headerAA}, state, &pindex, &invalid)); | |||||
BOOST_CHECK(state.IsValid()); | |||||
BOOST_CHECK(pindex != nullptr); | |||||
pindex = nullptr; | |||||
BOOST_CHECK(invalid.IsNull()); | |||||
// Header B should be rejected | |||||
BOOST_CHECK( | |||||
!ProcessNewBlockHeaders(config, {headerB}, state, &pindex, &invalid)); | |||||
BOOST_CHECK(state.IsInvalid()); | |||||
BOOST_CHECK(state.GetRejectCode() == REJECT_CHECKPOINT); | |||||
BOOST_CHECK(state.GetRejectReason() == "bad-fork-prior-to-checkpoint"); | |||||
BOOST_CHECK(pindex == nullptr); | |||||
BOOST_CHECK(invalid.GetHash() == headerB.GetHash()); | |||||
// Sanity check to ensure header was not saved in memory | |||||
{ | |||||
LOCK(cs_main); | |||||
BOOST_CHECK(LookupBlockIndex(headerB.GetHash()) == nullptr); | |||||
} | |||||
// Header AB should be rejected | |||||
BOOST_CHECK( | |||||
!ProcessNewBlockHeaders(config, {headerAB}, state, &pindex, &invalid)); | |||||
BOOST_CHECK(state.IsInvalid()); | |||||
BOOST_CHECK(state.GetRejectCode() == REJECT_CHECKPOINT); | |||||
BOOST_CHECK(state.GetRejectReason() == "checkpoint mismatch"); | |||||
BOOST_CHECK(pindex == nullptr); | |||||
BOOST_CHECK(invalid.GetHash() == headerAB.GetHash()); | |||||
// Sanity check to ensure header was not saved in memory | |||||
{ | |||||
LOCK(cs_main); | |||||
BOOST_CHECK(LookupBlockIndex(headerAB.GetHash()) == nullptr); | |||||
} | |||||
} | |||||
BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() |