Skip to content

Commit

Permalink
Merge #6511: feat: start v19 from block 1 - fire up test chains by fi…
Browse files Browse the repository at this point in the history
…rst block - 8/n

88888e2 tests: speed up twice unit tests evo_dip3_* by generating less blocks for v19 (Konstantin Akimov)
a6c2391 tests: speed up feature_llmq_evo.py (Konstantin Akimov)
4d212bc tests: actually test legacy and non-legacy masternodes together in feature_dip3_v19.py (Konstantin Akimov)
b03d886 feat: fix mining early quorums on early blocks with no troubles! (Konstantin Akimov)
1845730 feat: activate v19 from block 1 (Konstantin Akimov)
9a23427 fix: potentiall failure of MigrateDBIfNeeded if v19 is activated before DIP3 (Konstantin Akimov)
506f1f5 feat: remove code forbidding register Evo nodes before v19 activation (Konstantin Akimov)

Pull request description:

  ## Issue being fixed or feature implemented
  This PR is 8th in the achieving ultimate goal to activate old forks from block 1.
  It helps to run unit and functional tests faster; it helps for platform's dev-environment to start faster.

  ## What was done?
  Activate V19 (basic BLS, evo nodes) from block 1 and related fixes. Depends on #6508 which contains critical fixes and changes to make this PR work at all.

  Prior work for other forks: #6325 and other PRs.

  ## How Has This Been Tested?
  Run unit & functional tests. See also multiple updates for functional tests and optimization.

  ## Breaking Changes
  N/A; affect only Regtest

  ## Checklist:
  - [x] I have performed a self-review of my own code
  - [ ] I have commented my code, particularly in hard-to-understand areas
  - [ ] I have added or updated relevant unit/integration/functional/e2e tests
  - [ ] I have made corresponding changes to the documentation
  - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_

ACKs for top commit:
  UdjinM6:
    utACK 88888e2
  PastaPastaPasta:
    utACK 88888e2

Tree-SHA512: 4ce4bab92d87483dd70a80a8785288327cbaa2b03cf2b8b9cf10cab47e86019477840e360d55fe50f2fdcabf902d57e32189318d279117fb2232c4dbfefe67d7
  • Loading branch information
PastaPastaPasta committed Jan 11, 2025
2 parents 3edc738 + 88888e2 commit 5fd6a3f
Show file tree
Hide file tree
Showing 23 changed files with 47 additions and 119 deletions.
4 changes: 3 additions & 1 deletion src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,7 @@ class CRegTestParams : public CChainParams {
consensus.DIP0020Height = 1; // Always active unless overridden
consensus.DIP0024Height = 1; // Always have dip0024 quorums unless overridden
consensus.DIP0024QuorumsHeight = 1; // Always have dip0024 quorums unless overridden
consensus.V19Height = 900;
consensus.V19Height = 1; // Always active unless overriden
consensus.V20Height = 900;
consensus.MN_RRHeight = 900;
consensus.MinBIP9WarningHeight = 0;
Expand Down Expand Up @@ -1031,6 +1031,8 @@ static void MaybeUpdateHeights(const ArgsManager& args, Consensus::Params& conse
consensus.DIP0008Height = int{height};
} else if (name == "dip0024") {
consensus.DIP0024QuorumsHeight = int{height};
} else if (name == "v19") {
consensus.V19Height = int{height};
} else if (name == "v20") {
consensus.V20Height = int{height};
} else if (name == "mn_rr") {
Expand Down
2 changes: 1 addition & 1 deletion src/chainparamsbase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ void SetupChainParamsBaseOptions(ArgsManager& argsman)
argsman.AddArg("-budgetparams=<masternode>:<budget>:<superblock>", "Override masternode, budget and superblock start heights (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-devnet=<name>", "Use devnet chain with provided name", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-dip3params=<activation>:<enforcement>", "Override DIP3 activation and enforcement heights (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-testactivationheight=name@height.", "Set the activation height of 'name' (bip147, bip34, dersig, cltv, csv, brr, dip0001, dip0008, dip0024, v20, mn_rr). (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-testactivationheight=name@height.", "Set the activation height of 'name' (bip147, bip34, dersig, cltv, csv, brr, dip0001, dip0008, dip0024, v19, v20, mn_rr). (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-highsubsidyblocks=<n>", "The number of blocks with a higher than normal subsidy to mine at the start of a chain. Block after that height will have fixed subsidy base. (default: 0, devnet-only)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-highsubsidyfactor=<n>", "The factor to multiply the normal block subsidy by while in the highsubsidyblocks window of a chain (default: 1, devnet-only)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
argsman.AddArg("-llmqchainlocks=<quorum name>", "Override the default LLMQ type used for ChainLocks. Allows using ChainLocks with smaller LLMQs. (default: llmq_devnet, devnet-only)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
Expand Down
35 changes: 14 additions & 21 deletions src/evo/deterministicmns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ CDeterministicMNCPtr CDeterministicMNList::GetMNPayee(gsl::not_null<const CBlock
return nullptr;
}

// The flag is-v19-activate is used for optimization; we don't need to go over all masternodes every pre-v19 block
const bool isv19Active{DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_V19)};
const bool isMNRewardReallocation{DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_MN_RR)};
// EvoNodes are rewarded 4 blocks in a row until MNRewardReallocation (Platform release)
Expand Down Expand Up @@ -737,7 +738,6 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, gsl::no

newList.DecreaseScores();

const bool isV19Active{DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_V19)};
const bool isMNRewardReallocation{DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_MN_RR)};

// we skip the coinbase
Expand All @@ -756,10 +756,6 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, gsl::no
}
auto& proTx = *opt_proTx;

if (proTx.nType == MnType::Evo && !isV19Active) {
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-payload");
}

auto dmn = std::make_shared<CDeterministicMN>(newList.GetTotalRegisteredCount(), proTx.nType);
dmn->proTxHash = tx.GetHash();

Expand Down Expand Up @@ -819,10 +815,6 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, gsl::no
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-payload");
}

if (opt_proTx->nType == MnType::Evo && !DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_V19)) {
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-payload");
}

if (newList.HasUniqueProperty(opt_proTx->addr) && newList.GetUniquePropertyMN(opt_proTx->addr)->proTxHash != opt_proTx->proTxHash) {
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-dup-addr");
}
Expand Down Expand Up @@ -1236,12 +1228,6 @@ bool CDeterministicMNManager::MigrateDBIfNeeded()
return true;
}

if (DeploymentActiveAt(*m_chainstate.m_chain.Tip(), consensusParams, Consensus::DEPLOYMENT_V19)) {
// too late
LogPrintf("CDeterministicMNManager::%s -- migration is not possible\n", __func__);
return false;
}

// Removing the old EVODB_BEST_BLOCK value early results in older version to crash immediately, even if the upgrade
// process is cancelled in-between. But if the new version sees that the old EVODB_BEST_BLOCK is already removed,
// then we must assume that the upgrade process was already running before but was interrupted.
Expand All @@ -1264,6 +1250,13 @@ bool CDeterministicMNManager::MigrateDBIfNeeded()
return true;
}

if (DeploymentActiveAt(*m_chainstate.m_chain.Tip(), consensusParams, Consensus::DEPLOYMENT_V19)) {
// too late
LogPrintf("CDeterministicMNManager::%s -- migration is not possible\n", __func__);
return false;
}


CDBBatch batch(m_evoDb.GetRawDB());

for (const auto nHeight : irange::range(Params().GetConsensus().DIP0003Height, m_chainstate.m_chain.Height() + 1)) {
Expand Down Expand Up @@ -1351,12 +1344,6 @@ bool CDeterministicMNManager::MigrateDBIfNeeded2()
return true;
}

if (DeploymentActiveAt(*m_chainstate.m_chain.Tip(), consensusParams, Consensus::DEPLOYMENT_V19)) {
// too late
LogPrintf("CDeterministicMNManager::%s -- migration is not possible\n", __func__);
return false;
}

// Removing the old EVODB_BEST_BLOCK value early results in older version to crash immediately, even if the upgrade
// process is cancelled in-between. But if the new version sees that the old EVODB_BEST_BLOCK is already removed,
// then we must assume that the upgrade process was already running before but was interrupted.
Expand All @@ -1379,6 +1366,12 @@ bool CDeterministicMNManager::MigrateDBIfNeeded2()
return true;
}

if (DeploymentActiveAt(*m_chainstate.m_chain.Tip(), consensusParams, Consensus::DEPLOYMENT_V19)) {
// too late
LogPrintf("CDeterministicMNManager::%s -- migration is not possible\n", __func__);
return false;
}

CDBBatch batch(m_evoDb.GetRawDB());

for (const auto nHeight : irange::range(Params().GetConsensus().DIP0003Height, m_chainstate.m_chain.Height() + 1)) {
Expand Down
12 changes: 2 additions & 10 deletions src/rpc/evo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -643,11 +643,6 @@ static UniValue protx_register_common_wrapper(const JSONRPCRequest& request,
EnsureWalletIsUnlocked(*pwallet);
}

const bool isV19active{DeploymentActiveAfter(WITH_LOCK(cs_main, return chainman.ActiveChain().Tip();), Params().GetConsensus(), Consensus::DEPLOYMENT_V19)};
if (isEvoRequested && !isV19active) {
throw JSONRPCError(RPC_INVALID_REQUEST, "EvoNodes aren't allowed yet");
}

size_t paramIdx = 0;

CMutableTransaction tx;
Expand Down Expand Up @@ -965,11 +960,6 @@ static UniValue protx_update_service_common_wrapper(const JSONRPCRequest& reques

EnsureWalletIsUnlocked(*wallet);

const bool isV19active{DeploymentActiveAfter(WITH_LOCK(cs_main, return chainman.ActiveChain().Tip();), Params().GetConsensus(), Consensus::DEPLOYMENT_V19)};
if (isEvoRequested && !isV19active) {
throw JSONRPCError(RPC_INVALID_REQUEST, "EvoNodes aren't allowed yet");
}

CProUpServTx ptx;
ptx.nType = mnType;
ptx.proTxHash = ParseHashV(request.params[0], "proTxHash");
Expand Down Expand Up @@ -1055,6 +1045,8 @@ static UniValue protx_update_service_common_wrapper(const JSONRPCRequest& reques

FundSpecialTx(*wallet, tx, ptx, feeSource);

const bool isV19active = DeploymentActiveAfter(WITH_LOCK(cs_main, return chainman.ActiveChain().Tip();),
Params().GetConsensus(), Consensus::DEPLOYMENT_V19);
SignSpecialTxPayloadByHash(tx, ptx, keyOperator, !isV19active);
SetTxPayload(tx, ptx);

Expand Down
2 changes: 1 addition & 1 deletion src/test/evo_deterministicmns_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -860,7 +860,7 @@ struct TestChainV19Setup : public TestChainV19BeforeActivationSetup {

// 5 blocks earlier
TestChainV19BeforeActivationSetup::TestChainV19BeforeActivationSetup() :
TestChainSetup(894)
TestChainSetup(494, {"-testactivationheight=v19@500"})
{
bool v19_active{DeploymentActiveAfter(m_node.chainman->ActiveChain().Tip(), Params().GetConsensus(),
Consensus::DEPLOYMENT_V19)};
Expand Down
4 changes: 2 additions & 2 deletions src/test/util/setup_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -382,9 +382,9 @@ TestChainSetup::TestChainSetup(int num_blocks, const std::vector<const char*>& e
/* TestChainDIP3BeforeActivationSetup */
{ 430, uint256S("0x0bcefaa33fec56cd84d05d0e76cd6a78badcc20f627d91903646de6a07930a14") },
/* TestChainBRRBeforeActivationSetup */
{ 497, uint256S("0x3c71d807d28b9b813434eb0679ec3d5bcf424c20088cf578f3757521c3e3eded") },
{ 497, uint256S("0x0857a9b5db51835b1c828f019f4c664b5fe6c28ac44a6d868436930f832d31e5") },
/* TestChainV19BeforeActivationSetup */
{ 894, uint256S("0x3f031e5cceade15bdfa559ddecb2ccb2b8d17083bdfd871a9d23b17d04b15292") },
{ 494, uint256S("0x44ee5c8a5e5cbd4437d63c54ddc1d40329be811b25c492fa901e11cdf408f905") },
}
};

Expand Down
7 changes: 5 additions & 2 deletions test/functional/feature_dip3_v19.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@ def getmnlistdiff(self, base_block_hash, block_hash):
class DIP3V19Test(DashTestFramework):
def set_test_params(self):
self.extra_args = [[
'-testactivationheight=v20@1200', # required otherwise mine_quorum("llmq_test [100]") fails
'-testactivationheight=v19@200',
]] * 6
self.set_dash_test_params(6, 5, evo_count=2, extra_args=self.extra_args)


def run_test(self):
# Connect all nodes to node1 so that we always have the whole network connected
# Otherwise only masternode connections will be established between nodes, which won't propagate TXs/blocks
Expand All @@ -66,7 +67,9 @@ def run_test(self):
mn_list_before = self.nodes[0].masternodelist()
pubkeyoperator_list_before = set([mn_list_before[e]["pubkeyoperator"] for e in mn_list_before])

self.activate_v19(expected_activation_height=900)
self.mine_quorum(llmq_type_name='llmq_test', llmq_type=100)

self.activate_by_name('v19', expected_activation_height=200)
self.log.info("Activated v19 at height:" + str(self.nodes[0].getblockcount()))

mn_list_after = self.nodes[0].masternodelist()
Expand Down
14 changes: 7 additions & 7 deletions test/functional/feature_dip4_coinbasemerkleroots.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,28 +115,28 @@ def run_test(self):

# Verify that the first quorum appears in MNLISTDIFF
expectedDeleted = []
expectedNew = [QuorumId(100, int(first_quorum, 16)), QuorumId(104, int(first_quorum, 16)), QuorumId(106, int(first_quorum, 16))]
expectedNew = [QuorumId(100, int(first_quorum, 16)), QuorumId(104, int(first_quorum, 16))]
quorumList = self.test_getmnlistdiff_quorums(null_hash, self.nodes[0].getbestblockhash(), {}, expectedDeleted, expectedNew)
baseBlockHash = self.nodes[0].getbestblockhash()

second_quorum = self.mine_quorum()

# Verify that the second quorum appears in MNLISTDIFF
expectedDeleted = []
expectedNew = [QuorumId(100, int(second_quorum, 16)), QuorumId(104, int(second_quorum, 16)), QuorumId(106, int(second_quorum, 16))]
expectedNew = [QuorumId(100, int(second_quorum, 16)), QuorumId(104, int(second_quorum, 16))]
quorums_before_third = self.test_getmnlistdiff_quorums(baseBlockHash, self.nodes[0].getbestblockhash(), quorumList, expectedDeleted, expectedNew)
block_before_third = self.nodes[0].getbestblockhash()

third_quorum = self.mine_quorum()

# Verify that the first quorum is deleted and the third quorum is added in MNLISTDIFF (the first got inactive)
expectedDeleted = [QuorumId(100, int(first_quorum, 16)), QuorumId(104, int(first_quorum, 16)), QuorumId(106, int(first_quorum, 16))]
expectedNew = [QuorumId(100, int(third_quorum, 16)), QuorumId(104, int(third_quorum, 16)), QuorumId(106, int(third_quorum, 16))]
expectedDeleted = [QuorumId(100, int(first_quorum, 16)), QuorumId(104, int(first_quorum, 16))]
expectedNew = [QuorumId(100, int(third_quorum, 16)), QuorumId(104, int(third_quorum, 16))]
self.test_getmnlistdiff_quorums(block_before_third, self.nodes[0].getbestblockhash(), quorums_before_third, expectedDeleted, expectedNew)

# Verify that the diff between genesis and best block is the current active set (second and third quorum)
expectedDeleted = []
expectedNew = [QuorumId(100, int(second_quorum, 16)), QuorumId(104, int(second_quorum, 16)), QuorumId(106, int(second_quorum, 16)), QuorumId(100, int(third_quorum, 16)), QuorumId(104, int(third_quorum, 16)), QuorumId(106, int(third_quorum, 16))]
expectedNew = [QuorumId(100, int(second_quorum, 16)), QuorumId(104, int(second_quorum, 16)), QuorumId(100, int(third_quorum, 16)), QuorumId(104, int(third_quorum, 16))]
self.test_getmnlistdiff_quorums(null_hash, self.nodes[0].getbestblockhash(), {}, expectedDeleted, expectedNew)

# Now verify that diffs are correct around the block that mined the third quorum.
Expand All @@ -153,8 +153,8 @@ def run_test(self):
self.test_getmnlistdiff_quorums(block_before_third, prev_block2, quorums_before_third, expectedDeleted, expectedNew)
self.test_getmnlistdiff_quorums(block_before_third, prev_block, quorums_before_third, expectedDeleted, expectedNew)
# The block in which the quorum was mined and the 2 after that should all give the same diff
expectedDeleted = [QuorumId(100, int(first_quorum, 16)), QuorumId(104, int(first_quorum, 16)), QuorumId(106, int(first_quorum, 16))]
expectedNew = [QuorumId(100, int(third_quorum, 16)), QuorumId(104, int(third_quorum, 16)), QuorumId(106, int(third_quorum, 16))]
expectedDeleted = [QuorumId(100, int(first_quorum, 16)), QuorumId(104, int(first_quorum, 16))]
expectedNew = [QuorumId(100, int(third_quorum, 16)), QuorumId(104, int(third_quorum, 16))]
quorums_with_third = self.test_getmnlistdiff_quorums(block_before_third, mined_in_block, quorums_before_third, expectedDeleted, expectedNew)
self.test_getmnlistdiff_quorums(block_before_third, next_block, quorums_before_third, expectedDeleted, expectedNew)
self.test_getmnlistdiff_quorums(block_before_third, next_block2, quorums_before_third, expectedDeleted, expectedNew)
Expand Down
6 changes: 3 additions & 3 deletions test/functional/feature_governance.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,13 @@ def run_test(self):
self.log.info("Check 1st superblock before v20")
self.bump_mocktime(3)
self.generate(self.nodes[0], 3, sync_fun=self.sync_blocks())
assert_equal(self.nodes[0].getblockcount(), 130)
assert_equal(self.nodes[0].getblockcount(), 137)
assert_equal(self.nodes[0].getblockchaininfo()["softforks"]["v20"]["active"], False)
self.check_superblockbudget(False)

self.log.info("Check 2nd superblock before v20")
self.bump_mocktime(10)
self.generate(self.nodes[0], 10, sync_fun=self.sync_blocks())
self.bump_mocktime(3)
self.generate(self.nodes[0], 3, sync_fun=self.sync_blocks())
assert_equal(self.nodes[0].getblockcount(), 140)
assert_equal(self.nodes[0].getblockchaininfo()["softforks"]["v20"]["active"], False)
self.check_superblockbudget(False)
Expand Down
2 changes: 0 additions & 2 deletions test/functional/feature_governance_cl.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@ def run_test(self):

self.nodes[0].sporkupdate("SPORK_17_QUORUM_DKG_ENABLED", 0)
self.wait_for_sporks_same()
self.activate_v19(expected_activation_height=900)
self.log.info("Activated v19 at height:" + str(self.nodes[0].getblockcount()))
self.mine_cycle_quorum()

self.sync_blocks()
Expand Down
2 changes: 0 additions & 2 deletions test/functional/feature_llmq_connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,6 @@ def run_test(self):
self.nodes[0].sporkupdate("SPORK_23_QUORUM_POSE", 4070908800)
self.wait_for_sporks_same()

self.activate_v19(expected_activation_height=900)
self.log.info("Activated v19 at height:" + str(self.nodes[0].getblockcount()))
self.mine_cycle_quorum()

# Since we IS quorums are mined only using dip24 (rotation) we need to enable rotation, and continue tests on llmq_test_dip0024 for connections.
Expand Down
Loading

0 comments on commit 5fd6a3f

Please sign in to comment.