mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-09 10:43:19 -05:00
![Fabian Jahr](/assets/img/avatar_default.png)
The legacy serialization was vulnerable to maleation and is fixed by adopting the same serialization procedure as was already in use for MuHash. This also includes necessary test fixes where the hash_serialized2 was hardcoded as well as correction of the regtest chainparams. Co-authored-by: Sebastian Falbesoner <sebastian.falbesoner@gmail.com>
148 lines
6.3 KiB
C++
148 lines
6.3 KiB
C++
// Copyright (c) 2014-2021 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#include <chainparams.h>
|
|
#include <consensus/amount.h>
|
|
#include <net.h>
|
|
#include <signet.h>
|
|
#include <uint256.h>
|
|
#include <util/chaintype.h>
|
|
#include <validation.h>
|
|
|
|
#include <test/util/setup_common.h>
|
|
|
|
#include <boost/test/unit_test.hpp>
|
|
|
|
BOOST_FIXTURE_TEST_SUITE(validation_tests, TestingSetup)
|
|
|
|
static void TestBlockSubsidyHalvings(const Consensus::Params& consensusParams)
|
|
{
|
|
int maxHalvings = 64;
|
|
CAmount nInitialSubsidy = 50 * COIN;
|
|
|
|
CAmount nPreviousSubsidy = nInitialSubsidy * 2; // for height == 0
|
|
BOOST_CHECK_EQUAL(nPreviousSubsidy, nInitialSubsidy * 2);
|
|
for (int nHalvings = 0; nHalvings < maxHalvings; nHalvings++) {
|
|
int nHeight = nHalvings * consensusParams.nSubsidyHalvingInterval;
|
|
CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams);
|
|
BOOST_CHECK(nSubsidy <= nInitialSubsidy);
|
|
BOOST_CHECK_EQUAL(nSubsidy, nPreviousSubsidy / 2);
|
|
nPreviousSubsidy = nSubsidy;
|
|
}
|
|
BOOST_CHECK_EQUAL(GetBlockSubsidy(maxHalvings * consensusParams.nSubsidyHalvingInterval, consensusParams), 0);
|
|
}
|
|
|
|
static void TestBlockSubsidyHalvings(int nSubsidyHalvingInterval)
|
|
{
|
|
Consensus::Params consensusParams;
|
|
consensusParams.nSubsidyHalvingInterval = nSubsidyHalvingInterval;
|
|
TestBlockSubsidyHalvings(consensusParams);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(block_subsidy_test)
|
|
{
|
|
const auto chainParams = CreateChainParams(*m_node.args, ChainType::MAIN);
|
|
TestBlockSubsidyHalvings(chainParams->GetConsensus()); // As in main
|
|
TestBlockSubsidyHalvings(150); // As in regtest
|
|
TestBlockSubsidyHalvings(1000); // Just another interval
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(subsidy_limit_test)
|
|
{
|
|
const auto chainParams = CreateChainParams(*m_node.args, ChainType::MAIN);
|
|
CAmount nSum = 0;
|
|
for (int nHeight = 0; nHeight < 14000000; nHeight += 1000) {
|
|
CAmount nSubsidy = GetBlockSubsidy(nHeight, chainParams->GetConsensus());
|
|
BOOST_CHECK(nSubsidy <= 50 * COIN);
|
|
nSum += nSubsidy * 1000;
|
|
BOOST_CHECK(MoneyRange(nSum));
|
|
}
|
|
BOOST_CHECK_EQUAL(nSum, CAmount{2099999997690000});
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(signet_parse_tests)
|
|
{
|
|
ArgsManager signet_argsman;
|
|
signet_argsman.ForceSetArg("-signetchallenge", "51"); // set challenge to OP_TRUE
|
|
const auto signet_params = CreateChainParams(signet_argsman, ChainType::SIGNET);
|
|
CBlock block;
|
|
BOOST_CHECK(signet_params->GetConsensus().signet_challenge == std::vector<uint8_t>{OP_TRUE});
|
|
CScript challenge{OP_TRUE};
|
|
|
|
// empty block is invalid
|
|
BOOST_CHECK(!SignetTxs::Create(block, challenge));
|
|
BOOST_CHECK(!CheckSignetBlockSolution(block, signet_params->GetConsensus()));
|
|
|
|
// no witness commitment
|
|
CMutableTransaction cb;
|
|
cb.vout.emplace_back(0, CScript{});
|
|
block.vtx.push_back(MakeTransactionRef(cb));
|
|
block.vtx.push_back(MakeTransactionRef(cb)); // Add dummy tx to exercise merkle root code
|
|
BOOST_CHECK(!SignetTxs::Create(block, challenge));
|
|
BOOST_CHECK(!CheckSignetBlockSolution(block, signet_params->GetConsensus()));
|
|
|
|
// no header is treated valid
|
|
std::vector<uint8_t> witness_commitment_section_141{0xaa, 0x21, 0xa9, 0xed};
|
|
for (int i = 0; i < 32; ++i) {
|
|
witness_commitment_section_141.push_back(0xff);
|
|
}
|
|
cb.vout.at(0).scriptPubKey = CScript{} << OP_RETURN << witness_commitment_section_141;
|
|
block.vtx.at(0) = MakeTransactionRef(cb);
|
|
BOOST_CHECK(SignetTxs::Create(block, challenge));
|
|
BOOST_CHECK(CheckSignetBlockSolution(block, signet_params->GetConsensus()));
|
|
|
|
// no data after header, valid
|
|
std::vector<uint8_t> witness_commitment_section_325{0xec, 0xc7, 0xda, 0xa2};
|
|
cb.vout.at(0).scriptPubKey = CScript{} << OP_RETURN << witness_commitment_section_141 << witness_commitment_section_325;
|
|
block.vtx.at(0) = MakeTransactionRef(cb);
|
|
BOOST_CHECK(SignetTxs::Create(block, challenge));
|
|
BOOST_CHECK(CheckSignetBlockSolution(block, signet_params->GetConsensus()));
|
|
|
|
// Premature end of data, invalid
|
|
witness_commitment_section_325.push_back(0x01);
|
|
witness_commitment_section_325.push_back(0x51);
|
|
cb.vout.at(0).scriptPubKey = CScript{} << OP_RETURN << witness_commitment_section_141 << witness_commitment_section_325;
|
|
block.vtx.at(0) = MakeTransactionRef(cb);
|
|
BOOST_CHECK(!SignetTxs::Create(block, challenge));
|
|
BOOST_CHECK(!CheckSignetBlockSolution(block, signet_params->GetConsensus()));
|
|
|
|
// has data, valid
|
|
witness_commitment_section_325.push_back(0x00);
|
|
cb.vout.at(0).scriptPubKey = CScript{} << OP_RETURN << witness_commitment_section_141 << witness_commitment_section_325;
|
|
block.vtx.at(0) = MakeTransactionRef(cb);
|
|
BOOST_CHECK(SignetTxs::Create(block, challenge));
|
|
BOOST_CHECK(CheckSignetBlockSolution(block, signet_params->GetConsensus()));
|
|
|
|
// Extraneous data, invalid
|
|
witness_commitment_section_325.push_back(0x00);
|
|
cb.vout.at(0).scriptPubKey = CScript{} << OP_RETURN << witness_commitment_section_141 << witness_commitment_section_325;
|
|
block.vtx.at(0) = MakeTransactionRef(cb);
|
|
BOOST_CHECK(!SignetTxs::Create(block, challenge));
|
|
BOOST_CHECK(!CheckSignetBlockSolution(block, signet_params->GetConsensus()));
|
|
}
|
|
|
|
//! Test retrieval of valid assumeutxo values.
|
|
BOOST_AUTO_TEST_CASE(test_assumeutxo)
|
|
{
|
|
const auto params = CreateChainParams(*m_node.args, ChainType::REGTEST);
|
|
|
|
// These heights don't have assumeutxo configurations associated, per the contents
|
|
// of kernel/chainparams.cpp.
|
|
std::vector<int> bad_heights{0, 100, 111, 115, 209, 211};
|
|
|
|
for (auto empty : bad_heights) {
|
|
const auto out = params->AssumeutxoForHeight(empty);
|
|
BOOST_CHECK(!out);
|
|
}
|
|
|
|
const auto out110 = *params->AssumeutxoForHeight(110);
|
|
BOOST_CHECK_EQUAL(out110.hash_serialized.ToString(), "6657b736d4fe4db0cbc796789e812d5dba7f5c143764b1b6905612f1830609d1");
|
|
BOOST_CHECK_EQUAL(out110.nChainTx, 111U);
|
|
|
|
const auto out110_2 = *params->AssumeutxoForBlockhash(uint256S("0x696e92821f65549c7ee134edceeeeaaa4105647a3c4fd9f298c0aec0ab50425c"));
|
|
BOOST_CHECK_EQUAL(out110_2.hash_serialized.ToString(), "6657b736d4fe4db0cbc796789e812d5dba7f5c143764b1b6905612f1830609d1");
|
|
BOOST_CHECK_EQUAL(out110_2.nChainTx, 111U);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|