Skip to content

Commit

Permalink
feat: put DIP0024 activation to block 1 on RegTest
Browse files Browse the repository at this point in the history
  • Loading branch information
knst committed Dec 5, 2024
1 parent 632c4c4 commit 2bafadf
Show file tree
Hide file tree
Showing 7 changed files with 41 additions and 40 deletions.
4 changes: 3 additions & 1 deletion src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -794,7 +794,7 @@ class CRegTestParams : public CChainParams {
consensus.DIP0008Height = 1; // Always active unless overridden
consensus.BRRHeight = 1; // Always active unless overridden
consensus.DIP0020Height = 1; // Always active unless overridden
consensus.DIP0024QuorumsHeight = 900;
consensus.DIP0024QuorumsHeight = 1; // Always have dip0024 quorums unless overridden
consensus.V19Height = 900;
consensus.V20Height = 900;
consensus.MN_RRHeight = 900;
Expand Down Expand Up @@ -1025,6 +1025,8 @@ static void MaybeUpdateHeights(const ArgsManager& args, Consensus::Params& conse
consensus.DIP0001Height = int{height};
} else if (name == "dip0008") {
consensus.DIP0008Height = int{height};
} else if (name == "dip0024") {
consensus.DIP0024QuorumsHeight = 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, 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, 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
4 changes: 2 additions & 2 deletions src/test/util/setup_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,9 +354,9 @@ TestChainSetup::TestChainSetup(int num_blocks, const std::vector<const char*>& e
/* TestChainDIP3BeforeActivationSetup */
{ 430, uint256S("0x0bcefaa33fec56cd84d05d0e76cd6a78badcc20f627d91903646de6a07930a14") },
/* TestChainBRRBeforeActivationSetup */
{ 497, uint256S("0x23c31820ec5160b7181bfdf328e2b76cd12c9fa4544d892b7f01e74dd6220849") },
{ 497, uint256S("0x3c71d807d28b9b813434eb0679ec3d5bcf424c20088cf578f3757521c3e3eded") },
/* TestChainV19BeforeActivationSetup */
{ 894, uint256S("0x2885cf0fe8fdf29803b6c65002ba2570ff011531d8ea92be312a85d655e00c51") },
{ 894, uint256S("0x3f031e5cceade15bdfa559ddecb2ccb2b8d17083bdfd871a9d23b17d04b15292") },
}
};

Expand Down
3 changes: 2 additions & 1 deletion test/functional/feature_dip4_coinbasemerkleroots.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from test_framework.util import assert_equal

DIP0008_HEIGHT = 432
DIP0024_HEIGHT = 900

# TODO: this helper used in many tests, find a new home for it
class TestP2PConn(P2PInterface):
Expand All @@ -43,7 +44,7 @@ def getmnlistdiff(self, baseBlockHash, blockHash):

class LLMQCoinbaseCommitmentsTest(DashTestFramework):
def set_test_params(self):
self.extra_args = [[ f'-testactivationheight=dip0008@{DIP0008_HEIGHT}', "-vbparams=testdummy:999999999999:999999999999" ]] * 4
self.extra_args = [[ f'-testactivationheight=dip0008@{DIP0008_HEIGHT}', f'-testactivationheight=dip0024@{DIP0024_HEIGHT}', "-vbparams=testdummy:999999999999:999999999999" ]] * 4
self.set_dash_test_params(4, 3, extra_args = self.extra_args)

def remove_masternode(self, idx):
Expand Down
7 changes: 2 additions & 5 deletions test/functional/feature_llmq_rotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,9 @@ def run_test(self):
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.generate(self.nodes[0], 1, sync_fun=self.no_op)
Expand All @@ -103,10 +101,10 @@ def run_test(self):
assert_equal(dkg_info['active_dkgs'], 0)
nonzero_dkgs += dkg_info['active_dkgs']
assert_equal(dkg_info['next_dkg'], next_dkg)
assert_equal(nonzero_dkgs, 11) # 2 quorums 4 nodes each and 1 quorum of 3 nodes
assert_equal(nonzero_dkgs, 7) # 1 quorums 4 nodes and 1 quorum of 3 nodes

expectedDeleted = []
expectedNew = [h_100_0, h_106_0, h_104_0, h_100_1, h_106_1, h_104_1]
expectedNew = [h_100_0, h_106_0, h_100_1, h_106_1]
quorumList = self.test_getmnlistdiff_quorums(b_h_0, b_h_1, {}, expectedDeleted, expectedNew, testQuorumsCLSigs=False)

projected_activation_height = 900
Expand Down Expand Up @@ -363,7 +361,6 @@ def get_llmq_size(self, llmq_type):
100: 4, # In this test size for llmqType 100 is overwritten to 4
102: 3,
103: 4,
104: 4, # In this test size for llmqType 104 is overwritten to 4
106: 3
}.get(llmq_type, -1)

Expand Down
59 changes: 30 additions & 29 deletions test/functional/feature_llmq_signing.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from test_framework.util import assert_equal, assert_raises_rpc_error, force_finish_mnsync


q_type=100
class LLMQSigningTest(DashTestFramework):
def set_test_params(self):
self.set_dash_test_params(6, 5)
Expand Down Expand Up @@ -43,11 +44,11 @@ def run_test(self):

def check_sigs(hasrecsigs, isconflicting1, isconflicting2):
for mn in self.mninfo:
if mn.node.quorum("hasrecsig", 104, id, msgHash) != hasrecsigs:
if mn.node.quorum("hasrecsig", q_type, id, msgHash) != hasrecsigs:
return False
if mn.node.quorum("isconflicting", 104, id, msgHash) != isconflicting1:
if mn.node.quorum("isconflicting", q_type, id, msgHash) != isconflicting1:
return False
if mn.node.quorum("isconflicting", 104, id, msgHashConflict) != isconflicting2:
if mn.node.quorum("isconflicting", q_type, id, msgHashConflict) != isconflicting2:
return False
return True

Expand All @@ -61,24 +62,24 @@ def assert_sigs_nochange(hasrecsigs, isconflicting1, isconflicting2, timeout):
wait_for_sigs(False, False, False, 1)

# Sign first share without any optional parameter, should not result in recovered sig
self.mninfo[0].node.quorum("sign", 104, id, msgHash)
self.mninfo[0].node.quorum("sign", q_type, id, msgHash)
assert_sigs_nochange(False, False, False, 3)
# Sign second share and test optional quorumHash parameter, should not result in recovered sig
# 1. Providing an invalid quorum hash should fail and cause no changes for sigs
assert not self.mninfo[1].node.quorum("sign", 104, id, msgHash, msgHash)
assert not self.mninfo[1].node.quorum("sign", q_type, id, msgHash, msgHash)
assert_sigs_nochange(False, False, False, 3)
# 2. Providing a valid quorum hash should succeed and cause no changes for sigss
quorumHash = self.mninfo[1].node.quorum("selectquorum", 104, id)["quorumHash"]
assert self.mninfo[1].node.quorum("sign", 104, id, msgHash, quorumHash)
quorumHash = self.mninfo[1].node.quorum("selectquorum", q_type, id)["quorumHash"]
assert self.mninfo[1].node.quorum("sign", q_type, id, msgHash, quorumHash)
assert_sigs_nochange(False, False, False, 3)
# Sign third share and test optional submit parameter if spork21 is enabled, should result in recovered sig
# and conflict for msgHashConflict
if self.options.spork21:
# 1. Providing an invalid quorum hash and set submit=false, should throw an error
assert_raises_rpc_error(-8, 'quorum not found', self.mninfo[2].node.quorum, "sign", 104, id, msgHash, id, False)
assert_raises_rpc_error(-8, 'quorum not found', self.mninfo[2].node.quorum, "sign", q_type, id, msgHash, id, False)
# 2. Providing a valid quorum hash and set submit=false, should return a valid sigShare object
sig_share_rpc_1 = self.mninfo[2].node.quorum("sign", 104, id, msgHash, quorumHash, False)
sig_share_rpc_2 = self.mninfo[2].node.quorum("sign", 104, id, msgHash, "", False)
sig_share_rpc_1 = self.mninfo[2].node.quorum("sign", q_type, id, msgHash, quorumHash, False)
sig_share_rpc_2 = self.mninfo[2].node.quorum("sign", q_type, id, msgHash, "", False)
assert_equal(sig_share_rpc_1, sig_share_rpc_2)
assert_sigs_nochange(False, False, False, 3)
# 3. Sending the sig share received from RPC to the recovery member through P2P interface, should result
Expand All @@ -93,15 +94,15 @@ def assert_sigs_nochange(hasrecsigs, isconflicting1, isconflicting2, timeout):
for mn in self.mninfo:
assert mn.node.getconnectioncount() == self.llmq_size
# Get the current recovery member of the quorum
q = self.nodes[0].quorum('selectquorum', 104, id)
q = self.nodes[0].quorum('selectquorum', q_type, id)
mn = self.get_mninfo(q['recoveryMembers'][0])
# Open a P2P connection to it
p2p_interface = mn.node.add_p2p_connection(P2PInterface())
# Send the last required QSIGSHARE message to the recovery member
p2p_interface.send_message(msg_qsigshare([sig_share]))
else:
# If spork21 is not enabled just sign regularly
self.mninfo[2].node.quorum("sign", 104, id, msgHash)
self.mninfo[2].node.quorum("sign", q_type, id, msgHash)

wait_for_sigs(True, False, True, 15)

Expand All @@ -110,19 +111,19 @@ def assert_sigs_nochange(hasrecsigs, isconflicting1, isconflicting2, timeout):

# Test `quorum verify` rpc
node = self.mninfo[0].node
recsig = node.quorum("getrecsig", 104, id, msgHash)
recsig = node.quorum("getrecsig", q_type, id, msgHash)
# Find quorum automatically
height = node.getblockcount()
height_bad = node.getblockheader(recsig["quorumHash"])["height"]
hash_bad = node.getblockhash(0)
assert node.quorum("verify", 104, id, msgHash, recsig["sig"])
assert node.quorum("verify", 104, id, msgHash, recsig["sig"], "", height)
assert not node.quorum("verify", 104, id, msgHashConflict, recsig["sig"])
assert not node.quorum("verify", 104, id, msgHash, recsig["sig"], "", height_bad)
assert node.quorum("verify", q_type, id, msgHash, recsig["sig"])
assert node.quorum("verify", q_type, id, msgHash, recsig["sig"], "", height)
assert not node.quorum("verify", q_type, id, msgHashConflict, recsig["sig"])
assert not node.quorum("verify", q_type, id, msgHash, recsig["sig"], "", height_bad)
# Use specific quorum
assert node.quorum("verify", 104, id, msgHash, recsig["sig"], recsig["quorumHash"])
assert not node.quorum("verify", 104, id, msgHashConflict, recsig["sig"], recsig["quorumHash"])
assert_raises_rpc_error(-8, "quorum not found", node.quorum, "verify", 104, id, msgHash, recsig["sig"], hash_bad)
assert node.quorum("verify", q_type, id, msgHash, recsig["sig"], recsig["quorumHash"])
assert not node.quorum("verify", q_type, id, msgHashConflict, recsig["sig"], recsig["quorumHash"])
assert_raises_rpc_error(-8, "quorum not found", node.quorum, "verify", q_type, id, msgHash, recsig["sig"], hash_bad)

# Mine one more quorum, so that we have 2 active ones, nothing should change
self.mine_quorum()
Expand All @@ -131,23 +132,23 @@ def assert_sigs_nochange(hasrecsigs, isconflicting1, isconflicting2, timeout):
# Create a recovered sig for the oldest quorum i.e. the active quorum which will be moved
# out of the active set when a new quorum appears
request_id = 2
oldest_quorum_hash = node.quorum("list")["llmq_test_instantsend"][-1]
oldest_quorum_hash = node.quorum("list")["llmq_test"][-1]
# Search for a request id which selects the last active quorum
while True:
selected_hash = node.quorum('selectquorum', 104, uint256_to_string(request_id))["quorumHash"]
selected_hash = node.quorum('selectquorum', q_type, uint256_to_string(request_id))["quorumHash"]
if selected_hash == oldest_quorum_hash:
break
else:
request_id += 1
# Produce the recovered signature
id = uint256_to_string(request_id)
for mn in self.mninfo:
mn.node.quorum("sign", 104, id, msgHash)
mn.node.quorum("sign", q_type, id, msgHash)
# And mine a quorum to move the quorum which signed out of the active set
self.mine_quorum()
# Verify the recovered sig. This triggers the "signHeight + dkgInterval" verification
recsig = node.quorum("getrecsig", 104, id, msgHash)
assert node.quorum("verify", 104, id, msgHash, recsig["sig"], "", node.getblockcount())
recsig = node.quorum("getrecsig", q_type, id, msgHash)
assert node.quorum("verify", q_type, id, msgHash, recsig["sig"], "", node.getblockcount())

recsig_time = self.mocktime

Expand All @@ -166,21 +167,21 @@ def assert_sigs_nochange(hasrecsigs, isconflicting1, isconflicting2, timeout):
wait_for_sigs(False, False, False, 15)

for i in range(2):
self.mninfo[i].node.quorum("sign", 104, id, msgHashConflict)
self.mninfo[i].node.quorum("sign", q_type, id, msgHashConflict)
for i in range(2, 5):
self.mninfo[i].node.quorum("sign", 104, id, msgHash)
self.mninfo[i].node.quorum("sign", q_type, id, msgHash)
wait_for_sigs(True, False, True, 15)

if self.options.spork21:
id = uint256_to_string(request_id + 1)

# Isolate the node that is responsible for the recovery of a signature and assert that recovery fails
q = self.nodes[0].quorum('selectquorum', 104, id)
q = self.nodes[0].quorum('selectquorum', q_type, id)
mn = self.get_mninfo(q['recoveryMembers'][0])
mn.node.setnetworkactive(False)
self.wait_until(lambda: mn.node.getconnectioncount() == 0)
for i in range(4):
self.mninfo[i].node.quorum("sign", 104, id, msgHash)
self.mninfo[i].node.quorum("sign", q_type, id, msgHash)
assert_sigs_nochange(False, False, False, 3)
# Need to re-connect so that it later gets the recovered sig
mn.node.setnetworkactive(True)
Expand Down
2 changes: 1 addition & 1 deletion test/functional/rpc_blockchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ def _test_getblockchaininfo(self):
'dip0003': { 'type': 'buried', 'active': False, 'height': 432},
'dip0008': { 'type': 'buried', 'active': True, 'height': 1},
'dip0020': { 'type': 'buried', 'active': True, 'height': 1},
'dip0024': { 'type': 'buried', 'active': False, 'height': 900},
'dip0024': { 'type': 'buried', 'active': True, 'height': 1},
'realloc': { 'type': 'buried', 'active': True, 'height': 1},
'v19': { 'type': 'buried', 'active': False, 'height': 900},
'v20': { 'type': 'buried', 'active': False, 'height': 900},
Expand Down

0 comments on commit 2bafadf

Please sign in to comment.