Skip to content

Commit 38649da

Browse files
MarcoFalkePastaPastaPasta
authored andcommitted
Merge bitcoin#22520: test: improve rpc_blockchain.py tests and assert on time and mediantime
ef5e930 test: update logging and docstring in rpc_blockchain.py (Jon Atack) d548dc7 test: replace magic values by constants in rpc_blockchain.py (Jon Atack) 78c3610 test: assert on mediantime in getblockheader and getblockchaininfo (Jon Atack) 0a9129c test: assert on the value of getblockchaininfo#time (Jon Atack) Pull request description: Follow-up to bitcoin#22407 improving test coverage per bitcoin#22407 (review). ACKs for top commit: tryphe: untested ACK ef5e930 Tree-SHA512: f746d56f430331bc6a2ea7ecd27b21b06275927966aacf1f1127d8d5fdfd930583cabe72e23df3adb2e005da904fc05dc573b8e5eaa2f86e0e193b89a17a5734
1 parent 61f9d96 commit 38649da

File tree

1 file changed

+45
-33
lines changed

1 file changed

+45
-33
lines changed

test/functional/rpc_blockchain.py

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66
77
Test the following RPCs:
88
- getblockchaininfo
9+
- getchaintxstats
910
- gettxoutsetinfo
10-
- getdifficulty
11-
- getbestblockhash
12-
- getblockhash
1311
- getblockheader
14-
- getchaintxstats
12+
- getdifficulty
1513
- getnetworkhashps
14+
- waitforblockheight
15+
- getblock
16+
- getblockhash
17+
- getbestblockhash
1618
- verifychain
1719
1820
Tests correspond to code in rpc/blockchain.cpp.
@@ -49,6 +51,12 @@
4951
from test_framework.wallet import MiniWallet
5052

5153

54+
HEIGHT = 200 # blocks mined
55+
TIME_RANGE_STEP = 156 # ten-minute steps
56+
TIME_RANGE_MTP = TIME_GENESIS_BLOCK + (HEIGHT - 6) * TIME_RANGE_STEP
57+
TIME_RANGE_END = TIME_GENESIS_BLOCK + HEIGHT * TIME_RANGE_STEP
58+
59+
5260
class BlockchainTest(BitcoinTestFramework):
5361
def set_test_params(self):
5462
self.setup_clean_chain = True
@@ -72,9 +80,9 @@ def run_test(self):
7280
assert self.nodes[0].verifychain(4, 0)
7381

7482
def mine_chain(self):
75-
self.log.info('Create some old blocks')
83+
self.log.info(f"Generate {HEIGHT} blocks after the genesis block in 156 sec")
7684
address = self.nodes[0].get_deterministic_priv_key().address
77-
for t in range(TIME_GENESIS_BLOCK, TIME_GENESIS_BLOCK + 200 * 156, 156):
85+
for t in range(TIME_GENESIS_BLOCK, TIME_RANGE_END, TIME_RANGE_STEP):
7886
# 156 sec steps from genesis block time
7987
set_node_times(self.nodes, t)
8088
self.nodes[0].generatetoaddress(1, address)
@@ -101,7 +109,8 @@ def _test_getblockchaininfo(self):
101109
]
102110
res = self.nodes[0].getblockchaininfo()
103111

104-
assert isinstance(res['time'], int)
112+
assert_equal(res['time'], TIME_RANGE_END - TIME_RANGE_STEP)
113+
assert_equal(res['mediantime'], TIME_RANGE_MTP)
105114

106115
# result should have these additional pruning keys if manual pruning is enabled
107116
assert_equal(sorted(res.keys()), sorted(['pruneheight', 'automatic_pruning'] + keys))
@@ -177,8 +186,8 @@ def _test_getblockchaininfo(self):
177186
'statistics': {
178187
'period': 144,
179188
'threshold': 108,
180-
'elapsed': 57,
181-
'count': 57,
189+
'elapsed': HEIGHT - 143,
190+
'count': HEIGHT - 143,
182191
'possible': True,
183192
},
184193
'min_activation_height': 0,
@@ -203,33 +212,33 @@ def _test_getchaintxstats(self):
203212
assert_raises_rpc_error(-8, "blockhash must be of length 64 (not 1, for '0')", self.nodes[0].getchaintxstats, blockhash='0')
204213
assert_raises_rpc_error(-8, "blockhash must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')", self.nodes[0].getchaintxstats, blockhash='ZZZ0000000000000000000000000000000000000000000000000000000000000')
205214
assert_raises_rpc_error(-5, "Block not found", self.nodes[0].getchaintxstats, blockhash='0000000000000000000000000000000000000000000000000000000000000000')
206-
blockhash = self.nodes[0].getblockhash(200)
215+
blockhash = self.nodes[0].getblockhash(HEIGHT)
207216
self.nodes[0].invalidateblock(blockhash)
208217
assert_raises_rpc_error(-8, "Block is not in main chain", self.nodes[0].getchaintxstats, blockhash=blockhash)
209218
self.nodes[0].reconsiderblock(blockhash)
210219

211220
chaintxstats = self.nodes[0].getchaintxstats(nblocks=1)
212221
# 200 txs plus genesis tx
213-
assert_equal(chaintxstats['txcount'], 201)
222+
assert_equal(chaintxstats['txcount'], HEIGHT + 1)
214223
# tx rate should be 1 per ~2.6 minutes (156 seconds), or 1/156
215224
# we have to round because of binary math
216-
assert_equal(round(chaintxstats['txrate'] * 156, 10), Decimal(1))
225+
assert_equal(round(chaintxstats['txrate'] * TIME_RANGE_STEP, 10), Decimal(1))
217226

218227
b1_hash = self.nodes[0].getblockhash(1)
219228
b1 = self.nodes[0].getblock(b1_hash)
220-
b200_hash = self.nodes[0].getblockhash(200)
229+
b200_hash = self.nodes[0].getblockhash(HEIGHT)
221230
b200 = self.nodes[0].getblock(b200_hash)
222231
time_diff = b200['mediantime'] - b1['mediantime']
223232

224233
chaintxstats = self.nodes[0].getchaintxstats()
225234
assert_equal(chaintxstats['time'], b200['time'])
226-
assert_equal(chaintxstats['txcount'], 201)
235+
assert_equal(chaintxstats['txcount'], HEIGHT + 1)
227236
assert_equal(chaintxstats['window_final_block_hash'], b200_hash)
228-
assert_equal(chaintxstats['window_final_block_height'], 200)
229-
assert_equal(chaintxstats['window_block_count'], 199)
230-
assert_equal(chaintxstats['window_tx_count'], 199)
237+
assert_equal(chaintxstats['window_final_block_height'], HEIGHT )
238+
assert_equal(chaintxstats['window_block_count'], HEIGHT - 1)
239+
assert_equal(chaintxstats['window_tx_count'], HEIGHT - 1)
231240
assert_equal(chaintxstats['window_interval'], time_diff)
232-
assert_equal(round(chaintxstats['txrate'] * time_diff, 10), Decimal(199))
241+
assert_equal(round(chaintxstats['txrate'] * time_diff, 10), Decimal(HEIGHT - 1))
233242

234243
chaintxstats = self.nodes[0].getchaintxstats(blockhash=b1_hash)
235244
assert_equal(chaintxstats['time'], b1['time'])
@@ -246,17 +255,17 @@ def _test_gettxoutsetinfo(self):
246255
res = node.gettxoutsetinfo()
247256

248257
assert_equal(res['total_amount'], Decimal('98214.28571450'))
249-
assert_equal(res['transactions'], 200)
250-
assert_equal(res['height'], 200)
251-
assert_equal(res['txouts'], 200)
258+
assert_equal(res['transactions'], HEIGHT)
259+
assert_equal(res['height'], HEIGHT)
260+
assert_equal(res['txouts'], HEIGHT)
252261
assert_equal(res['bogosize'], 15000),
253262
size = res['disk_size']
254263
assert size > 6400
255264
assert size < 64000
256265
assert_equal(len(res['bestblock']), 64)
257266
assert_equal(len(res['hash_serialized_2']), 64)
258267

259-
self.log.info("Test that gettxoutsetinfo() works for blockchain with just the genesis block")
268+
self.log.info("Test gettxoutsetinfo works for blockchain with just the genesis block")
260269
b1hash = node.getblockhash(1)
261270
node.invalidateblock(b1hash)
262271

@@ -269,7 +278,7 @@ def _test_gettxoutsetinfo(self):
269278
assert_equal(res2['bestblock'], node.getblockhash(0))
270279
assert_equal(len(res2['hash_serialized_2']), 64)
271280

272-
self.log.info("Test that gettxoutsetinfo() returns the same result after invalidate/reconsider block")
281+
self.log.info("Test gettxoutsetinfo returns the same result after invalidate/reconsider block")
273282
node.reconsiderblock(b1hash)
274283

275284
res3 = node.gettxoutsetinfo()
@@ -278,7 +287,7 @@ def _test_gettxoutsetinfo(self):
278287
del res['disk_size'], res3['disk_size']
279288
assert_equal(res, res3)
280289

281-
self.log.info("Test hash_type option for gettxoutsetinfo()")
290+
self.log.info("Test gettxoutsetinfo hash_type option")
282291
# Adding hash_type 'hash_serialized_2', which is the default, should
283292
# not change the result.
284293
res4 = node.gettxoutsetinfo(hash_type='hash_serialized_2')
@@ -302,18 +311,19 @@ def _test_gettxoutsetinfo(self):
302311
assert_raises_rpc_error(-8, "foohash is not a valid hash_type", node.gettxoutsetinfo, "foohash")
303312

304313
def _test_getblockheader(self):
314+
self.log.info("Test getblockheader")
305315
node = self.nodes[0]
306316

307317
assert_raises_rpc_error(-8, "hash must be of length 64 (not 8, for 'nonsense')", node.getblockheader, "nonsense")
308318
assert_raises_rpc_error(-8, "hash must be hexadecimal string (not 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844')", node.getblockheader, "ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844")
309319
assert_raises_rpc_error(-5, "Block not found", node.getblockheader, "0cf7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844")
310320

311321
besthash = node.getbestblockhash()
312-
secondbesthash = node.getblockhash(199)
322+
secondbesthash = node.getblockhash(HEIGHT - 1)
313323
header = node.getblockheader(blockhash=besthash)
314324

315325
assert_equal(header['hash'], besthash)
316-
assert_equal(header['height'], 200)
326+
assert_equal(header['height'], HEIGHT)
317327
assert_equal(header['confirmations'], 1)
318328
assert_equal(header['previousblockhash'], secondbesthash)
319329
assert_is_hex_string(header['chainwork'])
@@ -323,7 +333,7 @@ def _test_getblockheader(self):
323333
assert_is_hash_string(header['merkleroot'])
324334
assert_is_hash_string(header['bits'], length=None)
325335
assert isinstance(header['time'], int)
326-
assert isinstance(header['mediantime'], int)
336+
assert_equal(header['mediantime'], TIME_RANGE_MTP)
327337
assert isinstance(header['nonce'], int)
328338
assert isinstance(header['version'], int)
329339
assert isinstance(int(header['versionHex'], 16), int)
@@ -341,20 +351,22 @@ def _test_getblockheader(self):
341351
assert 'nextblockhash' not in node.getblockheader(node.getbestblockhash())
342352

343353
def _test_getdifficulty(self):
354+
self.log.info("Test getdifficulty")
344355
difficulty = self.nodes[0].getdifficulty()
345356
# 1 hash in 2 should be valid, so difficulty should be 1/2**31
346357
# binary => decimal => binary math is why we do this check
347358
assert abs(difficulty * 2**31 - 1) < 0.0001
348359

349360
def _test_getnetworkhashps(self):
361+
self.log.info("Test getnetworkhashps")
350362
hashes_per_second = self.nodes[0].getnetworkhashps()
351363
# This should be 2 hashes every 2.6 minutes (156 seconds) or 1/78
352364
assert abs(hashes_per_second * 78 - 1) < 0.0001
353365

354366
def _test_stopatheight(self):
355-
assert_equal(self.nodes[0].getblockcount(), 200)
367+
assert_equal(self.nodes[0].getblockcount(), HEIGHT)
356368
self.nodes[0].generatetoaddress(6, self.nodes[0].get_deterministic_priv_key().address)
357-
assert_equal(self.nodes[0].getblockcount(), 206)
369+
assert_equal(self.nodes[0].getblockcount(), HEIGHT + 6)
358370
self.log.debug('Node should not stop at this height')
359371
assert_raises(subprocess.TimeoutExpired, lambda: self.nodes[0].process.wait(timeout=3))
360372
try:
@@ -364,7 +376,7 @@ def _test_stopatheight(self):
364376
self.log.debug('Node should stop at this height...')
365377
self.nodes[0].wait_until_stopped()
366378
self.start_node(0, ['-txindex=0'])
367-
assert_equal(self.nodes[0].getblockcount(), 207)
379+
assert_equal(self.nodes[0].getblockcount(), HEIGHT + 7)
368380

369381
def _test_waitforblockheight(self):
370382
self.log.info("Test waitforblockheight")
@@ -417,17 +429,17 @@ def _test_getblock(self):
417429
miniwallet.send_self_transfer(fee_rate=fee_per_kb, from_node=node)
418430
blockhash = node.generate(1)[0]
419431

420-
self.log.info("Test that getblock with verbosity 1 doesn't include fee")
432+
self.log.info("Test getblock with verbosity 1 doesn't include fee")
421433
block = node.getblock(blockhash, 1)
422434
assert 'fee' not in block['tx'][1]
423435

424-
self.log.info('Test that getblock with verbosity 2 includes expected fee')
436+
self.log.info('Test getblock with verbosity 2 includes expected fee')
425437
block = node.getblock(blockhash, 2)
426438
tx = block['tx'][1]
427439
assert 'fee' in tx
428440
assert_equal(tx['fee'], tx['size'] * fee_per_byte)
429441

430-
self.log.info("Test that getblock with verbosity 2 still works with pruned Undo data")
442+
self.log.info("Test getblock with verbosity 2 still works with pruned Undo data")
431443
datadir = get_datadir_path(self.options.tmpdir, 0)
432444

433445
def move_block_file(old, new):

0 commit comments

Comments
 (0)