Skip to content

Commit e06a8b6

Browse files
Merge #6751: test: wait delays for IS, CL just 0.05s
1a5cee6 test: instead bumping time per 1 second bump straightly 30 seconds in feature_llmq_is_retroactive (Konstantin Akimov) 0e9f7fb test: move helper wait_for_tx from test_framework to feature_llmq_is_retroactive (Konstantin Akimov) 71ef10a test: fix intermittent failures in p2p_instantsend.py and others (Konstantin Akimov) 067aa25 test: use default delay 0.05 for waiter of chainlock and chainlocked blocks (Konstantin Akimov) Pull request description: ## Issue being fixed or feature implemented Dash Core sends transactions after random delay for privacy reason. tx_relay->m_next_inv_send_time = GetExponentialRand(current_time, OUTBOUND_INVENTORY_BROADCAST_INTERVAL) This expential random delay could be long as 2s * 10 = 20 seconds or even longer sometimes. ## What was done? Prior work: #6631 To be sure that helper wait_for_instantsend is reliable need to bump mocktime for 20+ second, or even better 30 seconds. It fixes potential instability in functional tests and make them more deterministic and faster to run. Decreased delay for ChainLocks also. ## How Has This Been Tested? Run functional tests several times; no new failures are noticed. Minor performance improvement for functional tests that use `wait_for_instantlock`: ``` TEST | STATUS | DURATION feature_asset_locks.py | ✓ Passed | 114 s feature_llmq_is_cl_conflicts.py | ✓ Passed | 47 s feature_llmq_is_retroactive.py | ✓ Passed | 135 s feature_llmq_singlenode.py | ✓ Passed | 56 s feature_notifications.py | ✓ Passed | 74 s interface_zmq_dash.py --legacy-wallet | ✓ Passed | 45 s p2p_instantsend.py | ✓ Passed | 49 s rpc_verifyislock.py | ✓ Passed | 39 s ALL | ✓ Passed | 559 s (accumulated) Runtime: 135 s ---> TEST | STATUS | DURATION feature_asset_locks.py | ✓ Passed | 113 s feature_llmq_is_cl_conflicts.py | ✓ Passed | 33 s feature_llmq_is_retroactive.py | ✓ Passed | 126 s feature_llmq_singlenode.py | ✓ Passed | 37 s feature_notifications.py | ✓ Passed | 29 s interface_zmq_dash.py --legacy-wallet | ✓ Passed | 41 s p2p_instantsend.py | ✓ Passed | 44 s rpc_verifyislock.py | ✓ Passed | 37 s ALL | ✓ Passed | 460 s (accumulated) Runtime: 126 s ``` ## Breaking Changes N/A ## Checklist: - [x] 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 ACKs for top commit: UdjinM6: utACK 1a5cee6 PastaPastaPasta: utACK 1a5cee6 Tree-SHA512: c8b2066513f5496eac6ad98a8c6891acd4ad05820ad7339f657d695be114370cf0b4b7250f5d5077f1ec88b1baac658f01386c48190115163dd9f0e49941fd9f
2 parents 1b2cc07 + 1a5cee6 commit e06a8b6

File tree

9 files changed

+43
-21
lines changed

9 files changed

+43
-21
lines changed

test/functional/feature_asset_locks.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,7 @@ def test_asset_unlocks(self, node_wallet, node, pubkey):
378378
txid = self.send_tx(asset_unlock_tx)
379379
assert_equal(node.getmempoolentry(txid)['fees']['base'], Decimal("0.0007"))
380380
is_id = node_wallet.sendtoaddress(node_wallet.getnewaddress(), 1)
381+
self.bump_mocktime(30)
381382
for node in self.nodes:
382383
self.wait_for_instantlock(is_id, node)
383384

test/functional/feature_llmq_is_cl_conflicts.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ def test_chainlock_overrides_islock(self, test_block_conflict, mine_confllicting
9696
rawtx4_txid = self.nodes[0].sendrawtransaction(rawtx4)
9797

9898
# wait for transactions to propagate
99+
self.bump_mocktime(30)
99100
self.sync_mempools()
100101
for node in self.nodes:
101102
self.wait_for_instantlock(rawtx1_txid, node)
@@ -156,6 +157,7 @@ def test_chainlock_overrides_islock(self, test_block_conflict, mine_confllicting
156157
rawtx5 = self.nodes[0].signrawtransactionwithwallet(rawtx5)['hex']
157158
rawtx5_txid = self.nodes[0].sendrawtransaction(rawtx5)
158159
# wait for the transaction to propagate
160+
self.bump_mocktime(30)
159161
self.sync_mempools()
160162
for node in self.nodes:
161163
self.wait_for_instantlock(rawtx5_txid, node)

test/functional/feature_llmq_is_retroactive.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@ def set_test_params(self):
2424
# -whitelist is needed to avoid the trickling logic on node0
2525
self.set_dash_test_params(5, 4, [["-whitelist=127.0.0.1"], [], [], [], ["-minrelaytxfee=0.001"]])
2626

27+
# random delay before tx is actually send by network could take up to 30 seconds
28+
def wait_for_tx(self, txid, node, expected=True, timeout=60):
29+
def check_tx():
30+
try:
31+
return node.getrawtransaction(txid)
32+
except:
33+
return False
34+
if self.wait_until(check_tx, timeout=timeout, do_assert=expected) and not expected:
35+
raise AssertionError("waiting unexpectedly succeeded")
36+
2737
def run_test(self):
2838
self.nodes[0].sporkupdate("SPORK_17_QUORUM_DKG_ENABLED", 0)
2939
# Turn mempool IS signing off
@@ -39,6 +49,7 @@ def run_test(self):
3949
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
4050
# 3 nodes should be enough to create an IS lock even if nodes 4 and 5 (which have no tx itself)
4151
# are the only "neighbours" in intra-quorum connections for one of them.
52+
self.bump_mocktime(30)
4253
self.wait_for_instantlock(txid, self.nodes[0], False, 5)
4354
# Have to disable ChainLocks to avoid signing a block with a "safe" tx too early
4455
self.nodes[0].sporkupdate("SPORK_19_CHAINLOCKS_ENABLED", 4000000000)
@@ -59,8 +70,8 @@ def run_test(self):
5970
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
6071
# 3 nodes should be enough to create an IS lock even if nodes 4 and 5 (which have no tx itself)
6172
# are the only "neighbours" in intra-quorum connections for one of them.
73+
self.bump_mocktime(30)
6274
self.wait_for_instantlock(txid, self.nodes[0])
63-
self.bump_mocktime(1)
6475
block = self.generate(self.nodes[0], 1, sync_fun=self.no_op)[0]
6576
self.wait_for_chainlocked_block_all_nodes(block)
6677

@@ -69,6 +80,7 @@ def run_test(self):
6980
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
7081
# Make sure nodes 1 and 2 received the TX before we continue,
7182
# otherwise it might announce the TX to node 3 when reconnecting
83+
self.bump_mocktime(30)
7284
self.wait_for_tx(txid, self.nodes[1])
7385
self.wait_for_tx(txid, self.nodes[2])
7486
self.reconnect_isolated_node(3, 0)
@@ -101,6 +113,7 @@ def run_test(self):
101113
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
102114
# Make sure nodes 1 and 2 received the TX before we continue,
103115
# otherwise it might announce the TX to node 3 when reconnecting
116+
self.bump_mocktime(30)
104117
self.wait_for_tx(txid, self.nodes[1])
105118
self.wait_for_tx(txid, self.nodes[2])
106119
self.reconnect_isolated_node(3, 0)
@@ -139,6 +152,7 @@ def test_all_nodes_session_timeout(self, do_cycle_llmqs):
139152
txid = self.nodes[0].sendrawtransaction(rawtx)
140153
txid = self.nodes[3].sendrawtransaction(rawtx)
141154
# Make sure nodes 1 and 2 received the TX before we continue
155+
self.bump_mocktime(30)
142156
self.wait_for_tx(txid, self.nodes[1])
143157
self.wait_for_tx(txid, self.nodes[2])
144158
# Make sure signing is done on nodes 1 and 2 (it's async)
@@ -178,12 +192,13 @@ def test_single_node_session_timeout(self, do_cycle_llmqs):
178192
self.wait_for_mnauth(self.nodes[3], 2)
179193
self.nodes[0].sendrawtransaction(rawtx)
180194
# Make sure nodes 1 and 2 received the TX
195+
self.bump_mocktime(30)
181196
self.wait_for_tx(txid, self.nodes[1])
182197
self.wait_for_tx(txid, self.nodes[2])
198+
self.bump_mocktime(30)
183199
# Make sure signing is done on nodes 1 and 2 (it's async)
184-
time.sleep(5)
185200
# node 3 fully reconnected but the signing session is already timed out on it, so no IS lock
186-
self.wait_for_instantlock(txid, self.nodes[0], False, 1)
201+
self.wait_for_instantlock(txid, self.nodes[0], False, 5)
187202
if do_cycle_llmqs:
188203
self.cycle_llmqs()
189204
self.wait_for_instantlock(txid, self.nodes[0], False, 5)

test/functional/feature_llmq_singlenode.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ def run_test(self):
104104

105105
self.log.info("Send funds and wait InstantSend lock")
106106
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
107+
self.bump_mocktime(30)
107108
self.wait_for_instantlock(txid, self.nodes[0])
108109

109110
self.log.info("Test various options to sign messages with nodes")
@@ -181,6 +182,7 @@ def run_test(self):
181182
self.log.info(f"Chainlock on block: {block_hash} is expecting")
182183
self.wait_for_best_chainlock(self.nodes[0], block_hash)
183184
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
185+
self.bump_mocktime(30)
184186
self.log.info(f"InstantSend lock on tx: {txid} is expecting")
185187
self.wait_for_instantlock(txid, self.nodes[0])
186188

test/functional/feature_notifications.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,11 @@ def run_test(self):
132132
tx_count = 10
133133
for _ in range(tx_count):
134134
txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1)
135-
self.wait_for_instantlock(txid, self.nodes[1])
135+
self.bump_mocktime(30)
136+
self.wait_for_instantlock(txid, self.nodes[0])
136137

137138
# wait at most 10 seconds for expected number of files before reading the content
139+
self.bump_mocktime(30)
138140
self.wait_until(lambda: len(os.listdir(self.instantsendnotify_dir)) == tx_count, timeout=10)
139141

140142
# directory content should equal the generated transaction hashes

test/functional/interface_zmq_dash.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ def test_instantsend_publishers(self):
293293
assert_equal(['None'], self.nodes[0].getislocks([rpc_raw_tx_1['txid']]))
294294
# Send the first transaction and wait for the InstantLock
295295
rpc_raw_tx_1_hash = self.nodes[0].sendrawtransaction(rpc_raw_tx_1['hex'])
296+
self.bump_mocktime(30)
296297
self.wait_for_instantlock(rpc_raw_tx_1_hash, self.nodes[0])
297298
# Validate hashtxlock
298299
zmq_tx_lock_hash = self.subscribers[ZMQPublisher.hash_tx_lock].receive().read(32).hex()
@@ -345,6 +346,7 @@ def test_instantsend_publishers(self):
345346
pass
346347
# Now send the tx itself
347348
self.test_node.send_tx(from_hex(msg_tx(),rpc_raw_tx_3['hex']))
349+
self.bump_mocktime(30)
348350
self.wait_for_instantlock(rpc_raw_tx_3['txid'], self.nodes[0])
349351
# Validate hashtxlock
350352
zmq_tx_lock_hash = self.subscribers[ZMQPublisher.hash_tx_lock].receive().read(32).hex()
@@ -378,6 +380,7 @@ def test_governance_publishers(self):
378380
}
379381
proposal_hex = ''.join(format(x, '02x') for x in json.dumps(proposal_data).encode())
380382
collateral = self.nodes[0].gobject("prepare", "0", proposal_rev, proposal_time, proposal_hex)
383+
self.bump_mocktime(30)
381384
self.wait_for_instantlock(collateral, self.nodes[0])
382385
self.generate(self.nodes[0], 6, sync_fun=lambda: self.sync_blocks())
383386
rpc_proposal_hash = self.nodes[0].gobject("submit", "0", proposal_rev, proposal_time, proposal_hex, collateral)

test/functional/p2p_instantsend.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ def test_block_doublespend(self):
4242
# feed the sender with some balance
4343
sender_addr = sender.getnewaddress()
4444
is_id = self.nodes[0].sendtoaddress(sender_addr, 1)
45+
self.bump_mocktime(30)
4546
for node in self.nodes:
4647
self.wait_for_instantlock(is_id, node)
47-
self.bump_mocktime(1)
4848
self.generate(self.nodes[0], 2)
4949

5050
# create doublespending transaction, but don't relay it
@@ -58,6 +58,7 @@ def test_block_doublespend(self):
5858
connected_nodes = self.nodes.copy()
5959
del connected_nodes[self.isolated_idx]
6060
self.sync_mempools(connected_nodes)
61+
self.bump_mocktime(30)
6162
for node in connected_nodes:
6263
self.wait_for_instantlock(is_id, node)
6364
# send doublespend transaction to isolated node
@@ -101,9 +102,9 @@ def test_mempool_doublespend(self):
101102
# feed the sender with some balance
102103
sender_addr = sender.getnewaddress()
103104
is_id = self.nodes[0].sendtoaddress(sender_addr, 1)
105+
self.bump_mocktime(30)
104106
for node in self.nodes:
105107
self.wait_for_instantlock(is_id, node)
106-
self.bump_mocktime(1)
107108
self.generate(self.nodes[0], 2)
108109

109110
# create doublespending transaction, but don't relay it
@@ -124,18 +125,19 @@ def test_mempool_doublespend(self):
124125
receiver_addr = receiver.getnewaddress()
125126
is_id = sender.sendtoaddress(receiver_addr, 0.9)
126127
# wait for the transaction to propagate
128+
self.bump_mocktime(30)
127129
self.sync_mempools()
128130
for node in self.nodes:
129131
self.wait_for_instantlock(is_id, node)
130132
assert dblspnd_txid not in set(isolated.getrawmempool())
131133
# send coins back to the controller node without waiting for confirmations
132134
sentback_id = receiver.sendtoaddress(self.nodes[0].getnewaddress(), 0.9, "", "", True)
135+
self.bump_mocktime(30)
133136
self.sync_mempools()
134137
for node in self.nodes:
135138
self.wait_for_instantlock(sentback_id, node)
136139
assert_equal(receiver.getwalletinfo()["balance"], 0)
137140
# mine more blocks
138-
self.bump_mocktime(1)
139141
self.generate(self.nodes[0], 2)
140142

141143
if __name__ == '__main__':

test/functional/rpc_verifyislock.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def run_test(self):
3838
self.generate(self.nodes[0], 8, sync_fun=self.sync_blocks())
3939

4040
txid = node.sendtoaddress(node.getnewaddress(), 1)
41+
self.bump_mocktime(30)
4142
self.wait_for_instantlock(txid, node)
4243

4344
request_id = self.get_request_id(self.nodes[0].getrawtransaction(txid))

test/functional/test_framework/test_framework.py

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1898,16 +1898,6 @@ def make_change(from_node, amount_in, amount_out, fee):
18981898
ret = {**decoded, **ret}
18991899
return ret
19001900

1901-
def wait_for_tx(self, txid, node, expected=True, timeout=60):
1902-
def check_tx():
1903-
try:
1904-
self.bump_mocktime(1)
1905-
return node.getrawtransaction(txid)
1906-
except:
1907-
return False
1908-
if self.wait_until(check_tx, timeout=timeout, sleep=1, do_assert=expected) and not expected:
1909-
raise AssertionError("waiting unexpectedly succeeded")
1910-
19111901
def create_isdlock(self, hextx):
19121902
tx = tx_from_hex(hextx)
19131903
tx.rehash()
@@ -1930,15 +1920,19 @@ def create_isdlock(self, hextx):
19301920

19311921
return isdlock
19321922

1923+
# due to privacy reasons random delay is used before sending transaction by network
1924+
# most times is just 2-5 seconds, but once in 1000 it's up to 1000 seconds.
1925+
# it's recommended to bump mocktime for 30 seconds before wait_for_instantlock
19331926
def wait_for_instantlock(self, txid, node, expected=True, timeout=60):
1927+
19341928
def check_instantlock():
1935-
self.bump_mocktime(1)
19361929
try:
19371930
return node.getrawtransaction(txid, True)["instantlock"]
19381931
except:
19391932
return False
1933+
19401934
self.log.info(f"Expecting InstantLock for {txid}")
1941-
if self.wait_until(check_instantlock, timeout=timeout, sleep=1, do_assert=expected) and not expected:
1935+
if self.wait_until(check_instantlock, timeout=timeout, do_assert=expected) and not expected:
19421936
raise AssertionError("waiting unexpectedly succeeded")
19431937

19441938
def wait_for_chainlocked_block(self, node, block_hash, expected=True, timeout=15):
@@ -1949,15 +1943,15 @@ def check_chainlocked_block():
19491943
except:
19501944
return False
19511945
self.log.info(f"Expecting ChainLock for {block_hash}")
1952-
if self.wait_until(check_chainlocked_block, timeout=timeout, sleep=0.1, do_assert=expected) and not expected:
1946+
if self.wait_until(check_chainlocked_block, timeout=timeout, do_assert=expected) and not expected:
19531947
raise AssertionError("waiting unexpectedly succeeded")
19541948

19551949
def wait_for_chainlocked_block_all_nodes(self, block_hash, timeout=15, expected=True):
19561950
for node in self.nodes:
19571951
self.wait_for_chainlocked_block(node, block_hash, expected=expected, timeout=timeout)
19581952

19591953
def wait_for_best_chainlock(self, node, block_hash, timeout=15):
1960-
self.wait_until(lambda: node.getbestchainlock()["blockhash"] == block_hash, timeout=timeout, sleep=0.1)
1954+
self.wait_until(lambda: node.getbestchainlock()["blockhash"] == block_hash, timeout=timeout)
19611955

19621956
def wait_for_sporks_same(self, timeout=30):
19631957
def check_sporks_same():

0 commit comments

Comments
 (0)