From 3bf7d2a38c5d8dfa2bab9cf3dcdb757a88e74ab6 Mon Sep 17 00:00:00 2001 From: PastaPastaPasta <6443210+PastaPastaPasta@users.noreply.github.com> Date: Wed, 31 May 2023 15:34:14 -0500 Subject: [PATCH] feat: ability to disable clsig creation while retaining clsig enforcement (#5398) ## Issue being fixed or feature implemented Currently, Chainlocks are either enabled or disabled. This PR adds a third state: enabled but we will not sign new ones. Should probably backport this to v19.x ## What was done? Spork state != 0 but active will now result in chain locks being enforced but not created. ## How Has This Been Tested? ## Breaking Changes None ## Checklist: _Go over all the following points, and put an `x` in all the boxes that apply._ - [ ] 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)_ --------- Co-authored-by: UdjinM6 --- src/llmq/chainlocks.cpp | 9 +++++++++ src/llmq/chainlocks.h | 1 + test/functional/feature_llmq_chainlocks.py | 14 ++++++++++++++ test/functional/test_framework/test_framework.py | 4 ++-- 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/llmq/chainlocks.cpp b/src/llmq/chainlocks.cpp index 56d7fb0020..e42e3677b4 100644 --- a/src/llmq/chainlocks.cpp +++ b/src/llmq/chainlocks.cpp @@ -249,6 +249,10 @@ void CChainLocksHandler::TrySignChainTip() return; } + if (!ChainLocksSigningEnabled(spork_manager)) { + return; + } + const CBlockIndex* pindex = WITH_LOCK(cs_main, return ::ChainActive().Tip()); if (pindex->pprev == nullptr) { @@ -687,4 +691,9 @@ bool AreChainLocksEnabled(const CSporkManager& sporkManager) return sporkManager.IsSporkActive(SPORK_19_CHAINLOCKS_ENABLED); } +bool ChainLocksSigningEnabled(const CSporkManager& sporkManager) +{ + return sporkManager.GetSporkValue(SPORK_19_CHAINLOCKS_ENABLED) == 0; +} + } // namespace llmq diff --git a/src/llmq/chainlocks.h b/src/llmq/chainlocks.h index e7bf421e9e..7f9422a78b 100644 --- a/src/llmq/chainlocks.h +++ b/src/llmq/chainlocks.h @@ -128,6 +128,7 @@ private: extern std::unique_ptr chainLocksHandler; bool AreChainLocksEnabled(const CSporkManager& sporkManager); +bool ChainLocksSigningEnabled(const CSporkManager& sporkManager); } // namespace llmq diff --git a/test/functional/feature_llmq_chainlocks.py b/test/functional/feature_llmq_chainlocks.py index 2b00eab47e..24f30f8069 100755 --- a/test/functional/feature_llmq_chainlocks.py +++ b/test/functional/feature_llmq_chainlocks.py @@ -66,6 +66,20 @@ class LLMQChainLocksTest(DashTestFramework): block = self.nodes[0].getblock(self.nodes[0].getblockhash(h)) assert block['chainlock'] + # Update spork to SPORK_19_CHAINLOCKS_ENABLED and test its behaviour + self.nodes[0].sporkupdate("SPORK_19_CHAINLOCKS_ENABLED", 1) + self.wait_for_sporks_same() + + # Generate new blocks and verify that they are not chainlocked + previous_block_hash = self.nodes[0].getbestblockhash() + for _ in range(2): + block_hash = self.nodes[0].generate(1)[0] + self.wait_for_chainlocked_block_all_nodes(block_hash, expected=False) + assert self.nodes[0].getblock(previous_block_hash)["chainlock"] + + self.nodes[0].sporkupdate("SPORK_19_CHAINLOCKS_ENABLED", 0) + self.wait_for_sporks_same() + self.log.info("Isolate node, mine on another, and reconnect") self.isolate_node(0) node0_mining_addr = self.nodes[0].getnewaddress() diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 86556cedbb..1ee14328cf 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -1513,9 +1513,9 @@ class DashTestFramework(BitcoinTestFramework): if wait_until(check_chainlocked_block, timeout=timeout, sleep=0.1, do_assert=expected) and not expected: raise AssertionError("waiting unexpectedly succeeded") - def wait_for_chainlocked_block_all_nodes(self, block_hash, timeout=15): + def wait_for_chainlocked_block_all_nodes(self, block_hash, timeout=15, expected=True): for node in self.nodes: - self.wait_for_chainlocked_block(node, block_hash, timeout=timeout) + self.wait_for_chainlocked_block(node, block_hash, expected=expected, timeout=timeout) def wait_for_best_chainlock(self, node, block_hash, timeout=15): wait_until(lambda: node.getbestchainlock()["blockhash"] == block_hash, timeout=timeout, sleep=0.1)