Skip to content

Commit 7ee31cb

Browse files
codablockUdjinM6
authored andcommitted
Speed up integration tests with masternodes (#2642)
* Implement copy_datadir to allow easy copying of state from one node to another * Instead of starting with a fresh datadir for MNs, reuse a copy of the faucet * Start masternodes in parallel instead of waiting for the previous to finish * Allow specifying of window and threshold with -bip9params * Implement -dip3activationheight for regtests * Implement fast DIP3 activation in DashTestFramework * Speed up activation of DIP3 in dip3-deterministicmns.py * Update qa/rpc-tests/test_framework/test_framework.py Co-Authored-By: codablock <ablock84@gmail.com> * Always assign fast_dip3_activation
1 parent fda16f1 commit 7ee31cb

10 files changed

+126
-27
lines changed

qa/rpc-tests/autoix-mempool.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
class AutoIXMempoolTest(DashTestFramework):
2525
def __init__(self):
26-
super().__init__(13, 10, ["-maxmempool=%d" % MAX_MEMPOOL_SIZE, '-limitdescendantsize=10'])
26+
super().__init__(13, 10, ["-maxmempool=%d" % MAX_MEMPOOL_SIZE, '-limitdescendantsize=10'], fast_dip3_activation=True)
2727
# set sender, receiver
2828
self.receiver_idx = self.num_nodes - 2
2929
self.sender_idx = self.num_nodes - 3

qa/rpc-tests/dip3-deterministicmns.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ def __init__(self):
2222
self.num_nodes = 1 + self.num_initial_mn + 2 # +1 for controller, +1 for mn-qt, +1 for mn created after dip3 activation
2323
self.setup_clean_chain = True
2424

25-
self.extra_args = ["-budgetparams=240:100:240"]
25+
self.extra_args = ["-budgetparams=10:10:10"]
2626
self.extra_args += ["-sporkkey=cP4EKFyJsHT39LDqgdcB43Y3YXjNyjb5Fuas1GQSeAtjnZWmZEQK"]
27+
self.extra_args += ["-bip9params=dip0003:0:999999999999:45:45", "-dip3activationheight=150"]
2728

2829
def setup_network(self):
2930
disable_mocktime()
@@ -56,9 +57,9 @@ def run_test(self):
5657
self.nodes[0].generate(1) # generate enough for collaterals
5758
print("controller node has {} dash".format(self.nodes[0].getbalance()))
5859

59-
# Make sure we're below block 432 (which activates dip3)
60+
# Make sure we're below block 135 (which activates dip3)
6061
print("testing rejection of ProTx before dip3 activation")
61-
assert(self.nodes[0].getblockchaininfo()['blocks'] < 432)
62+
assert(self.nodes[0].getblockchaininfo()['blocks'] < 135)
6263

6364
mns = []
6465

@@ -69,7 +70,7 @@ def run_test(self):
6970
mns.append(before_dip3_mn)
7071

7172
# block 500 starts enforcing DIP3 MN payments
72-
while self.nodes[0].getblockcount() < 498:
73+
while self.nodes[0].getblockcount() < 150:
7374
self.nodes[0].generate(1)
7475

7576
print("mining final block for DIP3 activation")

qa/rpc-tests/llmq-signing.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
class LLMQSigningTest(DashTestFramework):
1919
def __init__(self):
20-
super().__init__(11, 10, [])
20+
super().__init__(11, 10, [], fast_dip3_activation=True)
2121

2222
def run_test(self):
2323

qa/rpc-tests/p2p-autoinstantsend.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
class AutoInstantSendTest(DashTestFramework):
2525
def __init__(self):
26-
super().__init__(14, 10, [])
26+
super().__init__(14, 10, [], fast_dip3_activation=True)
2727
# set sender, receiver, isolated nodes
2828
self.isolated_idx = self.num_nodes - 1
2929
self.receiver_idx = self.num_nodes - 2

qa/rpc-tests/p2p-instantsend.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
class InstantSendTest(DashTestFramework):
1616
def __init__(self):
17-
super().__init__(14, 10, [])
17+
super().__init__(14, 10, [], fast_dip3_activation=True)
1818
# set sender, receiver, isolated nodes
1919
self.isolated_idx = self.num_nodes - 1
2020
self.receiver_idx = self.num_nodes - 2
@@ -55,7 +55,7 @@ def run_test(self):
5555
# start last node
5656
self.nodes[self.isolated_idx] = start_node(self.isolated_idx,
5757
self.options.tmpdir,
58-
["-debug"])
58+
["-debug"] + self.extra_args)
5959
# send doublespend transaction to isolated node
6060
self.nodes[self.isolated_idx].sendrawtransaction(dblspnd_tx['hex'])
6161
# generate block on isolated node with doublespend transaction

qa/rpc-tests/test_framework/test_framework.py

+58-8
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import shutil
1212
import tempfile
1313
import traceback
14+
from concurrent.futures import ThreadPoolExecutor
1415
from time import time, sleep
1516

1617
from .util import (
@@ -35,7 +36,8 @@
3536
set_node_times,
3637
p2p_port,
3738
satoshi_round,
38-
wait_to_sync)
39+
wait_to_sync,
40+
copy_datadir)
3941
from .authproxy import JSONRPCException
4042

4143

@@ -218,7 +220,7 @@ def __init__(self, proTxHash, ownerAddr, votingAddr, pubKeyOperator, keyOperator
218220

219221

220222
class DashTestFramework(BitcoinTestFramework):
221-
def __init__(self, num_nodes, masterodes_count, extra_args):
223+
def __init__(self, num_nodes, masterodes_count, extra_args, fast_dip3_activation=False):
222224
super().__init__()
223225
self.mn_count = masterodes_count
224226
self.num_nodes = num_nodes
@@ -228,6 +230,12 @@ def __init__(self, num_nodes, masterodes_count, extra_args):
228230
# additional args
229231
self.extra_args = extra_args
230232

233+
self.extra_args += ["-sporkkey=cP4EKFyJsHT39LDqgdcB43Y3YXjNyjb5Fuas1GQSeAtjnZWmZEQK"]
234+
235+
self.fast_dip3_activation = fast_dip3_activation
236+
if fast_dip3_activation:
237+
self.extra_args += ["-bip9params=dip0003:0:999999999999:10:5", "-dip3activationheight=50"]
238+
231239
def create_simple_node(self):
232240
idx = len(self.nodes)
233241
args = self.extra_args
@@ -268,24 +276,64 @@ def prepare_masternodes(self):
268276
self.mninfo.append(MasternodeInfo(proTxHash, ownerAddr, votingAddr, bls['public'], bls['secret'], address, txid, collateral_vout))
269277
self.sync_all()
270278

279+
def prepare_datadirs(self):
280+
# stop faucet node so that we can copy the datadir
281+
stop_node(self.nodes[0], 0)
282+
283+
start_idx = len(self.nodes)
284+
for idx in range(0, self.mn_count):
285+
copy_datadir(0, idx + start_idx, self.options.tmpdir)
286+
287+
# restart faucet node
288+
self.nodes[0] = start_node(0, self.options.tmpdir, self.extra_args)
289+
271290
def start_masternodes(self):
272291
start_idx = len(self.nodes)
292+
273293
for idx in range(0, self.mn_count):
294+
self.nodes.append(None)
295+
executor = ThreadPoolExecutor(max_workers=20)
296+
297+
def do_start(idx):
274298
args = ['-masternode=1',
275299
'-masternodeblsprivkey=%s' % self.mninfo[idx].keyOperator] + self.extra_args
276300
node = start_node(idx + start_idx, self.options.tmpdir, args)
277301
self.mninfo[idx].node = node
278-
self.nodes.append(node)
302+
self.nodes[idx + start_idx] = node
303+
wait_to_sync(node, True)
304+
305+
def do_connect(idx):
279306
for i in range(0, idx + 1):
280307
connect_nodes(self.nodes[idx + start_idx], i)
281-
wait_to_sync(node, True)
308+
309+
jobs = []
310+
311+
# start up nodes in parallel
312+
for idx in range(0, self.mn_count):
313+
jobs.append(executor.submit(do_start, idx))
314+
315+
# wait for all nodes to start up
316+
for job in jobs:
317+
job.result()
318+
jobs.clear()
319+
320+
# connect nodes in parallel
321+
for idx in range(0, self.mn_count):
322+
jobs.append(executor.submit(do_connect, idx))
323+
324+
# wait for all nodes to connect
325+
for job in jobs:
326+
job.result()
327+
jobs.clear()
328+
282329
sync_masternodes(self.nodes, True)
283330

331+
executor.shutdown()
332+
284333
def setup_network(self):
285334
self.nodes = []
286335
# create faucet node for collateral and transactions
287-
args = ["-sporkkey=cP4EKFyJsHT39LDqgdcB43Y3YXjNyjb5Fuas1GQSeAtjnZWmZEQK"] + self.extra_args
288-
self.nodes.append(start_node(0, self.options.tmpdir, args))
336+
self.nodes.append(start_node(0, self.options.tmpdir, self.extra_args))
289337
required_balance = MASTERNODE_COLLATERAL * self.mn_count + 1
290338
while self.nodes[0].getbalance() < required_balance:
291339
set_mocktime(get_mocktime() + 1)
@@ -297,12 +345,14 @@ def setup_network(self):
297345
sync_masternodes(self.nodes, True)
298346

299347
# activate DIP3
300-
while self.nodes[0].getblockcount() < 500:
301-
self.nodes[0].generate(10)
348+
if not self.fast_dip3_activation:
349+
while self.nodes[0].getblockcount() < 500:
350+
self.nodes[0].generate(10)
302351
self.sync_all()
303352

304353
# create masternodes
305354
self.prepare_masternodes()
355+
self.prepare_datadirs()
306356
self.start_masternodes()
307357

308358
set_mocktime(get_mocktime() + 1)

qa/rpc-tests/test_framework/util.py

+15
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,21 @@ def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, timewait=None
400400
raise
401401
return rpcs
402402

403+
404+
def copy_datadir(from_node, to_node, dirname):
405+
from_datadir = os.path.join(dirname, "node"+str(from_node), "regtest")
406+
to_datadir = os.path.join(dirname, "node"+str(to_node), "regtest")
407+
408+
dirs = ["blocks", "chainstate", "evodb", "llmq"]
409+
for d in dirs:
410+
try:
411+
src = os.path.join(from_datadir, d)
412+
dst = os.path.join(to_datadir, d)
413+
shutil.copytree(src, dst)
414+
except:
415+
pass
416+
417+
403418
def log_filename(dirname, n_node, logname):
404419
return os.path.join(dirname, "node"+str(n_node), "regtest", logname)
405420

src/chainparams.cpp

+19-3
Original file line numberDiff line numberDiff line change
@@ -789,10 +789,21 @@ class CRegTestParams : public CChainParams {
789789
consensus.llmqs[Consensus::LLMQ_50_60] = llmq50_60;
790790
}
791791

792-
void UpdateBIP9Parameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout)
792+
void UpdateBIP9Parameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout, int64_t nWindowSize, int64_t nThreshold)
793793
{
794794
consensus.vDeployments[d].nStartTime = nStartTime;
795795
consensus.vDeployments[d].nTimeout = nTimeout;
796+
if (nWindowSize != -1) {
797+
consensus.vDeployments[d].nWindowSize = nWindowSize;
798+
}
799+
if (nThreshold != -1) {
800+
consensus.vDeployments[d].nThreshold = nThreshold;
801+
}
802+
}
803+
804+
void UpdateDIP3ActivationHeight(int nHeight)
805+
{
806+
consensus.DIP0003Height = nHeight;
796807
}
797808

798809
void UpdateBudgetParameters(int nMasternodePaymentsStartBlock, int nBudgetPaymentsStartBlock, int nSuperblockStartBlock)
@@ -838,9 +849,14 @@ void SelectParams(const std::string& network)
838849
pCurrentParams = &Params(network);
839850
}
840851

841-
void UpdateRegtestBIP9Parameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout)
852+
void UpdateRegtestBIP9Parameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout, int64_t nWindowSize, int64_t nThreshold)
853+
{
854+
regTestParams.UpdateBIP9Parameters(d, nStartTime, nTimeout, nWindowSize, nThreshold);
855+
}
856+
857+
void UpdateRegtestDIP3ActivationHeight(int nHeight)
842858
{
843-
regTestParams.UpdateBIP9Parameters(d, nStartTime, nTimeout);
859+
regTestParams.UpdateDIP3ActivationHeight(nHeight);
844860
}
845861

846862
void UpdateRegtestBudgetParameters(int nMasternodePaymentsStartBlock, int nBudgetPaymentsStartBlock, int nSuperblockStartBlock)

src/chainparams.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,12 @@ void SelectParams(const std::string& chain);
145145
/**
146146
* Allows modifying the BIP9 regtest parameters.
147147
*/
148-
void UpdateRegtestBIP9Parameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout);
148+
void UpdateRegtestBIP9Parameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout, int64_t nWindowSize, int64_t nThreshold);
149+
150+
/**
151+
* Allows modifying the DIP3 activation height
152+
*/
153+
void UpdateRegtestDIP3ActivationHeight(int nHeight);
149154

150155
/**
151156
* Allows modifying the budget regtest parameters.

src/init.cpp

+18-6
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,7 @@ std::string HelpMessage(HelpMessageMode mode)
543543
strUsage += HelpMessageOpt("-limitancestorsize=<n>", strprintf("Do not accept transactions whose size with all in-mempool ancestors exceeds <n> kilobytes (default: %u)", DEFAULT_ANCESTOR_SIZE_LIMIT));
544544
strUsage += HelpMessageOpt("-limitdescendantcount=<n>", strprintf("Do not accept transactions if any ancestor would have <n> or more in-mempool descendants (default: %u)", DEFAULT_DESCENDANT_LIMIT));
545545
strUsage += HelpMessageOpt("-limitdescendantsize=<n>", strprintf("Do not accept transactions if any ancestor would have more than <n> kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT));
546-
strUsage += HelpMessageOpt("-bip9params=<deployment>:<start>:<end>", "Use given start/end times for specified BIP9 deployment (regtest-only)");
546+
strUsage += HelpMessageOpt("-bip9params=<deployment>:<start>:<end>(:<window>:<threshold>)", "Use given start/end times for specified BIP9 deployment (regtest-only). Specifying window and threshold is optional.");
547547
strUsage += HelpMessageOpt("-watchquorums=<n>", strprintf("Watch and validate quorum communication (default: %u)", llmq::DEFAULT_WATCH_QUORUMS));
548548
}
549549
std::string debugCategories = "addrman, alert, bench, cmpctblock, coindb, db, http, leveldb, libevent, lock, mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc, selectcoins, tor, zmq, "
@@ -1290,23 +1290,31 @@ bool AppInitParameterInteraction()
12901290
for (auto i : deployments) {
12911291
std::vector<std::string> vDeploymentParams;
12921292
boost::split(vDeploymentParams, i, boost::is_any_of(":"));
1293-
if (vDeploymentParams.size() != 3) {
1294-
return InitError("BIP9 parameters malformed, expecting deployment:start:end");
1293+
if (vDeploymentParams.size() != 3 && vDeploymentParams.size() != 5) {
1294+
return InitError("BIP9 parameters malformed, expecting deployment:start:end or deployment:start:end:window:threshold");
12951295
}
1296-
int64_t nStartTime, nTimeout;
1296+
int64_t nStartTime, nTimeout, nWindowSize = -1, nThreshold = -1;
12971297
if (!ParseInt64(vDeploymentParams[1], &nStartTime)) {
12981298
return InitError(strprintf("Invalid nStartTime (%s)", vDeploymentParams[1]));
12991299
}
13001300
if (!ParseInt64(vDeploymentParams[2], &nTimeout)) {
13011301
return InitError(strprintf("Invalid nTimeout (%s)", vDeploymentParams[2]));
13021302
}
1303+
if (vDeploymentParams.size() == 5) {
1304+
if (!ParseInt64(vDeploymentParams[3], &nWindowSize)) {
1305+
return InitError(strprintf("Invalid nWindowSize (%s)", vDeploymentParams[3]));
1306+
}
1307+
if (!ParseInt64(vDeploymentParams[4], &nThreshold)) {
1308+
return InitError(strprintf("Invalid nThreshold (%s)", vDeploymentParams[4]));
1309+
}
1310+
}
13031311
bool found = false;
13041312
for (int j=0; j<(int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j)
13051313
{
13061314
if (vDeploymentParams[0].compare(VersionBitsDeploymentInfo[j].name) == 0) {
1307-
UpdateRegtestBIP9Parameters(Consensus::DeploymentPos(j), nStartTime, nTimeout);
1315+
UpdateRegtestBIP9Parameters(Consensus::DeploymentPos(j), nStartTime, nTimeout, nWindowSize, nThreshold);
13081316
found = true;
1309-
LogPrintf("Setting BIP9 activation parameters for %s to start=%ld, timeout=%ld\n", vDeploymentParams[0], nStartTime, nTimeout);
1317+
LogPrintf("Setting BIP9 activation parameters for %s to start=%ld, timeout=%ld, window=%ld, threshold=%ld\n", vDeploymentParams[0], nStartTime, nTimeout, nWindowSize, nThreshold);
13101318
break;
13111319
}
13121320
}
@@ -1316,6 +1324,10 @@ bool AppInitParameterInteraction()
13161324
}
13171325
}
13181326

1327+
if (IsArgSet("-dip3activationheight")) {
1328+
UpdateRegtestDIP3ActivationHeight(GetArg("-dip3activationheight", 0));
1329+
}
1330+
13191331
if (IsArgSet("-budgetparams")) {
13201332
// Allow overriding budget parameters for testing
13211333
if (!chainparams.MineBlocksOnDemand()) {

0 commit comments

Comments
 (0)