• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MinaProtocol / mina / 584

11 Sep 2025 07:15PM UTC coverage: 14.436% (-19.8%) from 34.248%
584

push

buildkite

web-flow
Merge pull request #17778 from MinaProtocol/dkijania/publish_mina_logproc

[CI] Publish logproc in nightly

9561 of 66228 relevant lines covered (14.44%)

279.58 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.73
/src/app/replayer/sql.ml
1
(* sql.ml -- (Postgresql) SQL queries for replayer *)
2

3
open Core_kernel
4

5
module Block_info = struct
6
  type t =
25✔
7
    { id : int
8
    ; global_slot_since_genesis : int64
9
    ; state_hash : string
10
    ; ledger_hash : string
11
    ; snarked_ledger_hash_id : int
12
    }
13
  [@@deriving hlist]
14

15
  let typ =
16
    Mina_caqti.Type_spec.custom_type ~to_hlist ~of_hlist
1✔
17
      Caqti_type.[ int; int64; string; string; int ]
18

19
  (* find all blocks, working back from block with given state hash *)
20
  let query =
21
    Mina_caqti.collect_req
1✔
22
      Caqti_type.(t2 string int64)
1✔
23
      typ
24
      {sql| WITH RECURSIVE chain AS (
25
              SELECT id,parent_id,global_slot_since_genesis,state_hash,ledger_hash, snarked_ledger_hash_id FROM blocks b                                                                                                                                                           WHERE b.state_hash = $1
26

27
              UNION ALL
28

29
              SELECT b.id,b.parent_id,b.global_slot_since_genesis,b.state_hash,b.ledger_hash, b.snarked_ledger_hash_id FROM blocks b
30

31
              INNER JOIN chain
32

33
              ON b.id = chain.parent_id AND chain.id <> chain.parent_id                                                                                                                                                                                 )
34

35
           SELECT id,global_slot_since_genesis,state_hash,ledger_hash, snarked_ledger_hash_id FROM chain c                                                                                                                                                                      WHERE c.global_slot_since_genesis >= $2                                                                                                                                                                                                 |sql}
36

37
  let run (module Conn : Mina_caqti.CONNECTION) ~state_hash ~start_slot =
38
    Conn.collect_list query (state_hash, start_slot)
1✔
39
end
40

41
(* build query to find all blocks back to genesis block, starting with the block containing the
42
   specified state hash; for each such block, find ids of all (user or internal) commands in that block
43
*)
44

45
let find_command_ids_query s =
46
  sprintf
3✔
47
    {sql| WITH RECURSIVE chain AS (
48

49
            SELECT id,parent_id,global_slot_since_genesis FROM blocks b
50
            WHERE b.state_hash = $1
51

52
            UNION ALL
53

54
            SELECT b.id,b.parent_id,b.global_slot_since_genesis FROM blocks b
55

56
            INNER JOIN chain
57

58
            ON b.id = chain.parent_id AND chain.id <> chain.parent_id
59
          )
60

61
          SELECT DISTINCT %s_command_id FROM chain c
62

63
          INNER JOIN blocks_%s_commands bc
64

65
          ON bc.block_id = c.id
66

67
          WHERE c.global_slot_since_genesis >= $2
68

69
     |sql}
70
    s s
71

72
module Block = struct
73
  let state_hash_query =
74
    Mina_caqti.find_req Caqti_type.int Caqti_type.string
1✔
75
      {sql| SELECT state_hash FROM blocks
76
            WHERE id = ?
77
      |sql}
78

79
  let get_state_hash (module Conn : Mina_caqti.CONNECTION) id =
80
    Conn.find state_hash_query id
1,328✔
81

82
  let parent_id_query =
83
    Mina_caqti.find_req Caqti_type.int Caqti_type.int
1✔
84
      {sql| SELECT parent_id FROM blocks
85
            WHERE id = ?
86
      |sql}
87

88
  let get_parent_id (module Conn : Mina_caqti.CONNECTION) id =
89
    Conn.find parent_id_query id
24✔
90

91
  let unparented_query =
92
    Mina_caqti.collect_req Caqti_type.unit Caqti_type.int
1✔
93
      {sql| SELECT id FROM blocks
94
            WHERE parent_id IS NULL
95
      |sql}
96

97
  let get_unparented (module Conn : Mina_caqti.CONNECTION) () =
98
    Conn.collect_list unparented_query ()
×
99

100
  let get_height_query =
101
    Mina_caqti.find_req Caqti_type.int Caqti_type.int64
1✔
102
      {sql| SELECT height FROM blocks WHERE id = $1 |sql}
103

104
  let get_height (module Conn : Mina_caqti.CONNECTION) ~block_id =
105
    Conn.find get_height_query block_id
×
106

107
  let max_slot_query =
108
    Mina_caqti.find_req Caqti_type.unit Caqti_type.int64
1✔
109
      {sql| SELECT MAX(global_slot_since_genesis) FROM blocks |sql}
110

111
  let get_max_slot (module Conn : Mina_caqti.CONNECTION) () =
112
    Conn.find max_slot_query ()
×
113

114
  let max_canonical_slot_query =
115
    Mina_caqti.find_req Caqti_type.unit Caqti_type.int64
1✔
116
      {sql| SELECT MAX(global_slot_since_genesis) FROM blocks
117
            WHERE chain_status = 'canonical'
118
      |sql}
119

120
  let get_max_canonical_slot (module Conn : Mina_caqti.CONNECTION) () =
121
    Conn.find max_canonical_slot_query ()
1✔
122

123
  let next_slot_query =
124
    Mina_caqti.find_opt_req Caqti_type.int64 Caqti_type.int64
1✔
125
      {sql| SELECT global_slot_since_genesis FROM blocks
126
            WHERE global_slot_since_genesis >= $1
127
            AND chain_status <> 'orphaned'
128
            ORDER BY global_slot_since_genesis ASC
129
            LIMIT 1
130
      |sql}
131

132
  let get_next_slot (module Conn : Mina_caqti.CONNECTION) slot =
133
    Conn.find_opt next_slot_query slot
1✔
134

135
  let state_hashes_by_slot_query =
136
    Mina_caqti.collect_req Caqti_type.int64 Caqti_type.string
1✔
137
      {sql| SELECT state_hash FROM blocks WHERE global_slot_since_genesis = $1 |sql}
138

139
  let get_state_hashes_by_slot (module Conn : Mina_caqti.CONNECTION) slot =
140
    Conn.collect_list state_hashes_by_slot_query slot
×
141

142
  (* find all blocks, working back from block with given state hash *)
143
  let chain_query =
144
    Mina_caqti.collect_req Caqti_type.string Caqti_type.string
1✔
145
      {sql| WITH RECURSIVE chain AS (
146

147
              SELECT id,parent_id FROM blocks b WHERE b.state_hash = ?
148

149
              UNION ALL
150

151
              SELECT b.id,b.parent_id FROM blocks b
152

153
              INNER JOIN chain
154

155
              ON b.id = chain.parent_id AND NOT chain.parent_id IS NULL
156
           )
157

158
           SELECT 'ok' AS found_chain FROM chain c
159

160
      |sql}
161

162
  let get_chain (module Conn : Mina_caqti.CONNECTION) state_hash =
163
    Conn.collect_list chain_query state_hash
×
164

165
  (* either the bonafide genesis block, or the most recent "linking" block
166
     at a hard fork point that has the genesis winner, that's at or before the
167
     start slot
168
  *)
169
  let genesis_snarked_ledger_query =
170
    let genesis_winner =
171
      let pk, _ = Mina_state.Consensus_state_hooks.genesis_winner in
172
      Signature_lib.Public_key.Compressed.to_base58_check pk
1✔
173
    in
174
    Mina_caqti.find_req Caqti_type.int64 Caqti_type.string
1✔
175
      (sprintf
1✔
176
         {sql| SELECT snarked_ledger_hashes.value
177
               FROM blocks
178
               INNER JOIN snarked_ledger_hashes
179
               ON snarked_ledger_hashes.id = blocks.snarked_ledger_hash_id
180
               INNER JOIN public_keys
181
               ON public_keys.id = blocks.block_winner_id
182
               WHERE public_keys.value = '%s'
183
               AND blocks.global_slot_since_genesis <= $1
184
               ORDER BY blocks.height DESC
185
               LIMIT 1
186
         |sql}
187
         genesis_winner )
188

189
  let genesis_snarked_ledger (module Conn : Mina_caqti.CONNECTION) start_slot =
190
    Conn.find genesis_snarked_ledger_query start_slot
1✔
191
end
192

193
module User_command_ids = struct
194
  let query =
195
    Mina_caqti.collect_req
1✔
196
      Caqti_type.(t2 string int64)
1✔
197
      Caqti_type.int
198
      (find_command_ids_query "user")
1✔
199

200
  let run (module Conn : Mina_caqti.CONNECTION) ~state_hash ~start_slot =
201
    Conn.collect_list query (state_hash, start_slot)
1✔
202
end
203

204
module User_command = struct
205
  type t =
131✔
206
    { typ : string
207
    ; fee_payer_id : int
208
    ; source_id : int
209
    ; receiver_id : int
210
    ; fee : int64
211
    ; amount : int64 option
212
    ; valid_until : int64 option
213
    ; memo : string
214
    ; nonce : int64
215
    ; block_id : int
216
    ; block_height : int64
217
    ; global_slot_since_genesis : int64
218
    ; sequence_no : int
219
    ; status : string
220
    }
221
  [@@deriving hlist]
222

223
  let typ =
224
    Mina_caqti.Type_spec.custom_type ~to_hlist ~of_hlist
1✔
225
      Caqti_type.
226
        [ string
227
        ; int
228
        ; int
229
        ; int
230
        ; int64
231
        ; option int64
1✔
232
        ; option int64
1✔
233
        ; string
234
        ; int64
235
        ; int
236
        ; int64
237
        ; int64
238
        ; int
239
        ; string
240
        ]
241

242
  let query =
243
    Mina_caqti.collect_req Caqti_type.int typ
1✔
244
      {sql| SELECT command_type,fee_payer_id, source_id,receiver_id,fee,amount,valid_until,memo,nonce,
245
                   blocks.id,blocks.height,blocks.global_slot_since_genesis,
246
                   sequence_no,status
247

248
            FROM user_commands AS uc
249

250
            INNER JOIN blocks_user_commands AS buc
251

252
            ON uc.id = buc.user_command_id
253

254
            INNER JOIN blocks
255

256
            ON blocks.id = buc.block_id
257

258
            WHERE uc.id = $1
259

260
       |sql}
261

262
  let run (module Conn : Mina_caqti.CONNECTION) user_cmd_id =
263
    Conn.collect_list query user_cmd_id
95✔
264
end
265

266
module Zkapp_command_ids = struct
267
  let query =
268
    Mina_caqti.collect_req
1✔
269
      Caqti_type.(t2 string int64)
1✔
270
      Caqti_type.int
271
      (find_command_ids_query "zkapp")
1✔
272

273
  let run (module Conn : Mina_caqti.CONNECTION) ~state_hash ~start_slot =
274
    Conn.collect_list query (state_hash, start_slot)
1✔
275
end
276

277
module Zkapp_command = struct
278
  type t =
265✔
279
    { zkapp_fee_payer_body_id : int
280
    ; zkapp_account_updates_ids : int array
281
    ; memo : string
282
    ; block_id : int
283
    ; global_slot_since_genesis : int64
284
    ; sequence_no : int
285
    ; hash : string
286
    }
287
  [@@deriving hlist]
288

289
  let typ =
290
    Mina_caqti.Type_spec.custom_type ~to_hlist ~of_hlist
1✔
291
      Caqti_type.
292
        [ int; Mina_caqti.array_int_typ; string; int; int64; int; string ]
293

294
  let query =
295
    Mina_caqti.collect_req Caqti_type.int typ
1✔
296
      {sql| SELECT zkapp_fee_payer_body_id,zkapp_account_updates_ids,memo,
297
                   blocks.id,blocks.global_slot_since_genesis,
298
                   sequence_no,hash
299

300
            FROM zkapp_commands AS zkc
301

302
            INNER JOIN blocks_zkapp_commands AS bzc
303

304
            ON zkc.id = bzc.zkapp_command_id
305

306
            INNER JOIN blocks
307

308
            ON blocks.id = bzc.block_id
309

310
            WHERE zkc.id = $1
311

312
       |sql}
313

314
  let run (module Conn : Mina_caqti.CONNECTION) zkapp_cmd_id =
315
    Conn.collect_list query zkapp_cmd_id
188✔
316
end
317

318
module Internal_command_ids = struct
319
  let query =
320
    Mina_caqti.collect_req
1✔
321
      Caqti_type.(t2 string int64)
1✔
322
      Caqti_type.int
323
      (find_command_ids_query "internal")
1✔
324

325
  let run (module Conn : Mina_caqti.CONNECTION) ~state_hash ~start_slot =
326
    Conn.collect_list query (state_hash, start_slot)
1✔
327
end
328

329
module Internal_command = struct
330
  type t =
65✔
331
    { typ : string
332
    ; receiver_id : int
333
    ; fee : int64
334
    ; block_id : int
335
    ; block_height : int64
336
    ; global_slot_since_genesis : int64
337
    ; sequence_no : int
338
    ; secondary_sequence_no : int
339
    }
340
  [@@deriving hlist]
341

342
  let typ =
343
    Mina_caqti.Type_spec.custom_type ~to_hlist ~of_hlist
1✔
344
      Caqti_type.[ string; int; int64; int; int64; int64; int; int ]
345

346
  (* the transaction global slot since genesis is taken from the internal command's current block, mirroring
347
     the call to Staged_ledger.apply in Block_producer
348
  *)
349
  let query =
350
    Mina_caqti.collect_req
1✔
351
      Caqti_type.(t2 int64 int)
1✔
352
      typ
353
      {sql| SELECT command_type,receiver_id,fee,
354
                   b.id,b.height,b.global_slot_since_genesis,
355
                   sequence_no,secondary_sequence_no
356

357
            FROM (SELECT * FROM internal_commands WHERE id = $2) AS ic
358

359
            INNER JOIN blocks_internal_commands AS bic
360

361
            ON ic.id = bic.internal_command_id
362

363
            INNER JOIN blocks AS b
364

365
            ON b.id = bic.block_id
366

367
            INNER JOIN blocks as parent
368

369
            ON parent.id = b.parent_id
370

371
            WHERE b.global_slot_since_genesis >= $1
372
       |sql}
373

374
  let run (module Conn : Mina_caqti.CONNECTION) ~start_slot ~internal_cmd_id =
375
    Conn.collect_list query (start_slot, internal_cmd_id)
17✔
376
end
377

378
module Public_key = struct
379
  let query =
380
    Mina_caqti.find_opt_req Caqti_type.int Caqti_type.string
1✔
381
      {sql| SELECT value FROM public_keys
382
            WHERE id = ?
383
      |sql}
384

385
  let run (module Conn : Mina_caqti.CONNECTION) pk_id =
386
    Conn.find_opt query pk_id
×
387
end
388

389
module Snarked_ledger_hashes = struct
390
  let query =
391
    Mina_caqti.find_req Caqti_type.int Caqti_type.string
1✔
392
      {sql| SELECT value FROM snarked_ledger_hashes
393
            WHERE id = ?
394
      |sql}
395

396
  let run (module Conn : Mina_caqti.CONNECTION) id = Conn.find query id
97✔
397
end
398

399
module Epoch_data = struct
400
  type epoch_data = { epoch_ledger_hash : string; epoch_data_seed : string }
401

402
  let epoch_data_typ =
403
    let encode t = Ok (t.epoch_ledger_hash, t.epoch_data_seed) in
×
404
    let decode (epoch_ledger_hash, epoch_data_seed) =
405
      Ok { epoch_ledger_hash; epoch_data_seed }
1,330✔
406
    in
407
    let rep = Caqti_type.(t2 string string) in
1✔
408
    Caqti_type.custom ~encode ~decode rep
1✔
409

410
  let query_epoch_data =
411
    Mina_caqti.find_req Caqti_type.int epoch_data_typ
1✔
412
      {sql| SELECT slh.value, ed.seed FROM snarked_ledger_hashes AS slh
413

414
       INNER JOIN
415

416
       epoch_data AS ed
417

418
       ON slh.id = ed.ledger_hash_id
419

420
       WHERE ed.id = ?
421

422
      |sql}
423

424
  let get_epoch_data (module Conn : Mina_caqti.CONNECTION) epoch_ledger_id =
425
    Conn.find query_epoch_data epoch_ledger_id
1,330✔
426

427
  let query_staking_epoch_data_id =
428
    Mina_caqti.find_req Caqti_type.string Caqti_type.int
1✔
429
      {sql| SELECT staking_epoch_data_id FROM blocks
430

431
            WHERE state_hash = ?
432

433
      |sql}
434

435
  let get_staking_epoch_data_id (module Conn : Mina_caqti.CONNECTION) state_hash
436
      =
437
    Conn.find query_staking_epoch_data_id state_hash
664✔
438

439
  let query_next_epoch_data_id =
440
    Mina_caqti.find_req Caqti_type.string Caqti_type.int
1✔
441
      {sql| SELECT next_epoch_data_id FROM blocks
442

443
            WHERE state_hash = ?
444
      |sql}
445

446
  let get_next_epoch_data_id (module Conn : Mina_caqti.CONNECTION) state_hash =
447
    Conn.find query_next_epoch_data_id state_hash
664✔
448
end
449

450
module Parent_block = struct
451
  (* fork block is parent of block with the given state hash *)
452
  let query_parent_state_hash =
453
    Mina_caqti.find_req Caqti_type.string Caqti_type.string
1✔
454
      {sql| SELECT parent.state_hash FROM blocks AS parent
455

456
            INNER JOIN
457

458
            (SELECT parent_id FROM blocks WHERE state_hash = ?) AS epoch_ledgers_block
459

460
            ON epoch_ledgers_block.parent_id = parent.id
461
      |sql}
462

463
  let get_parent_state_hash (module Conn : Mina_caqti.CONNECTION)
464
      epoch_ledgers_state_hash =
465
    Conn.find query_parent_state_hash epoch_ledgers_state_hash
×
466
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc