|
| 1 | +BEGIN; |
| 2 | + |
| 3 | +CREATE MATERIALIZED VIEW views.validator_uptimes AS |
| 4 | + -- With a limit of 14400 blocks, this is the last ~24 hrs of signatures. |
| 5 | + WITH last_window_blocks AS ( |
| 6 | + SELECT height, signer_entity_ids |
| 7 | + FROM chain.blocks |
| 8 | + ORDER BY height DESC |
| 9 | + LIMIT 14400 |
| 10 | + OFFSET 1 -- Omit the most recent block; signatures for it are obtained in the next block. |
| 11 | + ), |
| 12 | + -- Generate a series of 12 segments representing ~2 hours within the window. |
| 13 | + all_segments AS ( |
| 14 | + SELECT generate_series(0, 11) AS segment_id |
| 15 | + ), |
| 16 | + -- Segments of blocks of ~2 hours within the main window, with expanded signers. |
| 17 | + segment_blocks AS ( |
| 18 | + SELECT |
| 19 | + height, |
| 20 | + UNNEST(signer_entity_ids) AS signer_entity_id, |
| 21 | + (ROW_NUMBER() OVER (ORDER BY height DESC) - 1) / 1200 AS segment_id |
| 22 | + FROM last_window_blocks |
| 23 | + ), |
| 24 | + -- Count signed blocks in each segment. |
| 25 | + segment_counts AS ( |
| 26 | + SELECT |
| 27 | + signer_entity_id, |
| 28 | + segment_id, |
| 29 | + COUNT(height) AS signed_blocks_count |
| 30 | + FROM |
| 31 | + segment_blocks |
| 32 | + -- Compute this for all validators; the client can select from the view if needed. |
| 33 | + GROUP BY |
| 34 | + signer_entity_id, segment_id |
| 35 | + ) |
| 36 | + -- Group windows per signer and calculate overall percentage. |
| 37 | + SELECT |
| 38 | + signers.signer_entity_id AS signer_entity_id, |
| 39 | + COALESCE(SUM(signed_blocks_count), 0) AS window_signed, |
| 40 | + ARRAY_AGG(COALESCE(segment_counts.signed_blocks_count, 0) ORDER BY segment_counts.segment_id) AS segments_signed, |
| 41 | + 14400 AS window_length, -- 14400 blocks per window. |
| 42 | + 1200 AS segment_length -- 1200 blocks per segment. |
| 43 | + FROM |
| 44 | + -- Ensure we have all windows for each signer, even if they didn't sign in a particular window. |
| 45 | + (SELECT DISTINCT signer_entity_id FROM segment_counts) AS signers |
| 46 | + CROSS JOIN all_segments |
| 47 | + LEFT JOIN segment_counts ON signers.signer_entity_id = segment_counts.signer_entity_id AND all_segments.segment_id = segment_counts.segment_id |
| 48 | + GROUP BY |
| 49 | + signers.signer_entity_id; |
| 50 | + |
| 51 | +CREATE UNIQUE INDEX ix_views_validator_uptimes_signer_entity_id ON views.validator_uptimes (signer_entity_id); -- A unique index is required for CONCURRENTLY refreshing the view. |
| 52 | + |
| 53 | +-- Grant others read-only use. This does NOT apply to future tables in the schema. |
| 54 | +GRANT SELECT ON ALL TABLES IN SCHEMA views TO PUBLIC; |
| 55 | + |
| 56 | +END; |
0 commit comments