mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 03:52:49 +01:00
test: replace feature_block_reward_reallocation.py with two corresponding unit tests (#4603)
* test: Add BRR and DAT unit tests * test: Drop feature_block_reward_reallocation.py * change copyright * remove trivially removable includes * use constexpr, remove empty statement * Don't use BOOST_ASSERT, fix bug? Not sure if this was a bug, as it does an assignment. If this isn't a bug please add a comment / explanation ``` BOOST_ASSERT(::ChainActive().Tip()->nVersion = 536870912); ``` * deduplicate all the things (also test all activation periods) * use try_emplace, and remove some tempararies * update threshold to be inline with dynamic * explicitly include map, vector, remove now unneeded base58.h * remove unused param, and replace raw loop with range loop * re: Don't use BOOST_ASSERT, fix bug? * Make TestChain<smth>Setup in dynamic_activation_thresholds_tests more general * Specify min level activation tests correctly Co-authored-by: Pasta <pasta@dashboost.org>
This commit is contained in:
parent
459bc3ee7e
commit
99cbd9d0d2
@ -120,6 +120,7 @@ BITCOIN_TESTS =\
|
||||
test/bech32_tests.cpp \
|
||||
test/bip32_tests.cpp \
|
||||
test/bip39_tests.cpp \
|
||||
test/block_reward_reallocation_tests.cpp \
|
||||
test/blockchain_tests.cpp \
|
||||
test/blockencodings_tests.cpp \
|
||||
test/blockfilter_tests.cpp \
|
||||
@ -139,6 +140,7 @@ BITCOIN_TESTS =\
|
||||
test/denialofservice_tests.cpp \
|
||||
test/dip0020opcodes_tests.cpp \
|
||||
test/descriptor_tests.cpp \
|
||||
test/dynamic_activation_thresholds_tests.cpp \
|
||||
test/evo_deterministicmns_tests.cpp \
|
||||
test/evo_simplifiedmns_tests.cpp \
|
||||
test/flatfile_tests.cpp \
|
||||
|
329
src/test/block_reward_reallocation_tests.cpp
Normal file
329
src/test/block_reward_reallocation_tests.cpp
Normal file
@ -0,0 +1,329 @@
|
||||
// Copyright (c) 2021 The Dash Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <test/setup_common.h>
|
||||
|
||||
#include <chainparams.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <keystore.h>
|
||||
#include <messagesigner.h>
|
||||
#include <miner.h>
|
||||
#include <netbase.h>
|
||||
#include <script/interpreter.h>
|
||||
#include <script/sign.h>
|
||||
#include <script/standard.h>
|
||||
#include <validation.h>
|
||||
|
||||
#include <evo/specialtx.h>
|
||||
#include <evo/providertx.h>
|
||||
#include <evo/deterministicmns.h>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
using SimpleUTXOMap = std::map<COutPoint, std::pair<int, CAmount>>;
|
||||
|
||||
const auto deployment_id = Consensus::DEPLOYMENT_REALLOC;
|
||||
const int window{500}, th_start{400}, th_end{300};
|
||||
|
||||
struct TestChainBRRBeforeActivationSetup : public TestChainSetup
|
||||
{
|
||||
TestChainBRRBeforeActivationSetup() : TestChainSetup(497)
|
||||
{
|
||||
// Force fast DIP3 activation
|
||||
gArgs.ForceSetArg("-dip3params", "30:50");
|
||||
SelectParams(CBaseChainParams::REGTEST);
|
||||
gArgs.ForceRemoveArg("-dip3params");
|
||||
}
|
||||
};
|
||||
|
||||
static SimpleUTXOMap BuildSimpleUtxoMap(const std::vector<CTransactionRef>& txs)
|
||||
{
|
||||
SimpleUTXOMap utxos;
|
||||
for (size_t i = 0; i < txs.size(); i++) {
|
||||
auto& tx = txs[i];
|
||||
for (size_t j = 0; j < tx->vout.size(); j++) {
|
||||
utxos.try_emplace(COutPoint(tx->GetHash(), j), std::make_pair((int)i + 1, tx->vout[j].nValue));
|
||||
}
|
||||
}
|
||||
return utxos;
|
||||
}
|
||||
|
||||
static std::vector<COutPoint> SelectUTXOs(SimpleUTXOMap& utoxs, CAmount amount, CAmount& changeRet)
|
||||
{
|
||||
changeRet = 0;
|
||||
|
||||
std::vector<COutPoint> selectedUtxos;
|
||||
CAmount selectedAmount = 0;
|
||||
while (!utoxs.empty()) {
|
||||
bool found = false;
|
||||
for (auto it = utoxs.begin(); it != utoxs.end(); ++it) {
|
||||
if (::ChainActive().Height() - it->second.first < 101) {
|
||||
continue;
|
||||
}
|
||||
|
||||
found = true;
|
||||
selectedAmount += it->second.second;
|
||||
selectedUtxos.emplace_back(it->first);
|
||||
utoxs.erase(it);
|
||||
break;
|
||||
}
|
||||
BOOST_ASSERT(found);
|
||||
if (selectedAmount >= amount) {
|
||||
changeRet = selectedAmount - amount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return selectedUtxos;
|
||||
}
|
||||
|
||||
static void FundTransaction(CMutableTransaction& tx, SimpleUTXOMap& utoxs, const CScript& scriptPayout, CAmount amount)
|
||||
{
|
||||
CAmount change;
|
||||
auto inputs = SelectUTXOs(utoxs, amount, change);
|
||||
for (const auto& input : inputs) {
|
||||
tx.vin.emplace_back(input);
|
||||
}
|
||||
tx.vout.emplace_back(amount, scriptPayout);
|
||||
if (change != 0) {
|
||||
tx.vout.emplace_back(change, scriptPayout);
|
||||
}
|
||||
}
|
||||
|
||||
static void SignTransaction(CMutableTransaction& tx, const CKey& coinbaseKey)
|
||||
{
|
||||
CBasicKeyStore tempKeystore;
|
||||
tempKeystore.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
|
||||
|
||||
for (size_t i = 0; i < tx.vin.size(); i++) {
|
||||
CTransactionRef txFrom;
|
||||
uint256 hashBlock;
|
||||
BOOST_ASSERT(GetTransaction(tx.vin[i].prevout.hash, txFrom, Params().GetConsensus(), hashBlock));
|
||||
BOOST_ASSERT(SignSignature(tempKeystore, *txFrom, tx, i, SIGHASH_ALL));
|
||||
}
|
||||
}
|
||||
|
||||
static CMutableTransaction CreateProRegTx(SimpleUTXOMap& utxos, int port, const CScript& scriptPayout, const CKey& coinbaseKey, CKey& ownerKeyRet, CBLSSecretKey& operatorKeyRet)
|
||||
{
|
||||
ownerKeyRet.MakeNewKey(true);
|
||||
operatorKeyRet.MakeNewKey();
|
||||
|
||||
CProRegTx proTx;
|
||||
proTx.collateralOutpoint.n = 0;
|
||||
proTx.addr = LookupNumeric("1.1.1.1", port);
|
||||
proTx.keyIDOwner = ownerKeyRet.GetPubKey().GetID();
|
||||
proTx.pubKeyOperator = operatorKeyRet.GetPublicKey();
|
||||
proTx.keyIDVoting = ownerKeyRet.GetPubKey().GetID();
|
||||
proTx.scriptPayout = scriptPayout;
|
||||
|
||||
CMutableTransaction tx;
|
||||
tx.nVersion = 3;
|
||||
tx.nType = TRANSACTION_PROVIDER_REGISTER;
|
||||
FundTransaction(tx, utxos, scriptPayout, 1000 * COIN);
|
||||
proTx.inputsHash = CalcTxInputsHash(CTransaction(tx));
|
||||
SetTxPayload(tx, proTx);
|
||||
SignTransaction(tx, coinbaseKey);
|
||||
|
||||
return tx;
|
||||
}
|
||||
|
||||
static CScript GenerateRandomAddress()
|
||||
{
|
||||
CKey key;
|
||||
key.MakeNewKey(false);
|
||||
return GetScriptForDestination(key.GetPubKey().GetID());
|
||||
}
|
||||
|
||||
static constexpr int threshold(int attempt)
|
||||
{
|
||||
// An implementation of VersionBitsConditionChecker::Threshold()
|
||||
int threshold_calc = th_start - attempt * attempt * window / 100 / 5;
|
||||
if (threshold_calc < th_end) {
|
||||
return th_end;
|
||||
}
|
||||
return threshold_calc;
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(block_reward_reallocation_tests)
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationSetup)
|
||||
{
|
||||
const auto& consensus_params = Params().GetConsensus();
|
||||
CScript coinbasePubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
|
||||
|
||||
auto signal = [&](int num_blocks, bool expected_lockin)
|
||||
{
|
||||
// Mine non-signalling blocks
|
||||
gArgs.ForceSetArg("-blockversion", "536870912");
|
||||
for (int i = 0; i < window - num_blocks; ++i) {
|
||||
CreateAndProcessBlock({}, coinbaseKey);
|
||||
}
|
||||
gArgs.ForceRemoveArg("-blockversion");
|
||||
if (num_blocks > 0) {
|
||||
// Mine signalling blocks
|
||||
for (int i = 0; i < num_blocks; ++i) {
|
||||
CreateAndProcessBlock({}, coinbaseKey);
|
||||
}
|
||||
}
|
||||
LOCK(cs_main);
|
||||
if (expected_lockin) {
|
||||
BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::LOCKED_IN);
|
||||
} else {
|
||||
BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::STARTED);
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_ASSERT(deterministicMNManager->IsDIP3Enforced(WITH_LOCK(cs_main, return ::ChainActive().Height())));
|
||||
|
||||
// Register one MN
|
||||
CKey ownerKey;
|
||||
CBLSSecretKey operatorKey;
|
||||
auto utxos = BuildSimpleUtxoMap(m_coinbase_txns);
|
||||
auto tx = CreateProRegTx(utxos, 1, GenerateRandomAddress(), coinbaseKey, ownerKey, operatorKey);
|
||||
|
||||
CreateAndProcessBlock({tx}, coinbaseKey);
|
||||
|
||||
{
|
||||
LOCK(cs_main);
|
||||
deterministicMNManager->UpdatedBlockTip(::ChainActive().Tip());
|
||||
|
||||
BOOST_ASSERT(deterministicMNManager->GetListAtChainTip().HasMN(tx.GetHash()));
|
||||
|
||||
BOOST_CHECK_EQUAL(::ChainActive().Height(), 498);
|
||||
BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::DEFINED);
|
||||
}
|
||||
|
||||
CreateAndProcessBlock({}, coinbaseKey);
|
||||
|
||||
{
|
||||
LOCK(cs_main);
|
||||
// Advance from DEFINED to STARTED at height = 499
|
||||
BOOST_CHECK_EQUAL(::ChainActive().Height(), 499);
|
||||
BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::STARTED);
|
||||
BOOST_CHECK_EQUAL(VersionBitsTipStatistics(consensus_params, deployment_id).threshold, threshold(0));
|
||||
// Next block should be signaling by default
|
||||
const auto pblocktemplate = BlockAssembler(Params()).CreateNewBlock(coinbasePubKey);
|
||||
BOOST_CHECK_EQUAL(::ChainActive().Tip()->nVersion, 536870912);
|
||||
BOOST_CHECK(pblocktemplate->block.nVersion != 536870912);
|
||||
}
|
||||
|
||||
signal(threshold(0) - 1, false); // 1 block short
|
||||
|
||||
{
|
||||
// Still STARTED but new threshold should be lower at height = 999
|
||||
LOCK(cs_main);
|
||||
BOOST_CHECK_EQUAL(::ChainActive().Height(), 999);
|
||||
BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::STARTED);
|
||||
BOOST_CHECK_EQUAL(VersionBitsTipStatistics(consensus_params, deployment_id).threshold, threshold(1));
|
||||
}
|
||||
|
||||
signal(threshold(1) - 1, false); // 1 block short again
|
||||
|
||||
{
|
||||
// Still STARTED but new threshold should be even lower at height = 1499
|
||||
LOCK(cs_main);
|
||||
BOOST_CHECK_EQUAL(::ChainActive().Height(), 1499);
|
||||
BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::STARTED);
|
||||
BOOST_CHECK_EQUAL(VersionBitsTipStatistics(consensus_params, deployment_id).threshold, threshold(2));
|
||||
}
|
||||
|
||||
signal(threshold(2), true); // just enough to lock in
|
||||
|
||||
{
|
||||
// Advanced to LOCKED_IN at height = 1999
|
||||
LOCK(cs_main);
|
||||
BOOST_CHECK_EQUAL(::ChainActive().Height(), 1999);
|
||||
BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::LOCKED_IN);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 499; ++i) {
|
||||
// Still LOCKED_IN at height = 2498
|
||||
CreateAndProcessBlock({}, coinbaseKey);
|
||||
LOCK(cs_main);
|
||||
BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::LOCKED_IN);
|
||||
}
|
||||
CreateAndProcessBlock({}, coinbaseKey);
|
||||
|
||||
{
|
||||
// Advance from LOCKED_IN to ACTIVE at height = 2499
|
||||
LOCK(cs_main);
|
||||
BOOST_CHECK_EQUAL(::ChainActive().Height(), 2499);
|
||||
BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::ACTIVE);
|
||||
BOOST_CHECK_EQUAL(VersionBitsTipStateSinceHeight(consensus_params, deployment_id), 2500);
|
||||
}
|
||||
|
||||
{
|
||||
// Reward split should stay ~50/50 before the first superblock after activation.
|
||||
// This applies even if reallocation was activated right at superblock height like it does here.
|
||||
// next block should be signaling by default
|
||||
LOCK(cs_main);
|
||||
auto masternode_payment = GetMasternodePayment(::ChainActive().Height(), GetBlockSubsidy(::ChainActive().Tip()->nBits, ::ChainActive().Height(), consensus_params), 2500);
|
||||
const auto pblocktemplate = BlockAssembler(Params()).CreateNewBlock(coinbasePubKey);
|
||||
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
CreateAndProcessBlock({}, coinbaseKey);
|
||||
}
|
||||
|
||||
{
|
||||
LOCK(cs_main);
|
||||
auto masternode_payment = GetMasternodePayment(::ChainActive().Height(), GetBlockSubsidy(::ChainActive().Tip()->nBits, ::ChainActive().Height(), consensus_params), 2500);
|
||||
const auto pblocktemplate = BlockAssembler(Params()).CreateNewBlock(coinbasePubKey);
|
||||
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx[0]->GetValueOut(), 13748571607);
|
||||
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment);
|
||||
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, 6874285801); // 0.4999999998
|
||||
}
|
||||
|
||||
// Reallocation should kick-in with the superblock mined at height = 2010,
|
||||
// there will be 19 adjustments, 3 superblocks long each
|
||||
for (int i = 0; i < 19; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 10; ++k) {
|
||||
CreateAndProcessBlock({}, coinbaseKey);
|
||||
}
|
||||
LOCK(cs_main);
|
||||
auto masternode_payment = GetMasternodePayment(::ChainActive().Height(), GetBlockSubsidy(::ChainActive().Tip()->nBits, ::ChainActive().Height(), consensus_params), 2500);
|
||||
const auto pblocktemplate = BlockAssembler(Params()).CreateNewBlock(coinbasePubKey);
|
||||
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Reward split should reach ~60/40 after reallocation is done
|
||||
LOCK(cs_main);
|
||||
auto masternode_payment = GetMasternodePayment(::ChainActive().Height(), GetBlockSubsidy(::ChainActive().Tip()->nBits, ::ChainActive().Height(), consensus_params), 2500);
|
||||
const auto pblocktemplate = BlockAssembler(Params()).CreateNewBlock(coinbasePubKey);
|
||||
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx[0]->GetValueOut(), 10221599170);
|
||||
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment);
|
||||
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, 6132959502); // 0.6
|
||||
}
|
||||
|
||||
// Reward split should stay ~60/40 after reallocation is done,
|
||||
// check 10 next superblocks
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
for (int k = 0; k < 10; ++k) {
|
||||
CreateAndProcessBlock({}, coinbaseKey);
|
||||
}
|
||||
LOCK(cs_main);
|
||||
auto masternode_payment = GetMasternodePayment(::ChainActive().Height(), GetBlockSubsidy(::ChainActive().Tip()->nBits, ::ChainActive().Height(), consensus_params), 2500);
|
||||
const auto pblocktemplate = BlockAssembler(Params()).CreateNewBlock(coinbasePubKey);
|
||||
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment);
|
||||
}
|
||||
|
||||
{
|
||||
// Reward split should reach ~60/40 after reallocation is done
|
||||
LOCK(cs_main);
|
||||
auto masternode_payment = GetMasternodePayment(::ChainActive().Height(), GetBlockSubsidy(::ChainActive().Tip()->nBits, ::ChainActive().Height(), consensus_params), 2500);
|
||||
const auto pblocktemplate = BlockAssembler(Params()).CreateNewBlock(coinbasePubKey);
|
||||
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx[0]->GetValueOut(), 9491484944);
|
||||
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment);
|
||||
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, 5694890966); // 0.6
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
135
src/test/dynamic_activation_thresholds_tests.cpp
Normal file
135
src/test/dynamic_activation_thresholds_tests.cpp
Normal file
@ -0,0 +1,135 @@
|
||||
// Copyright (c) 2021 The Dash Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <test/setup_common.h>
|
||||
|
||||
#include <chainparams.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <miner.h>
|
||||
#include <script/interpreter.h>
|
||||
#include <validation.h>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
const auto deployment_id = Consensus::DEPLOYMENT_DIP0020;
|
||||
constexpr int window{100}, th_start{80}, th_end{60};
|
||||
|
||||
static constexpr int threshold(int attempt)
|
||||
{
|
||||
// An implementation of VersionBitsConditionChecker::Threshold()
|
||||
int threshold_calc = th_start - attempt * attempt * window / 100 / 5;
|
||||
if (threshold_calc < th_end) {
|
||||
return th_end;
|
||||
}
|
||||
return threshold_calc;
|
||||
}
|
||||
|
||||
struct TestChainDATSetup : public TestChainSetup
|
||||
{
|
||||
TestChainDATSetup() : TestChainSetup(window - 2) {}
|
||||
|
||||
void signal(int num_blocks, bool expected_lockin)
|
||||
{
|
||||
const auto& consensus_params = Params().GetConsensus();
|
||||
// Mine non-signalling blocks
|
||||
gArgs.ForceSetArg("-blockversion", "536870912");
|
||||
for (int i = 0; i < window - num_blocks; ++i) {
|
||||
CreateAndProcessBlock({}, coinbaseKey);
|
||||
}
|
||||
gArgs.ForceRemoveArg("-blockversion");
|
||||
if (num_blocks > 0) {
|
||||
// Mine signalling blocks
|
||||
for (int i = 0; i < num_blocks; ++i) {
|
||||
CreateAndProcessBlock({}, coinbaseKey);
|
||||
}
|
||||
}
|
||||
LOCK(cs_main);
|
||||
if (expected_lockin) {
|
||||
BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::LOCKED_IN);
|
||||
} else {
|
||||
BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::STARTED);
|
||||
}
|
||||
}
|
||||
|
||||
void test(int activation_index, bool check_activation_at_min)
|
||||
{
|
||||
const auto& consensus_params = Params().GetConsensus();
|
||||
CScript coinbasePubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
|
||||
|
||||
{
|
||||
LOCK(cs_main);
|
||||
BOOST_CHECK_EQUAL(::ChainActive().Height(), window - 2);
|
||||
BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::DEFINED);
|
||||
}
|
||||
|
||||
CreateAndProcessBlock({}, coinbaseKey);
|
||||
|
||||
{
|
||||
LOCK(cs_main);
|
||||
// Advance from DEFINED to STARTED at height = window - 1
|
||||
BOOST_CHECK_EQUAL(::ChainActive().Height(), window - 1);
|
||||
BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::STARTED);
|
||||
BOOST_CHECK_EQUAL(VersionBitsTipStatistics(consensus_params, deployment_id).threshold, threshold(0));
|
||||
// Next block should be signaling by default
|
||||
const auto pblocktemplate = BlockAssembler(Params()).CreateNewBlock(coinbasePubKey);
|
||||
BOOST_CHECK_EQUAL(::ChainActive().Tip()->nVersion, 536870912);
|
||||
BOOST_CHECK(pblocktemplate->block.nVersion != 536870912);
|
||||
}
|
||||
|
||||
// Reach activation_index level
|
||||
for (int i = 0; i < activation_index; ++i) {
|
||||
signal(threshold(i) - 1, false); // 1 block short
|
||||
|
||||
{
|
||||
// Still STARTED but with a (potentially) new threshold
|
||||
LOCK(cs_main);
|
||||
BOOST_CHECK_EQUAL(::ChainActive().Height(), window * (i + 2) - 1);
|
||||
BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::STARTED);
|
||||
const auto vbts = VersionBitsTipStatistics(consensus_params, deployment_id);
|
||||
BOOST_CHECK_EQUAL(vbts.threshold, threshold(i + 1));
|
||||
BOOST_CHECK(vbts.threshold <= th_start);
|
||||
BOOST_CHECK(vbts.threshold >= th_end);
|
||||
}
|
||||
}
|
||||
if (LOCK(cs_main); check_activation_at_min) {
|
||||
BOOST_CHECK_EQUAL(VersionBitsTipStatistics(consensus_params, deployment_id).threshold, th_end);
|
||||
} else {
|
||||
BOOST_CHECK(VersionBitsTipStatistics(consensus_params, deployment_id).threshold > th_end);
|
||||
}
|
||||
|
||||
// activate
|
||||
signal(threshold(activation_index), true);
|
||||
for (int i = 0; i < window; ++i) {
|
||||
CreateAndProcessBlock({}, coinbaseKey);
|
||||
}
|
||||
{
|
||||
LOCK(cs_main);
|
||||
BOOST_CHECK_EQUAL(VersionBitsTipState(consensus_params, deployment_id), ThresholdState::ACTIVE);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(dynamic_activation_thresholds_tests)
|
||||
|
||||
#define TEST(INDEX, activate_at_min_level) BOOST_FIXTURE_TEST_CASE(activate_at_##INDEX##_level, TestChainDATSetup) \
|
||||
{ \
|
||||
test(INDEX, activate_at_min_level); \
|
||||
}
|
||||
|
||||
TEST(1, false)
|
||||
TEST(2, false)
|
||||
TEST(3, false)
|
||||
TEST(4, false)
|
||||
TEST(5, false)
|
||||
TEST(6, false)
|
||||
TEST(7, false)
|
||||
TEST(8, false)
|
||||
TEST(9, false)
|
||||
TEST(10, true)
|
||||
TEST(11, true)
|
||||
TEST(12, true)
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
@ -1,200 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2015-2020 The Dash Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
from test_framework.blocktools import create_block, create_coinbase, get_masternode_payment
|
||||
from test_framework.mininode import P2PDataStore
|
||||
from test_framework.messages import CTxOut, FromHex, CCbTx, CTransaction, ToHex
|
||||
from test_framework.script import CScript
|
||||
from test_framework.test_framework import DashTestFramework
|
||||
from test_framework.util import assert_equal, get_bip9_status, hex_str_to_bytes
|
||||
|
||||
'''
|
||||
feature_block_reward_reallocation.py
|
||||
|
||||
Checks block reward reallocation correctness
|
||||
|
||||
'''
|
||||
|
||||
|
||||
class BlockRewardReallocationTest(DashTestFramework):
|
||||
def set_test_params(self):
|
||||
self.set_dash_test_params(2, 1, fast_dip3_enforcement=True)
|
||||
self.set_dash_dip8_activation(450)
|
||||
|
||||
# 536870912 == 0x20000000, i.e. not signalling for anything
|
||||
def create_test_block(self, version=536870912):
|
||||
self.bump_mocktime(5)
|
||||
bt = self.nodes[0].getblocktemplate()
|
||||
tip = int(bt['previousblockhash'], 16)
|
||||
nextheight = bt['height']
|
||||
|
||||
coinbase = create_coinbase(nextheight)
|
||||
coinbase.nVersion = 3
|
||||
coinbase.nType = 5 # CbTx
|
||||
coinbase.vout[0].nValue = bt['coinbasevalue']
|
||||
for mn in bt['masternode']:
|
||||
coinbase.vout.append(CTxOut(mn['amount'], CScript(hex_str_to_bytes(mn['script']))))
|
||||
coinbase.vout[0].nValue -= mn['amount']
|
||||
cbtx = FromHex(CCbTx(), bt['coinbase_payload'])
|
||||
coinbase.vExtraPayload = cbtx.serialize()
|
||||
coinbase.rehash()
|
||||
coinbase.calc_sha256()
|
||||
|
||||
block = create_block(tip, coinbase, self.mocktime)
|
||||
block.nVersion = version
|
||||
# Add quorum commitments from template
|
||||
for tx in bt['transactions']:
|
||||
tx2 = FromHex(CTransaction(), tx['data'])
|
||||
if tx2.nType == 6:
|
||||
block.vtx.append(tx2)
|
||||
block.hashMerkleRoot = block.calc_merkle_root()
|
||||
block.rehash()
|
||||
block.solve()
|
||||
return block
|
||||
|
||||
def signal(self, num_blocks, expected_lockin):
|
||||
self.log.info("Signal with %d/500 blocks" % (num_blocks))
|
||||
# create and send non-signalling blocks
|
||||
for i in range(500 - num_blocks):
|
||||
test_block = self.create_test_block()
|
||||
self.nodes[0].submitblock(ToHex(test_block))
|
||||
# generate at most 10 signaling blocks at a time
|
||||
if num_blocks > 0:
|
||||
for i in range((num_blocks - 1) // 10):
|
||||
self.bump_mocktime(10)
|
||||
self.nodes[0].generate(10)
|
||||
self.nodes[0].generate((num_blocks - 1) % 10)
|
||||
assert_equal(get_bip9_status(self.nodes[0], 'realloc')['status'], 'started')
|
||||
self.nodes[0].generate(1)
|
||||
if expected_lockin:
|
||||
assert_equal(get_bip9_status(self.nodes[0], 'realloc')['status'], 'locked_in')
|
||||
else:
|
||||
assert_equal(get_bip9_status(self.nodes[0], 'realloc')['status'], 'started')
|
||||
|
||||
def threshold(self, attempt):
|
||||
threshold_calc = 400 - attempt * attempt
|
||||
if threshold_calc < 300:
|
||||
return 300
|
||||
return threshold_calc
|
||||
|
||||
def run_test(self):
|
||||
self.log.info("Wait for DIP3 to activate")
|
||||
while get_bip9_status(self.nodes[0], 'dip0003')['status'] != 'active':
|
||||
self.bump_mocktime(10)
|
||||
self.nodes[0].generate(10)
|
||||
|
||||
self.nodes[0].add_p2p_connection(P2PDataStore())
|
||||
|
||||
self.log.info("Mine all but one remaining block in the window")
|
||||
bi = self.nodes[0].getblockchaininfo()
|
||||
for i in range(498 - bi['blocks']):
|
||||
self.bump_mocktime(1)
|
||||
self.nodes[0].generate(1)
|
||||
|
||||
self.log.info("Initial state is DEFINED")
|
||||
bi = self.nodes[0].getblockchaininfo()
|
||||
assert_equal(bi['blocks'], 498)
|
||||
assert_equal(bi['bip9_softforks']['realloc']['status'], 'defined')
|
||||
|
||||
self.log.info("Advance from DEFINED to STARTED at height = 499")
|
||||
self.nodes[0].generate(1)
|
||||
bi = self.nodes[0].getblockchaininfo()
|
||||
assert_equal(bi['blocks'], 499)
|
||||
assert_equal(bi['bip9_softforks']['realloc']['status'], 'started')
|
||||
assert_equal(bi['bip9_softforks']['realloc']['statistics']['threshold'], self.threshold(0))
|
||||
|
||||
self.signal(399, False) # 1 block short
|
||||
|
||||
self.log.info("Still STARTED but new threshold should be lower at height = 999")
|
||||
bi = self.nodes[0].getblockchaininfo()
|
||||
assert_equal(bi['blocks'], 999)
|
||||
assert_equal(bi['bip9_softforks']['realloc']['statistics']['threshold'], self.threshold(1))
|
||||
|
||||
self.signal(398, False) # 1 block short again
|
||||
|
||||
self.log.info("Still STARTED but new threshold should be even lower at height = 1499")
|
||||
bi = self.nodes[0].getblockchaininfo()
|
||||
assert_equal(bi['blocks'], 1499)
|
||||
assert_equal(bi['bip9_softforks']['realloc']['statistics']['threshold'], self.threshold(2))
|
||||
pre_locked_in_blockhash = bi['bestblockhash']
|
||||
|
||||
self.signal(396, True) # just enough to lock in
|
||||
self.log.info("Advanced to LOCKED_IN at height = 1999")
|
||||
|
||||
for i in range(49):
|
||||
self.bump_mocktime(10)
|
||||
self.nodes[0].generate(10)
|
||||
self.nodes[0].generate(9)
|
||||
|
||||
self.log.info("Still LOCKED_IN at height = 2498")
|
||||
bi = self.nodes[0].getblockchaininfo()
|
||||
assert_equal(bi['blocks'], 2498)
|
||||
assert_equal(bi['bip9_softforks']['realloc']['status'], 'locked_in')
|
||||
|
||||
self.log.info("Advance from LOCKED_IN to ACTIVE at height = 2499")
|
||||
self.nodes[0].generate(1) # activation
|
||||
bi = self.nodes[0].getblockchaininfo()
|
||||
assert_equal(bi['blocks'], 2499)
|
||||
assert_equal(bi['bip9_softforks']['realloc']['status'], 'active')
|
||||
assert_equal(bi['bip9_softforks']['realloc']['since'], 2500)
|
||||
|
||||
self.log.info("Reward split should stay ~50/50 before the first superblock after activation")
|
||||
# This applies even if reallocation was activated right at superblock height like it does here
|
||||
bt = self.nodes[0].getblocktemplate()
|
||||
assert_equal(bt['height'], 2500)
|
||||
assert_equal(bt['masternode'][0]['amount'], get_masternode_payment(bt['height'], bt['coinbasevalue'], 2500))
|
||||
self.nodes[0].generate(9)
|
||||
bt = self.nodes[0].getblocktemplate()
|
||||
assert_equal(bt['masternode'][0]['amount'], get_masternode_payment(bt['height'], bt['coinbasevalue'], 2500))
|
||||
assert_equal(bt['coinbasevalue'], 13748571607)
|
||||
assert_equal(bt['masternode'][0]['amount'], 6874285801) # 0.4999999998
|
||||
|
||||
self.log.info("Reallocation should kick-in with the superblock mined at height = 2010")
|
||||
for _ in range(19): # there will be 19 adjustments, 3 superblocks long each
|
||||
for i in range(3):
|
||||
self.bump_mocktime(10)
|
||||
self.nodes[0].generate(10)
|
||||
bt = self.nodes[0].getblocktemplate()
|
||||
assert_equal(bt['masternode'][0]['amount'], get_masternode_payment(bt['height'], bt['coinbasevalue'], 2500))
|
||||
|
||||
self.log.info("Reward split should reach ~60/40 after reallocation is done")
|
||||
assert_equal(bt['coinbasevalue'], 10221599170)
|
||||
assert_equal(bt['masternode'][0]['amount'], 6132959502) # 0.6
|
||||
|
||||
self.log.info("Reward split should stay ~60/40 after reallocation is done")
|
||||
for _ in range(10): # check 10 next superblocks
|
||||
self.bump_mocktime(10)
|
||||
self.nodes[0].generate(10)
|
||||
bt = self.nodes[0].getblocktemplate()
|
||||
assert_equal(bt['masternode'][0]['amount'], get_masternode_payment(bt['height'], bt['coinbasevalue'], 2500))
|
||||
assert_equal(bt['coinbasevalue'], 9491484944)
|
||||
assert_equal(bt['masternode'][0]['amount'], 5694890966) # 0.6
|
||||
|
||||
# make sure all nodes are still synced
|
||||
self.sync_all()
|
||||
|
||||
self.log.info("Rollback the chain back to the STARTED state")
|
||||
self.mocktime = self.nodes[0].getblock(pre_locked_in_blockhash, 1)['time']
|
||||
for node in self.nodes:
|
||||
node.invalidateblock(pre_locked_in_blockhash)
|
||||
# create and send non-signalling block
|
||||
test_block = self.create_test_block()
|
||||
self.nodes[0].submitblock(ToHex(test_block))
|
||||
bi = self.nodes[0].getblockchaininfo()
|
||||
assert_equal(bi['blocks'], 1499)
|
||||
assert_equal(bi['bip9_softforks']['realloc']['status'], 'started')
|
||||
assert_equal(bi['bip9_softforks']['realloc']['statistics']['threshold'], self.threshold(2))
|
||||
|
||||
self.log.info("Check thresholds reach min level and stay there")
|
||||
for i in range(8): # 7 to reach min level and 1 more to check it doesn't go lower than that
|
||||
self.signal(0, False) # no need to signal
|
||||
bi = self.nodes[0].getblockchaininfo()
|
||||
assert_equal(bi['blocks'], 1999 + i * 500)
|
||||
assert_equal(bi['bip9_softforks']['realloc']['status'], 'started')
|
||||
assert_equal(bi['bip9_softforks']['realloc']['statistics']['threshold'], self.threshold(i + 3))
|
||||
assert_equal(bi['bip9_softforks']['realloc']['statistics']['threshold'], 300)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
BlockRewardReallocationTest().main()
|
@ -77,7 +77,6 @@ BASE_SCRIPTS = [
|
||||
# Scripts that are run by default.
|
||||
# Longest test should go first, to favor running tests in parallel
|
||||
'feature_dip3_deterministicmns.py', # NOTE: needs dash_hash to pass
|
||||
'feature_block_reward_reallocation.py',
|
||||
'feature_llmq_data_recovery.py',
|
||||
'feature_fee_estimation.py',
|
||||
'wallet_hd.py',
|
||||
|
Loading…
Reference in New Issue
Block a user