66import logging
77import os
88import random
9+ import re
910import shutil
1011import signal
1112import sqlite3
@@ -38,7 +39,7 @@ class TestLeadershipSchedule:
3839 @allure .link (helpers .get_vcs_link ())
3940 @pytest .mark .dbsync
4041 @pytest .mark .parametrize ("for_epoch" , ("current" , "next" ))
41- def test_pool_blocks (
42+ def test_pool_blocks ( # noqa: C901
4243 self ,
4344 cluster_manager : cluster_management .ClusterManager ,
4445 cluster_use_pool : tp .Tuple [clusterlib .ClusterLib , str ],
@@ -48,12 +49,10 @@ def test_pool_blocks(
4849
4950 * query leadership schedule for selected pool for current epoch or next epoch
5051 * wait for epoch that comes after the queried epoch
51- * check in log files that the blocks were minted in expected slots
52- * if db-sync is available:
53-
54- - get info about minted blocks in queried epoch for the selected pool
55- - compare leadership schedule with blocks that were actually minted
56- - compare db-sync records with ledger state dump
52+ * get info about minted blocks in queried epoch for the selected pool
53+ * compare leadership schedule with blocks that were actually minted
54+ * compare log records with ledger state dump
55+ * (optional) check minted blocks in db-sync
5756 """
5857 # pylint: disable=unused-argument
5958 cluster , pool_name = cluster_use_pool
@@ -62,10 +61,10 @@ def test_pool_blocks(
6261 pool_rec = cluster_manager .cache .addrs_data [pool_name ]
6362 pool_id = cluster .g_stake_pool .get_stake_pool_id (pool_rec ["cold_key_pair" ].vkey_file )
6463
65- state_dir = cluster_nodes . get_cluster_env (). state_dir
66- pool_log_fname = f"{ pool_name .replace ('node-' , '' )} .stdout"
67- pool_log = state_dir / pool_log_fname
68- seek_offsets = { str ( pool_log ): helpers .get_eof_offset (pool_log )}
64+ pool_log = (
65+ cluster_nodes . get_cluster_env (). state_dir / f"{ pool_name .replace ('node-' , '' )} .stdout"
66+ )
67+ seek_offset = helpers .get_eof_offset (pool_log )
6968 timestamp = time .time ()
7069
7170 if for_epoch == "current" :
@@ -90,27 +89,66 @@ def test_pool_blocks(
9089 )
9190 slots_when_scheduled = {r .slot_no for r in leadership_schedule }
9291
93- expected_msgs = [
94- (pool_log_fname , rf'TraceForgedBlock"\),\("slot",Number { s } ' )
95- for s in slots_when_scheduled
96- ]
97-
9892 # Wait for epoch that comes after the queried epoch
99- cluster .wait_for_epoch (epoch_no = queried_epoch + 1 )
93+ cluster .wait_for_epoch (epoch_no = queried_epoch + 1 , padding_seconds = 10 )
94+
95+ # Get number of minted blocks from ledger
96+ ledger_state = clusterlib_utils .get_ledger_state (cluster_obj = cluster )
97+ clusterlib_utils .save_ledger_state (
98+ cluster_obj = cluster ,
99+ state_name = temp_template ,
100+ ledger_state = ledger_state ,
101+ )
102+ blocks_before : tp .Dict [str , int ] = ledger_state ["blocksBefore" ]
103+ pool_id_dec = helpers .decode_bech32 (pool_id )
104+ minted_blocks_ledger = blocks_before .get (pool_id_dec ) or 0
100105
101106 errors : tp .List [str ] = []
102107
103- log_msgs_errors = logfiles .check_msgs_presence_in_logs (
104- regex_pairs = expected_msgs ,
105- seek_offsets = seek_offsets ,
106- state_dir = state_dir ,
107- timestamp = timestamp ,
108- )
109- if len (log_msgs_errors ) > len (leadership_schedule ) // 2 :
110- log_msgs_errors_joined = "\n " .join (log_msgs_errors )
111- errors .append (f"Lot of slots missed: \n { log_msgs_errors_joined } " )
108+ def _check_logs () -> None :
109+ # Get info about minted blocks in queried epoch for the selected pool
110+ minted_lines = logfiles .find_msgs_in_logs (
111+ regex = '"TraceForgedBlock"' ,
112+ logfile = pool_log ,
113+ seek_offset = seek_offset ,
114+ timestamp = timestamp ,
115+ )
116+ tip = cluster .g_query .get_tip ()
117+ last_slot_queried_epoch = int (tip ["slot" ]) - int (tip ["slotInEpoch" ] - 1 )
118+ first_slot_queried_epoch = (
119+ last_slot_queried_epoch - int (cluster .genesis ["epochLength" ]) + 1
120+ )
121+ slots_pattern = re .compile (r'"slot",Number (\d+)\.0' )
122+ slots_when_minted = {
123+ s
124+ for m in minted_lines
125+ if (o := slots_pattern .search (m )) is not None
126+ and first_slot_queried_epoch <= (s := int (o .group (1 ))) <= last_slot_queried_epoch
127+ }
112128
113- if configuration .HAS_DBSYNC :
129+ # Compare leadership schedule with blocks that were actually minted
130+ difference_scheduled = slots_when_minted .difference (slots_when_scheduled )
131+ if difference_scheduled :
132+ errors .append (
133+ f"Some blocks were minted in other slots than scheduled: { difference_scheduled } "
134+ )
135+
136+ difference_minted = slots_when_scheduled .difference (slots_when_minted )
137+ if len (difference_minted ) > len (leadership_schedule ) // 5 :
138+ errors .append (f"Lot of slots missed: { difference_minted } " )
139+
140+ # Compare log records with ledger state dump
141+ minted_blocks_logs = len (slots_when_minted )
142+ # Some minted block may not be adopted, and so the total number of adopted blocks
143+ # may be lower than the number of minted blocks.
144+ if minted_blocks_ledger > minted_blocks_logs :
145+ errors .append (
146+ "Number of minted blocks reported by ledger state "
147+ "is higher than number extracted from log file: "
148+ f"{ minted_blocks_ledger } vs { minted_blocks_logs } "
149+ )
150+
151+ def _check_dbsync () -> None :
114152 # Get info about minted blocks in queried epoch for the selected pool
115153 minted_blocks = list (
116154 dbsync_queries .query_blocks (
@@ -123,30 +161,28 @@ def test_pool_blocks(
123161 difference_scheduled = slots_when_minted .difference (slots_when_scheduled )
124162 if difference_scheduled :
125163 errors .append (
126- f"Some blocks were minted in other slots than scheduled: { difference_scheduled } "
164+ "DB-Sync: Some blocks were minted in other slots than scheduled: "
165+ f"{ difference_scheduled } "
127166 )
128167
129168 difference_minted = slots_when_scheduled .difference (slots_when_minted )
130- if len (difference_minted ) > len (leadership_schedule ) // 2 :
131- errors .append (f"Lot of slots missed: { difference_minted } " )
169+ if len (difference_minted ) > len (leadership_schedule ) // 3 :
170+ errors .append (f"DB-Sync: Lot of slots missed: { difference_minted } " )
132171
133172 # Compare db-sync records with ledger state dump
134- ledger_state = clusterlib_utils .get_ledger_state (cluster_obj = cluster )
135- clusterlib_utils .save_ledger_state (
136- cluster_obj = cluster ,
137- state_name = temp_template ,
138- ledger_state = ledger_state ,
139- )
140- blocks_before : tp .Dict [str , int ] = ledger_state ["blocksBefore" ]
141- pool_id_dec = helpers .decode_bech32 (pool_id )
142- minted_blocks_ledger = blocks_before .get (pool_id_dec ) or 0
143173 minted_blocks_db = len (slots_when_minted )
144174 if minted_blocks_ledger != minted_blocks_db :
145175 errors .append (
146- "Numbers of minted blocks reported by ledger state and db-sync don't match: "
176+ "DB-Sync: Numbers of minted blocks reported by ledger state "
177+ "and db-sync don't match: "
147178 f"{ minted_blocks_ledger } vs { minted_blocks_db } "
148179 )
149180
181+ _check_logs ()
182+
183+ if configuration .HAS_DBSYNC :
184+ _check_dbsync ()
185+
150186 if errors :
151187 # Xfail if cardano-api GH-269 is still open
152188 if (
0 commit comments