Merge #6278: perf: reduced delays and syncs in functional tests to run faster

874ef8cda2 fix: mine_quorum_no_checks -> mine_quorum_less_checks: do some checks to make sure quorums are mined correctly (UdjinM6)
4f636f47b4 fix: re-order functional tests: move governance to 60+seconds category (Konstantin Akimov)
fe49f3f178 refactor: removed dead and commented code from test_framework.py (Konstantin Akimov)
cd1958c82a perf: removed sleep(6) from mine_cycle_quorum in functional tests (Konstantin Akimov)
3f17a01a83 fix: bump mocktime in simplepose when generating blocks to improve robustness (Konstantin Akimov)
132d95e651 perf: remove sleep(1) from each step of quorum creation in functional tests (Konstantin Akimov)
4c57ad1c05 chore: increase batch size from 10 to 50 for faster block generation in functional tests (Konstantin Akimov)

Pull request description:

  ## Issue being fixed or feature implemented
  Functional tests take too long time to run.

  (PR is recreated from https://github.com/dashpay/dash/pull/6268 because CI is broken)

  ## What was done?
   - increased robustness `feature_llmq_simplepose.py` by adding missing bump for mocktime during block generations
   - removed sleep(1) from each stage of mine_quorum
   - removed sleep(6) from final stage of mine_cycled_quorum
   - size of batch for block generation in `feature_asset_locks.py` and in `activate_fork_by_name()` increased from 10 blocks to 50 blocks
   - moved governance's functional tests to "60 seconds+" category because they always the last one to wait if running more than 10 jobs at once
  Plus extra refactoring which removes dead and commented code from test_framework.py

  ## How Has This Been Tested?
  Locally, the functional tests speed up with these fixes for 15% for overall time and 20% for accumulated time
  `test/functional/test_runner.py -j20`

  Before:
  ```
  ALL                                                | ✓ Passed  | 7860 s (accumulated)
  Runtime: 481 s
  ```

  After:
  ```
  ALL                                                | ✓ Passed | 6237 s (accumulated)
  Runtime: 416 s
  ```

  ---
  CI tsan job speeds up for 5 minutes in absolute time (~5%) and 1000 seconds in accumulated time.
  ```
  ALL                                                | ✓ Passed  | 23854 s (accumulated)
  Runtime: 6249 s
  ```
  ↑ [old version](https://gitlab.com/dashpay/dash/-/jobs/7822664869) vs [new version](https://gitlab.com/dashpay/dash/-/jobs/7825461091) ↓
  ```
  ALL                                                | ✓ Passed  | 22901 s (accumulated)
  Runtime: 5962 s
  ```

  ## Breaking Changes
  N/A

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

ACKs for top commit:
  UdjinM6:
    utACK 874ef8cda2
  PastaPastaPasta:
    utACK 874ef8cda2

Tree-SHA512: 514fa2fb32abd59c90f63b68fccc8c3d3b6d16b0b6ad7459c4a348825815e7d3012177565dea1f70b8a1f28ede1a297f91361365454d1be85955e77260451cf5
This commit is contained in:
pasta 2024-09-25 09:33:30 -05:00
commit 61201b80da
No known key found for this signature in database
GPG Key ID: 52527BEDABE87984
4 changed files with 21 additions and 37 deletions

View File

@ -219,11 +219,11 @@ class AssetLocksTest(DashTestFramework):
except JSONRPCException as e:
assert expected_error in e.error['message']
def slowly_generate_batch(self, count):
self.log.info(f"Slowly generate {count} blocks")
def generate_batch(self, count):
self.log.info(f"Generate {count} blocks")
while count > 0:
self.log.info(f"Generating batch of blocks {count} left")
batch = min(10, count)
batch = min(50, count)
count -= batch
self.bump_mocktime(batch)
self.nodes[1].generate(batch)
@ -426,7 +426,7 @@ class AssetLocksTest(DashTestFramework):
self.validate_credit_pool_balance(locked - 2 * COIN)
self.log.info("Generating many blocks to make quorum far behind (even still active)...")
self.slowly_generate_batch(too_late_height - node.getblockcount() - 1)
self.generate_batch(too_late_height - node.getblockcount() - 1)
self.check_mempool_result(tx=asset_unlock_tx_too_late, result_expected={'allowed': True, 'fees': {'base': Decimal(str(tiny_amount / COIN))}})
node.generate(1)
self.sync_all()
@ -444,7 +444,7 @@ class AssetLocksTest(DashTestFramework):
for inode in self.nodes:
inode.invalidateblock(block_asset_unlock)
self.validate_credit_pool_balance(locked)
self.slowly_generate_batch(50)
self.generate_batch(50)
self.validate_credit_pool_balance(locked)
for inode in self.nodes:
inode.reconsiderblock(block_to_reconsider)
@ -510,7 +510,7 @@ class AssetLocksTest(DashTestFramework):
assert spend_txid_in_block in block['tx']
self.log.info("Fast forward to the next day to reset all current unlock limits...")
self.slowly_generate_batch(blocks_in_one_day)
self.generate_batch(blocks_in_one_day)
self.mine_quorum_2_nodes(llmq_type_name='llmq_test_platform', llmq_type=106)
total = self.get_credit_pool_balance()
@ -585,7 +585,7 @@ class AssetLocksTest(DashTestFramework):
assert pending_txid in node.getrawmempool()
self.log.info("Fast forward to next day again...")
self.slowly_generate_batch(blocks_in_one_day - 1)
self.generate_batch(blocks_in_one_day - 1)
self.log.info("Checking mempool is empty now...")
self.mempool_size = 0
self.check_mempool_size()
@ -618,7 +618,7 @@ class AssetLocksTest(DashTestFramework):
self.log.info("generate many blocks to be sure that mempool is empty after expiring txes...")
self.slowly_generate_batch(60)
self.generate_batch(60)
self.log.info("Checking that credit pool is not changed...")
assert_equal(new_total, self.get_credit_pool_balance())
self.check_mempool_size()

View File

@ -92,16 +92,16 @@ class LLMQSimplePoSeTest(DashTestFramework):
for mn in self.mninfo:
assert not self.check_punished(mn) and not self.check_banned(mn)
def mine_quorum_no_check(self, expected_good_nodes, mninfos_online):
def mine_quorum_less_checks(self, expected_good_nodes, mninfos_online):
# Unlike in mine_quorum we skip most of the checks and only care about
# nodes moving forward from phase to phase and the fact that the quorum is actually mined.
self.log.info("Mining a quorum with no checks")
# nodes moving forward from phase to phase correctly and the fact that the quorum is actually mined.
self.log.info("Mining a quorum with less checks")
nodes = [self.nodes[0]] + [mn.node for mn in mninfos_online]
# move forward to next DKG
skip_count = 24 - (self.nodes[0].getblockcount() % 24)
if skip_count != 0:
self.bump_mocktime(1, nodes=nodes)
self.bump_mocktime(skip_count, nodes=nodes)
self.nodes[0].generate(skip_count)
self.sync_blocks(nodes)
@ -112,7 +112,7 @@ class LLMQSimplePoSeTest(DashTestFramework):
self.move_blocks(nodes, 2)
self.log.info("Waiting for phase 2 (contribute)")
self.wait_for_quorum_phase(q, 2, expected_good_nodes, None, 0, mninfos_online)
self.wait_for_quorum_phase(q, 2, expected_good_nodes, "receivedContributions", expected_good_nodes, mninfos_online)
self.move_blocks(nodes, 2)
self.log.info("Waiting for phase 3 (complain)")
@ -124,7 +124,7 @@ class LLMQSimplePoSeTest(DashTestFramework):
self.move_blocks(nodes, 2)
self.log.info("Waiting for phase 5 (commit)")
self.wait_for_quorum_phase(q, 5, expected_good_nodes, None, 0, mninfos_online)
self.wait_for_quorum_phase(q, 5, expected_good_nodes, "receivedPrematureCommitments", expected_good_nodes, mninfos_online)
self.move_blocks(nodes, 2)
self.log.info("Waiting for phase 6 (mining)")
@ -147,6 +147,7 @@ class LLMQSimplePoSeTest(DashTestFramework):
quorum_info = self.nodes[0].quorum("info", 100, new_quorum)
# Mine 8 (SIGN_HEIGHT_OFFSET) more blocks to make sure that the new quorum gets eligible for signing sessions
self.bump_mocktime(8)
self.nodes[0].generate(8)
self.sync_blocks(nodes)
self.log.info("New quorum: height=%d, quorumHash=%s, quorumIndex=%d, minedBlock=%s" % (quorum_info["height"], new_quorum, quorum_info["quorumIndex"], quorum_info["minedBlock"]))
@ -174,7 +175,7 @@ class LLMQSimplePoSeTest(DashTestFramework):
# 6th time is when it should be banned for sure.
for _ in range(6):
self.reset_probe_timeouts()
self.mine_quorum_no_check(expected_contributors - 1, mninfos_online)
self.mine_quorum_less_checks(expected_contributors - 1, mninfos_online)
assert self.check_banned(mn)

View File

@ -1136,7 +1136,7 @@ class DashTestFramework(BitcoinTestFramework):
self.wait_for_sporks_same()
# mine blocks in batches
batch_size = 10
batch_size = 50
if expected_activation_height is not None:
height = self.nodes[0].getblockcount()
assert height < expected_activation_height
@ -1170,9 +1170,6 @@ class DashTestFramework(BitcoinTestFramework):
self.nodes[0].sporkupdate("SPORK_17_QUORUM_DKG_ENABLED", spork17_value)
self.wait_for_sporks_same()
def activate_dip0024(self, expected_activation_height=None):
self.activate_by_name('dip0024', expected_activation_height)
def activate_v19(self, expected_activation_height=None):
self.activate_by_name('v19', expected_activation_height)
@ -1794,7 +1791,6 @@ class DashTestFramework(BitcoinTestFramework):
wait_until_helper(wait_func, timeout=timeout, sleep=sleep)
def move_blocks(self, nodes, num_blocks):
time.sleep(1)
self.bump_mocktime(1, nodes=nodes)
self.nodes[0].generate(num_blocks)
self.sync_blocks(nodes)
@ -1913,19 +1909,11 @@ class DashTestFramework(BitcoinTestFramework):
# move forward to next DKG
skip_count = 24 - (self.nodes[0].getblockcount() % 24)
# if skip_count != 0:
# self.bump_mocktime(1, nodes=nodes)
# self.nodes[0].generate(skip_count)
# time.sleep(4)
# self.sync_blocks(nodes)
self.move_blocks(nodes, skip_count)
q_0 = self.nodes[0].getbestblockhash()
self.log.info("Expected quorum_0 at:" + str(self.nodes[0].getblockcount()))
# time.sleep(4)
self.log.info("Expected quorum_0 hash:" + str(q_0))
# time.sleep(4)
self.log.info("quorumIndex 0: Waiting for phase 1 (init)")
self.wait_for_quorum_phase(q_0, 1, expected_members, None, 0, mninfos_online, llmq_type_name)
self.log.info("quorumIndex 0: Waiting for quorum connections (init)")
@ -1937,9 +1925,7 @@ class DashTestFramework(BitcoinTestFramework):
q_1 = self.nodes[0].getbestblockhash()
self.log.info("Expected quorum_1 at:" + str(self.nodes[0].getblockcount()))
# time.sleep(2)
self.log.info("Expected quorum_1 hash:" + str(q_1))
# time.sleep(2)
self.log.info("quorumIndex 1: Waiting for phase 1 (init)")
self.wait_for_quorum_phase(q_1, 1, expected_members, None, 0, mninfos_online, llmq_type_name)
self.log.info("quorumIndex 1: Waiting for quorum connections (init)")
@ -1996,14 +1982,12 @@ class DashTestFramework(BitcoinTestFramework):
self.log.info("quorumIndex 1: Waiting for phase 6 (finalization)")
self.wait_for_quorum_phase(q_1, 6, expected_members, None, 0, mninfos_online, llmq_type_name)
time.sleep(6)
self.log.info("Mining final commitments")
self.bump_mocktime(1, nodes=nodes)
self.nodes[0].getblocktemplate() # this calls CreateNewBlock
self.nodes[0].generate(1)
self.sync_blocks(nodes)
time.sleep(6)
self.log.info("Waiting for quorum(s) to appear in the list")
self.wait_for_quorums_list(q_0, q_1, nodes, llmq_type_name)
@ -2038,7 +2022,6 @@ class DashTestFramework(BitcoinTestFramework):
self.bump_mocktime(1, nodes=nodes)
self.nodes[0].generate(skip_count)
self.sync_blocks(nodes)
time.sleep(1)
self.log.info('Moved from block %d to %d' % (cur_block, self.nodes[0].getblockcount()))
def wait_for_recovered_sig(self, rec_sig_id, rec_sig_msg_hash, llmq_type=100, timeout=10):

View File

@ -133,6 +133,10 @@ BASE_SCRIPTS = [
'feature_dip4_coinbasemerkleroots.py', # NOTE: needs dash_hash to pass
'feature_asset_locks.py', # NOTE: needs dash_hash to pass
'feature_mnehf.py', # NOTE: needs dash_hash to pass
'feature_governance.py --legacy-wallet',
'feature_governance.py --descriptors',
'feature_governance_cl.py --legacy-wallet',
'feature_governance_cl.py --descriptors',
# vv Tests less than 60s vv
'p2p_sendheaders.py', # NOTE: needs dash_hash to pass
'p2p_sendheaders_compressed.py', # NOTE: needs dash_hash to pass
@ -294,10 +298,6 @@ BASE_SCRIPTS = [
'feature_cltv.py',
'feature_new_quorum_type_activation.py',
'feature_governance_objects.py',
'feature_governance.py --legacy-wallet',
'feature_governance.py --descriptors',
'feature_governance_cl.py --legacy-wallet',
'feature_governance_cl.py --descriptors',
'p2p_governance_invs.py',
'rpc_uptime.py',
'feature_discover.py',