From c8cae3824e3f028f6e67d66081cedbe244f0ea42 Mon Sep 17 00:00:00 2001 From: Odysseas Gabrielides Date: Wed, 10 May 2023 15:01:42 +0300 Subject: [PATCH 01/10] calculate modifier using v20 cbtx clsig --- src/llmq/utils.cpp | 47 +++++++++++++++++++--- src/llmq/utils.h | 2 +- test/functional/feature_llmq_rotation.py | 50 +++++++++++++++++++++--- 3 files changed, 88 insertions(+), 11 deletions(-) diff --git a/src/llmq/utils.cpp b/src/llmq/utils.cpp index a94d4f4e93fb..79295a9539a9 100644 --- a/src/llmq/utils.cpp +++ b/src/llmq/utils.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -58,6 +59,42 @@ void PreComputeQuorumMembers(const CBlockIndex* pQuorumBaseBlockIndex, bool rese } } +uint256 GetHashModifier(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex) +{ + auto opt_params = GetLLMQParams(llmqType); + assert(opt_params.has_value()); + Consensus::LLMQParams llmq_params = opt_params.value(); + if (IsV20Active(pQuorumBaseBlockIndex)) { + // v20 is active: calculate modifier using the new way + if (llmq_params.useRotation) { + // For rotated quorums we don't go back 8 blocks behind as it is already done in functions {BuildNewQuorumQuarterMembers, GetQuorumQuarterMembersBySnapshot, BuildQuorumSnapshot and GetMNUsageBySnapshot} + auto cbcl = GetNonNullCoinbaseChainlock(pQuorumBaseBlockIndex); + if (cbcl.has_value()) { + // We have a non-null CL signature: calculate modifier using this CL signature + auto& [bestCLSignature, bestCLHeightDiff] = cbcl.value(); + return ::SerializeHash(std::make_tuple(llmqType, pQuorumBaseBlockIndex->nHeight, bestCLSignature)); + } + // No non-null CL signature found in coinbase: calculate modifier using the usual way + return ::SerializeHash(std::make_pair(llmqType, pQuorumBaseBlockIndex->GetBlockHash())); + } else { + // For non-rotated quorums, we perform tasks for 8 blocks behind requested one + const CBlockIndex* pWorkBlockIndex = pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8); + auto cbcl = GetNonNullCoinbaseChainlock(pWorkBlockIndex); + if (cbcl.has_value()) { + // We have a non-null CL signature: calculate modifier using this CL signature + auto& [bestCLSignature, bestCLHeightDiff] = cbcl.value(); + return ::SerializeHash(std::make_tuple(llmqType, pWorkBlockIndex->nHeight, bestCLSignature)); + } + // No non-null CL signature found in coinbase: calculate modifier using the usual way + return ::SerializeHash(std::make_pair(llmqType, pWorkBlockIndex->GetBlockHash())); + } + } + else { + // v20 isn't active yet: calculate modifier using the usual way + return ::SerializeHash(std::make_pair(llmqType, pQuorumBaseBlockIndex->GetBlockHash())); + } +} + std::vector GetAllQuorumMembers(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex, bool reset_cache) { static CCriticalSection cs_members; @@ -136,7 +173,7 @@ std::vector GetAllQuorumMembers(Consensus::LLMQType llmqTy std::vector ComputeQuorumMembers(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex) { auto allMns = deterministicMNManager->GetListForBlock(pQuorumBaseBlockIndex); - auto modifier = ::SerializeHash(std::make_pair(llmqType, pQuorumBaseBlockIndex->GetBlockHash())); + const auto modifier = GetHashModifier(llmqType, pQuorumBaseBlockIndex); bool HPMNOnly = (Params().GetConsensus().llmqTypePlatform == llmqType) && IsV19Active(pQuorumBaseBlockIndex); const auto& llmq_params_opt = GetLLMQParams(llmqType); assert(llmq_params_opt.has_value()); @@ -264,7 +301,7 @@ std::vector> BuildNewQuorumQuarterMembers(cons size_t quorumSize = static_cast(llmqParams.size); auto quarterSize{quorumSize / 4}; const CBlockIndex* pWorkBlockIndex = pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8); - auto modifier = ::SerializeHash(std::make_pair(llmqParams.type, pWorkBlockIndex->GetBlockHash())); + const auto modifier = GetHashModifier(llmqParams.type, pWorkBlockIndex); auto allMns = deterministicMNManager->GetListForBlock(pWorkBlockIndex); @@ -415,7 +452,7 @@ void BuildQuorumSnapshot(const Consensus::LLMQParams& llmqParams, const CDetermi { quorumSnapshot.activeQuorumMembers.resize(allMns.GetAllMNsCount()); const CBlockIndex* pWorkBlockIndex = pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8); - auto modifier = ::SerializeHash(std::make_pair(llmqParams.type, pWorkBlockIndex->GetBlockHash())); + const auto modifier = GetHashModifier(llmqParams.type, pWorkBlockIndex); auto sortedAllMns = allMns.CalculateQuorum(allMns.GetAllMNsCount(), modifier); LogPrint(BCLog::LLMQ, "BuildQuorumSnapshot h[%d] numMns[%d]\n", pQuorumBaseBlockIndex->nHeight, allMns.GetAllMNsCount()); @@ -448,7 +485,7 @@ std::vector> GetQuorumQuarterMembersBySnapshot std::vector sortedCombinedMns; { const CBlockIndex* pWorkBlockIndex = pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8); - const auto modifier = ::SerializeHash(std::make_pair(llmqParams.type, pWorkBlockIndex->GetBlockHash())); + const auto modifier = GetHashModifier(llmqParams.type, pWorkBlockIndex); const auto [MnsUsedAtH, MnsNotUsedAtH] = GetMNUsageBySnapshot(llmqParams.type, pQuorumBaseBlockIndex, snapshot, nHeight); // the list begins with all the unused MNs auto sortedMnsNotUsedAtH = MnsNotUsedAtH.CalculateQuorum(MnsNotUsedAtH.GetAllMNsCount(), modifier); @@ -540,7 +577,7 @@ std::pair GetMNUsageBySnapshot(Conse CDeterministicMNList nonUsedMNs; const CBlockIndex* pWorkBlockIndex = pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8); - auto modifier = ::SerializeHash(std::make_pair(llmqType, pWorkBlockIndex->GetBlockHash())); + const auto modifier = GetHashModifier(llmqType, pWorkBlockIndex); auto allMns = deterministicMNManager->GetListForBlock(pWorkBlockIndex); auto sortedAllMns = allMns.CalculateQuorum(allMns.GetAllMNsCount(), modifier); diff --git a/src/llmq/utils.h b/src/llmq/utils.h index 46ee667a4491..3f671c4edad5 100644 --- a/src/llmq/utils.h +++ b/src/llmq/utils.h @@ -58,7 +58,7 @@ namespace utils std::vector GetAllQuorumMembers(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex, bool reset_cache = false); void PreComputeQuorumMembers(const CBlockIndex* pQuorumBaseBlockIndex, bool reset_cache = false); - +uint256 GetHashModifier(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex); uint256 BuildCommitmentHash(Consensus::LLMQType llmqType, const uint256& blockHash, const std::vector& validMembers, const CBLSPublicKey& pubKey, const uint256& vvecHash); uint256 BuildSignHash(Consensus::LLMQType llmqType, const uint256& quorumHash, const uint256& id, const uint256& msgHash); diff --git a/test/functional/feature_llmq_rotation.py b/test/functional/feature_llmq_rotation.py index 3ddbf2c23896..933196208817 100755 --- a/test/functional/feature_llmq_rotation.py +++ b/test/functional/feature_llmq_rotation.py @@ -73,20 +73,54 @@ def run_test(self): self.nodes[0].sporkupdate("SPORK_17_QUORUM_DKG_ENABLED", 0) self.wait_for_sporks_same() - self.activate_dip0024(expected_activation_height=900) - self.log.info("Activated DIP0024 at height:" + str(self.nodes[0].getblockcount())) + b_h_0 = self.nodes[0].getbestblockhash() + + #Mine 2 quorums so that Chainlocks can be available: Need them to include CL in CbTx as soon as v20 activates + self.log.info("Mining 2 quorums") + h_0 = self.mine_quorum() + h_100_0 = QuorumId(100, int(h_0, 16)) + h_106_0 = QuorumId(106, int(h_0, 16)) + h_104_0 = QuorumId(104, int(h_0, 16)) + h_1 = self.mine_quorum() + h_100_1 = QuorumId(100, int(h_1, 16)) + h_106_1 = QuorumId(106, int(h_1, 16)) + h_104_1 = QuorumId(104, int(h_1, 16)) + + self.log.info("Mine single block, wait for chainlock") + self.nodes[0].generate(1) + self.wait_for_chainlocked_block_all_nodes(self.nodes[0].getbestblockhash()) + + b_h_1 = self.nodes[0].getbestblockhash() + + expectedDeleted = [] + expectedNew = [h_100_0, h_106_0, h_104_0, h_100_1, h_106_1, h_104_1] + quorumList = self.test_getmnlistdiff_quorums(b_h_0, b_h_1, {}, expectedDeleted, expectedNew) + + self.activate_v20(expected_activation_height=904) + self.log.info("Activated v20 at height:" + str(self.nodes[0].getblockcount())) + self.log.info("Wait for chainlock") + self.wait_for_chainlocked_block_all_nodes(self.nodes[0].getbestblockhash()) #At this point, we need to move forward 3 cycles (3 x 24 blocks) so the first 3 quarters can be created (without DKG sessions) #self.log.info("Start at H height:" + str(self.nodes[0].getblockcount())) self.move_to_next_cycle() self.log.info("Cycle H height:" + str(self.nodes[0].getblockcount())) + self.log.info("Wait for chainlock") + self.wait_for_chainlocked_block_all_nodes(self.nodes[0].getbestblockhash()) self.move_to_next_cycle() self.log.info("Cycle H+C height:" + str(self.nodes[0].getblockcount())) + self.log.info("Wait for chainlock") + self.wait_for_chainlocked_block_all_nodes(self.nodes[0].getbestblockhash()) self.move_to_next_cycle() self.log.info("Cycle H+2C height:" + str(self.nodes[0].getblockcount())) + self.log.info("Wait for chainlock") + self.wait_for_chainlocked_block_all_nodes(self.nodes[0].getbestblockhash()) b_0 = self.nodes[0].getbestblockhash() + self.log.info("Wait for chainlock") + self.wait_for_chainlocked_block_all_nodes(self.nodes[0].getbestblockhash()) + (quorum_info_0_0, quorum_info_0_1) = self.mine_cycle_quorum(llmq_type_name=llmq_type_name, llmq_type=llmq_type) assert(self.test_quorum_listextended(quorum_info_0_0, llmq_type_name)) assert(self.test_quorum_listextended(quorum_info_0_1, llmq_type_name)) @@ -103,9 +137,12 @@ def run_test(self): q_103_0_1 = QuorumId(103, int(quorum_info_0_1["quorumHash"], 16)) b_1 = self.nodes[0].getbestblockhash() - expectedDeleted = [] + expectedDeleted = [h_100_0, h_104_0] expectedNew = [q_100_0, q_102_0, q_104_0, q_103_0_0, q_103_0_1] - quorumList = self.test_getmnlistdiff_quorums(b_0, b_1, {}, expectedDeleted, expectedNew) + quorumList = self.test_getmnlistdiff_quorums(b_0, b_1, quorumList, expectedDeleted, expectedNew) + + self.log.info("Wait for chainlock") + self.wait_for_chainlocked_block_all_nodes(self.nodes[0].getbestblockhash()) (quorum_info_1_0, quorum_info_1_1) = self.mine_cycle_quorum(llmq_type_name=llmq_type_name, llmq_type=llmq_type) assert(self.test_quorum_listextended(quorum_info_1_0, llmq_type_name)) @@ -122,7 +159,7 @@ def run_test(self): q_103_1_1 = QuorumId(103, int(quorum_info_1_1["quorumHash"], 16)) b_2 = self.nodes[0].getbestblockhash() - expectedDeleted = [q_103_0_0, q_103_0_1] + expectedDeleted = [h_100_1, q_103_0_0, q_103_0_1] expectedNew = [q_100_1, q_102_1, q_103_1_0, q_103_1_1] quorumList = self.test_getmnlistdiff_quorums(b_1, b_2, quorumList, expectedDeleted, expectedNew) @@ -137,6 +174,9 @@ def run_test(self): assert_greater_than_or_equal(len(intersection(quorum_members_0_0, quorum_members_1_0)), 3) assert_greater_than_or_equal(len(intersection(quorum_members_0_1, quorum_members_1_1)), 3) + self.log.info("Wait for chainlock") + self.wait_for_chainlocked_block_all_nodes(self.nodes[0].getbestblockhash()) + self.log.info("Mine a quorum to invalidate") (quorum_info_3_0, quorum_info_3_1) = self.mine_cycle_quorum(llmq_type_name=llmq_type_name, llmq_type=llmq_type) From 6be1b6d37be33e467d09b916e09fdf0210aa3cab Mon Sep 17 00:00:00 2001 From: Odysseas Gabrielides Date: Wed, 10 May 2023 15:30:34 +0300 Subject: [PATCH 02/10] linter fixes --- src/llmq/utils.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/llmq/utils.cpp b/src/llmq/utils.cpp index 79295a9539a9..a932d94ef4ea 100644 --- a/src/llmq/utils.cpp +++ b/src/llmq/utils.cpp @@ -9,7 +9,6 @@ #include #include -#include #include #include #include @@ -27,6 +26,11 @@ static constexpr int TESTNET_LLMQ_25_67_ACTIVATION_HEIGHT = 847000; +/** + * Forward declarations + */ +std::optional> GetNonNullCoinbaseChainlock(const CBlockIndex* pindex); + namespace llmq { From 01c8a6cc5be2bb401f2980c055afdbe58c093958 Mon Sep 17 00:00:00 2001 From: Odysseas Gabrielides Date: Thu, 11 May 2023 12:42:41 +0300 Subject: [PATCH 03/10] adaptations --- test/functional/feature_llmq_rotation.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/functional/feature_llmq_rotation.py b/test/functional/feature_llmq_rotation.py index 933196208817..887f264996ae 100755 --- a/test/functional/feature_llmq_rotation.py +++ b/test/functional/feature_llmq_rotation.py @@ -96,8 +96,12 @@ def run_test(self): expectedNew = [h_100_0, h_106_0, h_104_0, h_100_1, h_106_1, h_104_1] quorumList = self.test_getmnlistdiff_quorums(b_h_0, b_h_1, {}, expectedDeleted, expectedNew) - self.activate_v20(expected_activation_height=904) + self.activate_v20(expected_activation_height=1440) self.log.info("Activated v20 at height:" + str(self.nodes[0].getblockcount())) + + # v20 is active for the next block, not for the tip + self.nodes[0].generate(1) + self.log.info("Wait for chainlock") self.wait_for_chainlocked_block_all_nodes(self.nodes[0].getbestblockhash()) From f6c8a4a1108f35fad748fdcc5f69e7db11aa0b2a Mon Sep 17 00:00:00 2001 From: Odysseas Gabrielides Date: Thu, 11 May 2023 14:45:49 +0300 Subject: [PATCH 04/10] fix --- src/evo/cbtx.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/evo/cbtx.cpp b/src/evo/cbtx.cpp index f93b20eaffda..014a89a33a09 100644 --- a/src/evo/cbtx.cpp +++ b/src/evo/cbtx.cpp @@ -443,8 +443,19 @@ std::optional GetCoinbaseTx(const CBlockIndex* pindex) } CBlock block; - if (!ReadBlockFromDisk(block, pindex, Params().GetConsensus())) { - return std::nullopt; + { + FlatFilePos blockPos; + { + blockPos = pindex->GetBlockPos(); + } + + if (!ReadBlockFromDisk(block, blockPos, Params().GetConsensus())) { + return std::nullopt; + } + + if (block.GetHash() != pindex->GetBlockHash()) { + return std::nullopt; + } } CTransactionRef cbTx = block.vtx[0]; From 02a98b52c80733dfbf9f0d86c88f51e0ddeafd4a Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Thu, 11 May 2023 22:08:42 +0300 Subject: [PATCH 05/10] partial revert --- src/evo/cbtx.cpp | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/evo/cbtx.cpp b/src/evo/cbtx.cpp index 014a89a33a09..f93b20eaffda 100644 --- a/src/evo/cbtx.cpp +++ b/src/evo/cbtx.cpp @@ -443,19 +443,8 @@ std::optional GetCoinbaseTx(const CBlockIndex* pindex) } CBlock block; - { - FlatFilePos blockPos; - { - blockPos = pindex->GetBlockPos(); - } - - if (!ReadBlockFromDisk(block, blockPos, Params().GetConsensus())) { - return std::nullopt; - } - - if (block.GetHash() != pindex->GetBlockHash()) { - return std::nullopt; - } + if (!ReadBlockFromDisk(block, pindex, Params().GetConsensus())) { + return std::nullopt; } CTransactionRef cbTx = block.vtx[0]; From d32452c1769e584c77499ff6dbe1ae1afebb574b Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Sat, 13 May 2023 22:26:26 +0300 Subject: [PATCH 06/10] refactor: should pass pQuorumBaseBlockIndex to GetHashModifier (not some other block indexes) --- src/llmq/utils.cpp | 59 ++++++++++++++++++---------------------------- 1 file changed, 23 insertions(+), 36 deletions(-) diff --git a/src/llmq/utils.cpp b/src/llmq/utils.cpp index a932d94ef4ea..33c736754ea6 100644 --- a/src/llmq/utils.cpp +++ b/src/llmq/utils.cpp @@ -65,38 +65,27 @@ void PreComputeQuorumMembers(const CBlockIndex* pQuorumBaseBlockIndex, bool rese uint256 GetHashModifier(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex) { - auto opt_params = GetLLMQParams(llmqType); - assert(opt_params.has_value()); - Consensus::LLMQParams llmq_params = opt_params.value(); - if (IsV20Active(pQuorumBaseBlockIndex)) { - // v20 is active: calculate modifier using the new way - if (llmq_params.useRotation) { - // For rotated quorums we don't go back 8 blocks behind as it is already done in functions {BuildNewQuorumQuarterMembers, GetQuorumQuarterMembersBySnapshot, BuildQuorumSnapshot and GetMNUsageBySnapshot} - auto cbcl = GetNonNullCoinbaseChainlock(pQuorumBaseBlockIndex); - if (cbcl.has_value()) { - // We have a non-null CL signature: calculate modifier using this CL signature - auto& [bestCLSignature, bestCLHeightDiff] = cbcl.value(); - return ::SerializeHash(std::make_tuple(llmqType, pQuorumBaseBlockIndex->nHeight, bestCLSignature)); - } - // No non-null CL signature found in coinbase: calculate modifier using the usual way - return ::SerializeHash(std::make_pair(llmqType, pQuorumBaseBlockIndex->GetBlockHash())); - } else { - // For non-rotated quorums, we perform tasks for 8 blocks behind requested one - const CBlockIndex* pWorkBlockIndex = pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8); - auto cbcl = GetNonNullCoinbaseChainlock(pWorkBlockIndex); - if (cbcl.has_value()) { - // We have a non-null CL signature: calculate modifier using this CL signature - auto& [bestCLSignature, bestCLHeightDiff] = cbcl.value(); - return ::SerializeHash(std::make_tuple(llmqType, pWorkBlockIndex->nHeight, bestCLSignature)); - } - // No non-null CL signature found in coinbase: calculate modifier using the usual way - return ::SerializeHash(std::make_pair(llmqType, pWorkBlockIndex->GetBlockHash())); + auto llmq_params_opt = GetLLMQParams(llmqType); + assert(llmq_params_opt.has_value()); + + const CBlockIndex* pWorkBlockIndex = llmq_params_opt->useRotation ? + pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8) : + pQuorumBaseBlockIndex; + + if (IsV20Active(pWorkBlockIndex)) { + // v20 is active: calculate modifier using the new way. + auto cbcl = GetNonNullCoinbaseChainlock(pWorkBlockIndex); + if (cbcl.has_value()) { + // We have a non-null CL signature: calculate modifier using this CL signature + auto& [bestCLSignature, bestCLHeightDiff] = cbcl.value(); + return ::SerializeHash(std::make_tuple(llmqType, pWorkBlockIndex->nHeight, bestCLSignature)); } + // No non-null CL signature found in coinbase: calculate modifier using block hash only + return ::SerializeHash(std::make_pair(llmqType, pWorkBlockIndex->GetBlockHash())); } - else { - // v20 isn't active yet: calculate modifier using the usual way - return ::SerializeHash(std::make_pair(llmqType, pQuorumBaseBlockIndex->GetBlockHash())); - } + + // v20 isn't active yet: calculate modifier using the usual way + return ::SerializeHash(std::make_pair(llmqType, pWorkBlockIndex->GetBlockHash())); } std::vector GetAllQuorumMembers(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex, bool reset_cache) @@ -305,7 +294,7 @@ std::vector> BuildNewQuorumQuarterMembers(cons size_t quorumSize = static_cast(llmqParams.size); auto quarterSize{quorumSize / 4}; const CBlockIndex* pWorkBlockIndex = pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8); - const auto modifier = GetHashModifier(llmqParams.type, pWorkBlockIndex); + const auto modifier = GetHashModifier(llmqParams.type, pQuorumBaseBlockIndex); auto allMns = deterministicMNManager->GetListForBlock(pWorkBlockIndex); @@ -455,8 +444,7 @@ void BuildQuorumSnapshot(const Consensus::LLMQParams& llmqParams, const CDetermi CQuorumSnapshot& quorumSnapshot, int nHeight, std::vector& skipList, const CBlockIndex* pQuorumBaseBlockIndex) { quorumSnapshot.activeQuorumMembers.resize(allMns.GetAllMNsCount()); - const CBlockIndex* pWorkBlockIndex = pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8); - const auto modifier = GetHashModifier(llmqParams.type, pWorkBlockIndex); + const auto modifier = GetHashModifier(llmqParams.type, pQuorumBaseBlockIndex); auto sortedAllMns = allMns.CalculateQuorum(allMns.GetAllMNsCount(), modifier); LogPrint(BCLog::LLMQ, "BuildQuorumSnapshot h[%d] numMns[%d]\n", pQuorumBaseBlockIndex->nHeight, allMns.GetAllMNsCount()); @@ -488,8 +476,7 @@ std::vector> GetQuorumQuarterMembersBySnapshot { std::vector sortedCombinedMns; { - const CBlockIndex* pWorkBlockIndex = pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8); - const auto modifier = GetHashModifier(llmqParams.type, pWorkBlockIndex); + const auto modifier = GetHashModifier(llmqParams.type, pQuorumBaseBlockIndex); const auto [MnsUsedAtH, MnsNotUsedAtH] = GetMNUsageBySnapshot(llmqParams.type, pQuorumBaseBlockIndex, snapshot, nHeight); // the list begins with all the unused MNs auto sortedMnsNotUsedAtH = MnsNotUsedAtH.CalculateQuorum(MnsNotUsedAtH.GetAllMNsCount(), modifier); @@ -581,7 +568,7 @@ std::pair GetMNUsageBySnapshot(Conse CDeterministicMNList nonUsedMNs; const CBlockIndex* pWorkBlockIndex = pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8); - const auto modifier = GetHashModifier(llmqType, pWorkBlockIndex); + const auto modifier = GetHashModifier(llmqType, pQuorumBaseBlockIndex); auto allMns = deterministicMNManager->GetListForBlock(pWorkBlockIndex); auto sortedAllMns = allMns.CalculateQuorum(allMns.GetAllMNsCount(), modifier); From 20c8aae9ab3585b090d8497faf2e7b8a913de6ba Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Sun, 14 May 2023 12:46:17 +0300 Subject: [PATCH 07/10] feat: use `height - 8` for all quorum types after v20 activation --- src/llmq/utils.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/llmq/utils.cpp b/src/llmq/utils.cpp index 33c736754ea6..a808db021507 100644 --- a/src/llmq/utils.cpp +++ b/src/llmq/utils.cpp @@ -65,12 +65,7 @@ void PreComputeQuorumMembers(const CBlockIndex* pQuorumBaseBlockIndex, bool rese uint256 GetHashModifier(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex) { - auto llmq_params_opt = GetLLMQParams(llmqType); - assert(llmq_params_opt.has_value()); - - const CBlockIndex* pWorkBlockIndex = llmq_params_opt->useRotation ? - pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8) : - pQuorumBaseBlockIndex; + const CBlockIndex* pWorkBlockIndex = pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8); if (IsV20Active(pWorkBlockIndex)) { // v20 is active: calculate modifier using the new way. @@ -85,7 +80,12 @@ uint256 GetHashModifier(Consensus::LLMQType llmqType, const CBlockIndex* pQuorum } // v20 isn't active yet: calculate modifier using the usual way - return ::SerializeHash(std::make_pair(llmqType, pWorkBlockIndex->GetBlockHash())); + auto llmq_params_opt = GetLLMQParams(llmqType); + assert(llmq_params_opt.has_value()); + if (llmq_params_opt->useRotation) { + return ::SerializeHash(std::make_pair(llmqType, pWorkBlockIndex->GetBlockHash())); + } + return ::SerializeHash(std::make_pair(llmqType, pQuorumBaseBlockIndex->GetBlockHash())); } std::vector GetAllQuorumMembers(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex, bool reset_cache) @@ -165,11 +165,16 @@ std::vector GetAllQuorumMembers(Consensus::LLMQType llmqTy std::vector ComputeQuorumMembers(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex) { - auto allMns = deterministicMNManager->GetListForBlock(pQuorumBaseBlockIndex); - const auto modifier = GetHashModifier(llmqType, pQuorumBaseBlockIndex); bool HPMNOnly = (Params().GetConsensus().llmqTypePlatform == llmqType) && IsV19Active(pQuorumBaseBlockIndex); const auto& llmq_params_opt = GetLLMQParams(llmqType); assert(llmq_params_opt.has_value()); + assert(!llmq_params_opt->useRotation); + + const CBlockIndex* pWorkBlockIndex = IsV20Active(pQuorumBaseBlockIndex) ? + pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8) : + pQuorumBaseBlockIndex; + const auto modifier = GetHashModifier(llmqType, pQuorumBaseBlockIndex); + auto allMns = deterministicMNManager->GetListForBlock(pWorkBlockIndex); return allMns.CalculateQuorum(llmq_params_opt->size, modifier, HPMNOnly); } From 83236e3d5a19c8bce8467257d33d596b02c76b0a Mon Sep 17 00:00:00 2001 From: Odysseas Gabrielides Date: Tue, 16 May 2023 11:02:24 +0300 Subject: [PATCH 08/10] use const ref LLMQParams --- src/llmq/utils.cpp | 30 ++++++++++++++---------------- src/llmq/utils.h | 2 +- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/llmq/utils.cpp b/src/llmq/utils.cpp index a808db021507..3107ed9ecab1 100644 --- a/src/llmq/utils.cpp +++ b/src/llmq/utils.cpp @@ -48,7 +48,7 @@ static std::vector> BuildNewQuorumQuarterMembe static PreviousQuorumQuarters GetPreviousQuorumQuarterMembers(const Consensus::LLMQParams& llmqParams, const CBlockIndex* pBlockHMinusCIndex, const CBlockIndex* pBlockHMinus2CIndex, const CBlockIndex* pBlockHMinus3CIndex, int nHeight); static std::vector> GetQuorumQuarterMembersBySnapshot(const Consensus::LLMQParams& llmqParams, const CBlockIndex* pQuorumBaseBlockIndex, const llmq::CQuorumSnapshot& snapshot, int nHeights); -static std::pair GetMNUsageBySnapshot(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex, const llmq::CQuorumSnapshot& snapshot, int nHeight); +static std::pair GetMNUsageBySnapshot(const Consensus::LLMQParams& llmqParams, const CBlockIndex* pQuorumBaseBlockIndex, const llmq::CQuorumSnapshot& snapshot, int nHeight); static void BuildQuorumSnapshot(const Consensus::LLMQParams& llmqParams, const CDeterministicMNList& allMns, const CDeterministicMNList& mnUsedAtH, std::vector& sortedCombinedMns, CQuorumSnapshot& quorumSnapshot, int nHeight, std::vector& skipList, const CBlockIndex* pQuorumBaseBlockIndex); @@ -63,7 +63,7 @@ void PreComputeQuorumMembers(const CBlockIndex* pQuorumBaseBlockIndex, bool rese } } -uint256 GetHashModifier(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex) +uint256 GetHashModifier(const Consensus::LLMQParams& llmqParams, const CBlockIndex* pQuorumBaseBlockIndex) { const CBlockIndex* pWorkBlockIndex = pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8); @@ -73,19 +73,17 @@ uint256 GetHashModifier(Consensus::LLMQType llmqType, const CBlockIndex* pQuorum if (cbcl.has_value()) { // We have a non-null CL signature: calculate modifier using this CL signature auto& [bestCLSignature, bestCLHeightDiff] = cbcl.value(); - return ::SerializeHash(std::make_tuple(llmqType, pWorkBlockIndex->nHeight, bestCLSignature)); + return ::SerializeHash(std::make_tuple(llmqParams.type, pWorkBlockIndex->nHeight, bestCLSignature)); } // No non-null CL signature found in coinbase: calculate modifier using block hash only - return ::SerializeHash(std::make_pair(llmqType, pWorkBlockIndex->GetBlockHash())); + return ::SerializeHash(std::make_pair(llmqParams.type, pWorkBlockIndex->GetBlockHash())); } // v20 isn't active yet: calculate modifier using the usual way - auto llmq_params_opt = GetLLMQParams(llmqType); - assert(llmq_params_opt.has_value()); - if (llmq_params_opt->useRotation) { - return ::SerializeHash(std::make_pair(llmqType, pWorkBlockIndex->GetBlockHash())); + if (llmqParams.useRotation) { + return ::SerializeHash(std::make_pair(llmqParams.type, pWorkBlockIndex->GetBlockHash())); } - return ::SerializeHash(std::make_pair(llmqType, pQuorumBaseBlockIndex->GetBlockHash())); + return ::SerializeHash(std::make_pair(llmqParams.type, pQuorumBaseBlockIndex->GetBlockHash())); } std::vector GetAllQuorumMembers(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex, bool reset_cache) @@ -173,7 +171,7 @@ std::vector ComputeQuorumMembers(Consensus::LLMQType llmqT const CBlockIndex* pWorkBlockIndex = IsV20Active(pQuorumBaseBlockIndex) ? pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8) : pQuorumBaseBlockIndex; - const auto modifier = GetHashModifier(llmqType, pQuorumBaseBlockIndex); + const auto modifier = GetHashModifier(llmq_params_opt.value(), pQuorumBaseBlockIndex); auto allMns = deterministicMNManager->GetListForBlock(pWorkBlockIndex); return allMns.CalculateQuorum(llmq_params_opt->size, modifier, HPMNOnly); } @@ -299,7 +297,7 @@ std::vector> BuildNewQuorumQuarterMembers(cons size_t quorumSize = static_cast(llmqParams.size); auto quarterSize{quorumSize / 4}; const CBlockIndex* pWorkBlockIndex = pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8); - const auto modifier = GetHashModifier(llmqParams.type, pQuorumBaseBlockIndex); + const auto modifier = GetHashModifier(llmqParams, pQuorumBaseBlockIndex); auto allMns = deterministicMNManager->GetListForBlock(pWorkBlockIndex); @@ -449,7 +447,7 @@ void BuildQuorumSnapshot(const Consensus::LLMQParams& llmqParams, const CDetermi CQuorumSnapshot& quorumSnapshot, int nHeight, std::vector& skipList, const CBlockIndex* pQuorumBaseBlockIndex) { quorumSnapshot.activeQuorumMembers.resize(allMns.GetAllMNsCount()); - const auto modifier = GetHashModifier(llmqParams.type, pQuorumBaseBlockIndex); + const auto modifier = GetHashModifier(llmqParams, pQuorumBaseBlockIndex); auto sortedAllMns = allMns.CalculateQuorum(allMns.GetAllMNsCount(), modifier); LogPrint(BCLog::LLMQ, "BuildQuorumSnapshot h[%d] numMns[%d]\n", pQuorumBaseBlockIndex->nHeight, allMns.GetAllMNsCount()); @@ -481,8 +479,8 @@ std::vector> GetQuorumQuarterMembersBySnapshot { std::vector sortedCombinedMns; { - const auto modifier = GetHashModifier(llmqParams.type, pQuorumBaseBlockIndex); - const auto [MnsUsedAtH, MnsNotUsedAtH] = GetMNUsageBySnapshot(llmqParams.type, pQuorumBaseBlockIndex, snapshot, nHeight); + const auto modifier = GetHashModifier(llmqParams, pQuorumBaseBlockIndex); + const auto [MnsUsedAtH, MnsNotUsedAtH] = GetMNUsageBySnapshot(llmqParams, pQuorumBaseBlockIndex, snapshot, nHeight); // the list begins with all the unused MNs auto sortedMnsNotUsedAtH = MnsNotUsedAtH.CalculateQuorum(MnsNotUsedAtH.GetAllMNsCount(), modifier); sortedCombinedMns = std::move(sortedMnsNotUsedAtH); @@ -564,7 +562,7 @@ std::vector> GetQuorumQuarterMembersBySnapshot } } -std::pair GetMNUsageBySnapshot(Consensus::LLMQType llmqType, +std::pair GetMNUsageBySnapshot(const Consensus::LLMQParams& llmqParams, const CBlockIndex* pQuorumBaseBlockIndex, const llmq::CQuorumSnapshot& snapshot, int nHeight) @@ -573,7 +571,7 @@ std::pair GetMNUsageBySnapshot(Conse CDeterministicMNList nonUsedMNs; const CBlockIndex* pWorkBlockIndex = pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8); - const auto modifier = GetHashModifier(llmqType, pQuorumBaseBlockIndex); + const auto modifier = GetHashModifier(llmqParams, pQuorumBaseBlockIndex); auto allMns = deterministicMNManager->GetListForBlock(pWorkBlockIndex); auto sortedAllMns = allMns.CalculateQuorum(allMns.GetAllMNsCount(), modifier); diff --git a/src/llmq/utils.h b/src/llmq/utils.h index 3f671c4edad5..a5d15e8e2fdb 100644 --- a/src/llmq/utils.h +++ b/src/llmq/utils.h @@ -58,7 +58,7 @@ namespace utils std::vector GetAllQuorumMembers(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex, bool reset_cache = false); void PreComputeQuorumMembers(const CBlockIndex* pQuorumBaseBlockIndex, bool reset_cache = false); -uint256 GetHashModifier(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex); +uint256 GetHashModifier(const Consensus::LLMQParams& llmqParams, const CBlockIndex* pQuorumBaseBlockIndex); uint256 BuildCommitmentHash(Consensus::LLMQType llmqType, const uint256& blockHash, const std::vector& validMembers, const CBLSPublicKey& pubKey, const uint256& vvecHash); uint256 BuildSignHash(Consensus::LLMQType llmqType, const uint256& quorumHash, const uint256& id, const uint256& msgHash); From 499d885625e3110c400d7195614080cffe117cd9 Mon Sep 17 00:00:00 2001 From: Odysseas Gabrielides Date: Wed, 17 May 2023 17:57:40 +0300 Subject: [PATCH 09/10] ASSERT_IF_DEBUG and return empty if rotation --- src/llmq/utils.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/llmq/utils.cpp b/src/llmq/utils.cpp index 3107ed9ecab1..679449a69f3c 100644 --- a/src/llmq/utils.cpp +++ b/src/llmq/utils.cpp @@ -166,7 +166,8 @@ std::vector ComputeQuorumMembers(Consensus::LLMQType llmqT bool HPMNOnly = (Params().GetConsensus().llmqTypePlatform == llmqType) && IsV19Active(pQuorumBaseBlockIndex); const auto& llmq_params_opt = GetLLMQParams(llmqType); assert(llmq_params_opt.has_value()); - assert(!llmq_params_opt->useRotation); + ASSERT_IF_DEBUG(!llmq_params_opt->useRotation); + if (llmq_params_opt->useRotation) return {}; const CBlockIndex* pWorkBlockIndex = IsV20Active(pQuorumBaseBlockIndex) ? pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8) : From e1f8e9e5b66a9618b342e9a85a3063430b8cfae4 Mon Sep 17 00:00:00 2001 From: Odysseas Gabrielides Date: Wed, 17 May 2023 18:11:03 +0300 Subject: [PATCH 10/10] one block check --- src/llmq/utils.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/llmq/utils.cpp b/src/llmq/utils.cpp index 679449a69f3c..a7c136e99c30 100644 --- a/src/llmq/utils.cpp +++ b/src/llmq/utils.cpp @@ -166,8 +166,10 @@ std::vector ComputeQuorumMembers(Consensus::LLMQType llmqT bool HPMNOnly = (Params().GetConsensus().llmqTypePlatform == llmqType) && IsV19Active(pQuorumBaseBlockIndex); const auto& llmq_params_opt = GetLLMQParams(llmqType); assert(llmq_params_opt.has_value()); - ASSERT_IF_DEBUG(!llmq_params_opt->useRotation); - if (llmq_params_opt->useRotation) return {}; + if (llmq_params_opt->useRotation) { + ASSERT_IF_DEBUG(false); + return {}; + } const CBlockIndex* pWorkBlockIndex = IsV20Active(pQuorumBaseBlockIndex) ? pQuorumBaseBlockIndex->GetAncestor(pQuorumBaseBlockIndex->nHeight - 8) :