LCOV - code coverage report
Current view: top level - disco/gui - fd_gui.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 143 0.0 %
Date: 2026-06-19 09:21:35 Functions: 0 40 0.0 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_disco_gui_fd_gui_h
       2             : #define HEADER_fd_src_disco_gui_fd_gui_h
       3             : 
       4             : #include "fd_gui_peers.h"
       5             : 
       6             : #include "../topo/fd_topo.h"
       7             : 
       8             : #include "../../ballet/txn/fd_txn.h"
       9             : #include "../../disco/tiles.h"
      10             : #include "../../disco/fd_txn_p.h"
      11             : #include "../../disco/bundle/fd_bundle_tile.h"
      12             : #include "../../discof/restore/fd_snapct_tile.h"
      13             : #include "../../discof/restore/utils/fd_ssmsg.h"
      14             : #include "../../discof/tower/fd_tower_tile.h"
      15             : #include "../../discof/replay/fd_replay_tile.h"
      16             : #include "../../choreo/tower/fd_tower.h"
      17             : #include "../../choreo/tower/fd_tower_serdes.h"
      18             : #include "../../flamenco/leaders/fd_leaders.h"
      19             : #include "../../util/fd_util_base.h"
      20             : #include "../../util/hist/fd_histf.h"
      21             : #include "../../waltz/http/fd_http_server.h"
      22             : #include "../../flamenco/accdb/fd_accdb_cache.h"
      23             : #include "../../flamenco/accdb/fd_accdb_shmem.h"
      24             : 
      25             : /* frankendancer only */
      26             : #define FD_GUI_MAX_PEER_CNT (108000UL)
      27             : 
      28             : /* frankendancer only */
      29             : #define FD_GUI_START_PROGRESS_TYPE_INITIALIZING                       ( 0)
      30             : #define FD_GUI_START_PROGRESS_TYPE_SEARCHING_FOR_FULL_SNAPSHOT        ( 1)
      31             : #define FD_GUI_START_PROGRESS_TYPE_DOWNLOADING_FULL_SNAPSHOT          ( 2)
      32             : #define FD_GUI_START_PROGRESS_TYPE_SEARCHING_FOR_INCREMENTAL_SNAPSHOT ( 3)
      33             : #define FD_GUI_START_PROGRESS_TYPE_DOWNLOADING_INCREMENTAL_SNAPSHOT   ( 4)
      34             : #define FD_GUI_START_PROGRESS_TYPE_CLEANING_BLOCK_STORE               ( 5)
      35             : #define FD_GUI_START_PROGRESS_TYPE_CLEANING_ACCOUNTS                  ( 6)
      36             : #define FD_GUI_START_PROGRESS_TYPE_LOADING_LEDGER                     ( 7)
      37             : #define FD_GUI_START_PROGRESS_TYPE_PROCESSING_LEDGER                  ( 8)
      38             : #define FD_GUI_START_PROGRESS_TYPE_STARTING_SERVICES                  ( 9)
      39             : #define FD_GUI_START_PROGRESS_TYPE_HALTED                             (10)
      40             : #define FD_GUI_START_PROGRESS_TYPE_WAITING_FOR_SUPERMAJORITY          (11)
      41             : #define FD_GUI_START_PROGRESS_TYPE_RUNNING                            (12)
      42             : 
      43           0 : #define FD_GUI_NETWORK_EMA_HALF_LIFE_NS (1000000000L) /* 1 second in nanoseconds */
      44           0 : #define FD_GUI_NET_PROTO_CNT            (6UL)         /* turbine, gossip, tpu, repair, rserve, metric */
      45           0 : #define FD_GUI_NET_RATE_MAX_WINDOW_NS   (300L*1000L*1000L*1000L) /* 5 minutes in nanoseconds */
      46             : 
      47             : /* Monotonic deque element for sliding-window max tracking of
      48             :    EMA-smoothed network throughput. */
      49             : struct fd_gui_rate_entry {
      50             :   long   ts_nanos;
      51             :   double value;
      52             : };
      53             : typedef struct fd_gui_rate_entry fd_gui_rate_entry_t;
      54             : 
      55             : /* At 100 ms sampling, 5 minutes = 3000 samples. */
      56             : #define DEQUE_NAME fd_gui_rate_deque
      57           0 : #define DEQUE_T    fd_gui_rate_entry_t
      58           0 : #define DEQUE_MAX  4096UL
      59             : #include "../../util/tmpl/fd_deque.c"
      60             : 
      61             : /* frankendancer only */
      62             : struct fd_gui_gossip_peer {
      63             :   fd_pubkey_t pubkey[ 1 ];
      64             :   ulong       wallclock;
      65             :   ushort      shred_version;
      66             : 
      67             :   int has_version;
      68             :   struct {
      69             :     ushort major;
      70             :     ushort minor;
      71             :     ushort patch;
      72             : 
      73             :     int    has_commit;
      74             :     uint   commit;
      75             : 
      76             :     uint   feature_set;
      77             :   } version;
      78             : 
      79             :   struct {
      80             :     uint   ipv4;
      81             :     ushort port;
      82             :   } sockets[ 12 ];
      83             : };
      84             : 
      85             : /* frankendancer only */
      86             : struct fd_gui_vote_account {
      87             :   fd_pubkey_t pubkey[ 1 ];
      88             :   fd_pubkey_t vote_account[ 1 ];
      89             : 
      90             :   ulong       activated_stake;
      91             :   ulong       last_vote;
      92             :   ulong       root_slot;
      93             :   ulong       epoch_credits;
      94             :   uchar       commission;
      95             :   int         delinquent;
      96             : };
      97             : 
      98             : /* frankendancer only */
      99             : struct fd_gui_validator_info {
     100             :   fd_pubkey_t pubkey[ 1 ];
     101             : 
     102             :   char name[ 64 ];
     103             :   char website[ 128 ];
     104             :   char details[ 256 ];
     105             :   char icon_uri[ 128 ];
     106             : };
     107             : 
     108             : /* frankendancer only */
     109             : #define FD_GUI_SLOT_LEADER_UNSTARTED (0UL)
     110             : #define FD_GUI_SLOT_LEADER_STARTED   (1UL)
     111             : #define FD_GUI_SLOT_LEADER_ENDED     (2UL)
     112             : 
     113           0 : #define FD_GUI_SLOTS_CNT                           (864000UL) /* 2x 432000 */
     114           0 : #define FD_GUI_LEADER_CNT                          (4096UL)
     115             : 
     116           0 : #define FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS (10L)
     117           0 : #define FD_GUI_TPS_HISTORY_SAMPLE_CNT              (150UL)
     118             : 
     119           0 : #define FD_GUI_PROGCACHE_HISTORY_CNT               (600UL) /* 60s / 100ms */
     120             : 
     121           0 : #define FD_GUI_TILE_TIMER_SNAP_CNT                   (512UL)
     122           0 : #define FD_GUI_TILE_TIMER_LEADER_DOWNSAMPLE_CNT      (50UL)  /* 500ms / 10ms */
     123           0 : #define FD_GUI_SCHEDULER_COUNT_SNAP_CNT              (512UL)
     124             : #define FD_GUI_SCHEDULER_COUNT_LEADER_DOWNSAMPLE_CNT (50UL)  /* 500ms / 10ms */
     125             : 
     126           0 : #define FD_GUI_VOTE_STATE_NON_VOTING (0)
     127           0 : #define FD_GUI_VOTE_STATE_VOTING     (1)
     128           0 : #define FD_GUI_VOTE_STATE_DELINQUENT (2)
     129             : 
     130           0 : #define FD_GUI_BOOT_PROGRESS_TYPE_JOINING_GOSSIP               (1)
     131           0 : #define FD_GUI_BOOT_PROGRESS_TYPE_LOADING_FULL_SNAPSHOT        (2)
     132           0 : #define FD_GUI_BOOT_PROGRESS_TYPE_LOADING_INCREMENTAL_SNAPSHOT (3)
     133           0 : #define FD_GUI_BOOT_PROGRESS_TYPE_WAITING_FOR_SUPERMAJORITY    (4)
     134           0 : #define FD_GUI_BOOT_PROGRESS_TYPE_CATCHING_UP                  (5)
     135           0 : #define FD_GUI_BOOT_PROGRESS_TYPE_RUNNING                      (6)
     136             : 
     137           0 : #define FD_GUI_BOOT_PROGRESS_FULL_SNAPSHOT_IDX        (0UL)
     138           0 : #define FD_GUI_BOOT_PROGRESS_INCREMENTAL_SNAPSHOT_IDX (1UL)
     139           0 : #define FD_GUI_BOOT_PROGRESS_SNAPSHOT_CNT             (2UL)
     140             : 
     141           0 : #define FD_GUI_SLOT_LEVEL_INCOMPLETE               (0)
     142           0 : #define FD_GUI_SLOT_LEVEL_COMPLETED                (1)
     143           0 : #define FD_GUI_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED (2)
     144           0 : #define FD_GUI_SLOT_LEVEL_ROOTED                   (3)
     145           0 : #define FD_GUI_SLOT_LEVEL_FINALIZED                (4)
     146             : 
     147             : /* Ideally, we would store an entire epoch's worth of transactions.  If
     148             :    we assume any given validator will have at most 5% stake, and average
     149             :    transactions per slot is around 10_000, then an epoch will have about
     150             :    432_000*10_000*0.05 transactions (~2^28).
     151             : 
     152             :    Unfortunately, the transaction struct is 100+ bytes.  If we sized the
     153             :    array to 2^28 entries then the memory required would be ~26GB.  In
     154             :    order to keep memory usage to a more reasonable level, we'll
     155             :    arbitrarily use a fourth of that size. */
     156           0 : #define FD_GUI_TXN_HISTORY_SZ (1UL<<26UL)
     157             : 
     158           0 : #define FD_GUI_TXN_FLAGS_STARTED         ( 1U)
     159           0 : #define FD_GUI_TXN_FLAGS_ENDED           ( 2U)
     160           0 : #define FD_GUI_TXN_FLAGS_IS_SIMPLE_VOTE  ( 4U)
     161           0 : #define FD_GUI_TXN_FLAGS_FROM_BUNDLE     ( 8U)
     162           0 : #define FD_GUI_TXN_FLAGS_LANDED_IN_BLOCK (16U)
     163             : 
     164           0 : #define FD_GUI_TURBINE_RECV_TIMESTAMPS (750UL)
     165             : 
     166             : /* One use case for tracking ingress shred slot is to estimate when we
     167             :    have caught up to the tip of the blockchain.  A naive approach would
     168             :    be to track the maximum seen slot.
     169             : 
     170             :    maximum_seen_slot = fd_ulong_max( maximum_seen_slot, new_slot_from_shred_tile );
     171             : 
     172             :    Unfortunately, this doesn't always work because a validator can send
     173             :    a slot number that is arbitrarily large on a false fork. Also, these
     174             :    shreds can be for a repair response, which can be arbitrarily small.
     175             : 
     176             :    The prospects here seem bleak, but not all hope is lost!  We know
     177             :    that for a sufficiently large historical time window there is a high
     178             :    probability that at least some of the slots we observe will be valid
     179             :    recent turbine slots. For a sufficiently small window there is a high
     180             :    probability that all the observed shred slots are non-malicious (i.e.
     181             :    not arbitrarily large).
     182             : 
     183             :    In practice shred slots are almost always non-malicious. We can keep
     184             :    a history of the 12 largest slots we've seen in the past 4.8 seconds.
     185             :    We'll consider the "tip" of the blockchain to be the maximum slot in
     186             :    our history. This way, if we receive maliciously large slot number,
     187             :    it will be evicted after 4.8 seconds. If we receive a small slot from
     188             :    a repair response it will be ignored because we've seen other larger
     189             :    slots, meaning that our estimate is eventually consistent. For
     190             :    monitoring purposes this is sufficient.
     191             : 
     192             :    The worst case scenario is that this validator receives an incorrect
     193             :    shred slot slot more than once every 3 leader rotations. Before the
     194             :    previous incorrect slot is evicted from the history, a new one takes
     195             :    it's place and we wouldn't never get a correct estimate of the tip of
     196             :    the chain.  We also would indefinitely think that that we haven't
     197             :    caught up. This would require the chain having perpetually malicious
     198             :    leaders with adjacent rotations.  If this happens, Solana has bigger
     199             :    problems. */
     200           0 : #define FD_GUI_TURBINE_SLOT_HISTORY_SZ (  12UL )
     201             : 
     202             : /* Like the turbine slot, the latest repair slot can also swing to
     203             :    arbitrarily large values due to a malicious fork switch.  The gui
     204             :    provides the same guarantees for freshness and accuracy.  This
     205             :    history is somewhat larger to handle the increased repair bandwidth
     206             :    during catch up. */
     207           0 : #define FD_GUI_REPAIR_SLOT_HISTORY_SZ  ( 512UL )
     208             : 
     209             : /* FD_GUI_*_CATCH_UP_HISTORY_SZ is the capacity of the record of slots
     210             :    seen from repair or turbine during the catch up stage at startup.
     211             :    These buffers are run-length encoded, so they will typically be very
     212             :    small.  The worst-case scenario is unbounded, so bounds here are
     213             :    determined heuristically. */
     214           0 : #define FD_GUI_REPAIR_CATCH_UP_HISTORY_SZ  (4096UL)
     215           0 : #define FD_GUI_TURBINE_CATCH_UP_HISTORY_SZ (4096UL)
     216             : 
     217             : /* FD_GUI_SHREDS_STAGING_SZ is number of shred events we'll retain in
     218             :    in a small staging area.  The lifecycle of a shred looks something
     219             :    like the following
     220             : 
     221             :    states] turbine -> repairing (optional) ->  processing                   -> waiting_for_siblings -> slot_complete
     222             :    events]         ^-repair_requested      ^-shred_received/shred_repaired  ^-shred_replayed        ^-max(shred_replayed)
     223             : 
     224             :    We're interested in recording timestamps for state transitions (which
     225             :    these docs call "shred events").  Unfortunately, due to forking,
     226             :    duplicate packets, etc we can't make any guarantees about ordering or
     227             :    uniqueness for these event timestamps.  Instead the GUI just records
     228             :    timestamps for all events as they occur and put them into an array.
     229             :    Newly recorded event timestamps are also broadcast live to WebSocket
     230             :    consumers.
     231             : 
     232             :    The amount of shred events for non-finalized blocks can't really be
     233             :    bounded, so we use generous estimates here to set a memory bound. */
     234           0 : #define FD_GUI_MAX_SHREDS_PER_BLOCK  (32UL*1024UL)
     235           0 : #define FD_GUI_MAX_EVENTS_PER_SHRED  (       32UL)
     236           0 : #define FD_GUI_SHREDS_STAGING_SZ     (32UL * FD_GUI_MAX_SHREDS_PER_BLOCK * FD_GUI_MAX_EVENTS_PER_SHRED)
     237             : 
     238             : /* FD_GUI_SHREDS_HISTORY_SZ the number of shred events in our historical
     239             :    shred store.  Shred events here belong to finalized slots which means
     240             :    we won't record any additional shred updates for these slots.
     241             : 
     242             :    All shred events for a given slot will be places in a contiguous
     243             :    chunk in the array, and the bounding indicies are stored in the
     244             :    fd_gui_slot_t slot history.  Within a slot chunk, shred events are
     245             :    ordered in the ordered they were recorded by the gui tile.
     246             : 
     247             :    Ideally, we have enough space to store an epoch's worth of events,
     248             :    but we are limited by realistic memory consumption.  Instead, we pick
     249             :    bound heuristically. */
     250           0 : #define FD_GUI_SHREDS_HISTORY_SZ     (432000UL*2000UL*4UL / 12UL)
     251             : 
     252           0 : #define FD_GUI_SLOT_SHRED_REPAIR_REQUEST          (0UL)
     253           0 : #define FD_GUI_SLOT_SHRED_SHRED_RECEIVED_TURBINE  (1UL)
     254           0 : #define FD_GUI_SLOT_SHRED_SHRED_RECEIVED_REPAIR   (2UL)
     255           0 : #define FD_GUI_SLOT_SHRED_SHRED_REPLAY_EXEC_DONE  (3UL)
     256           0 : #define FD_GUI_SLOT_SHRED_SHRED_SLOT_COMPLETE     (4UL)
     257             : /* #define FD_GUI_SLOT_SHRED_SHRED_REPLAY_EXEC_START (5UL) // UNUSED */
     258           0 : #define FD_GUI_SLOT_SHRED_SHRED_PUBLISHED         (6UL)
     259             : 
     260           0 : #define FD_GUI_SLOT_RANKINGS_SZ (100UL)
     261           0 : #define FD_GUI_SLOT_RANKING_TYPE_ASC  (0)
     262           0 : #define FD_GUI_SLOT_RANKING_TYPE_DESC (1)
     263             : 
     264             : struct fd_gui_tile_timers {
     265             :   ulong timers[ FD_METRICS_ENUM_TILE_REGIME_CNT ];
     266             :   ulong sched_timers[ FD_METRICS_ENUM_CPU_REGIME_CNT ];
     267             : 
     268             :   int    in_backp;
     269             :   ushort last_cpu;
     270             :   uchar  status;
     271             :   ulong  heartbeat;
     272             :   ulong  backp_cnt;
     273             :   ulong  nvcsw;
     274             :   ulong  nivcsw;
     275             :   ulong  minflt;
     276             :   ulong  majflt;
     277             :   ulong  interrupts;
     278             : };
     279             : 
     280             : typedef struct fd_gui_tile_timers fd_gui_tile_timers_t;
     281             : 
     282             : struct fd_gui_scheduler_counts {
     283             :   long sample_time_ns;
     284             :   ulong regular;
     285             :   ulong votes;
     286             :   ulong conflicting;
     287             :   ulong bundles;
     288             : };
     289             : 
     290             : typedef struct fd_gui_scheduler_counts fd_gui_scheduler_counts_t;
     291             : 
     292             : struct fd_gui_network_stats {
     293             :   /* total bytes accumulated */
     294             :   struct {
     295             :     ulong turbine;
     296             :     ulong gossip;
     297             :     ulong tpu;
     298             :     ulong repair;
     299             :     ulong rserve;
     300             :     ulong metric;
     301             :   } in, out;
     302             : };
     303             : 
     304             : typedef struct fd_gui_network_stats fd_gui_network_stats_t;
     305             : 
     306             : struct fd_gui_accounts_stats {
     307             :   /* Raw counters/gauges read from tile metric pages.  Stored so we can
     308             :      compute deltas (and per-second rates) against a previous snapshot. */
     309             :   long  sample_time_nanos;
     310             : 
     311             :   /* Disk (gauges from accdb tile). */
     312             :   ulong accounts_total;
     313             :   ulong accounts_capacity;
     314             :   ulong disk_allocated_bytes;
     315             :   ulong disk_current_bytes;
     316             :   ulong disk_used_bytes;
     317             : 
     318             :   /* Compaction (gauges + counters from accdb tile). */
     319             :   ulong in_compaction;
     320             :   ulong compactions_requested;
     321             :   ulong compactions_completed;
     322             :   ulong accounts_relocated_bytes;
     323             : 
     324             :   /* Cache occupancy (gauges from accdb tile, per class). */
     325             :   ulong cache_class_used           [ FD_ACCDB_CACHE_CLASS_CNT ];
     326             :   ulong cache_class_max            [ FD_ACCDB_CACHE_CLASS_CNT ];
     327             :   ulong cache_class_reserved       [ FD_ACCDB_CACHE_CLASS_CNT ];
     328             :   /* Preeviction thresholds, expressed as used-slot counts directly
     329             :      comparable to cache_class_used / cache_class_max. */
     330             :   ulong cache_class_target_used    [ FD_ACCDB_CACHE_CLASS_CNT ];
     331             :   ulong cache_class_low_water_used [ FD_ACCDB_CACHE_CLASS_CNT ];
     332             : 
     333             :   /* Aggregate counters summed across all accdb consumer tiles. */
     334             :   ulong acquired;                   /* total acquires */
     335             :   ulong acquired_writable;          /* writable subset of acquires (RW tiles only) */
     336             :   ulong acquired_per_class           [ FD_ACCDB_CACHE_CLASS_CNT ]; /* acquires attributed to a class (RW tiles only) */
     337             :   ulong acquired_writable_per_class  [ FD_ACCDB_CACHE_CLASS_CNT ]; /* writable acquires attributed to a class (RW tiles only) */
     338             :   ulong not_found_per_class          [ FD_ACCDB_CACHE_CLASS_CNT ]; /* misses, per class */
     339             :   ulong evicted_per_class            [ FD_ACCDB_CACHE_CLASS_CNT ];
     340             :   ulong preevicted_per_class         [ FD_ACCDB_CACHE_CLASS_CNT ];
     341             :   ulong committed_new_per_class      [ FD_ACCDB_CACHE_CLASS_CNT ];
     342             :   ulong committed_overwrite_per_class[ FD_ACCDB_CACHE_CLASS_CNT ];
     343             : 
     344             :   /* IO counters.  bytes_written/read_ops/write_ops are summed across
     345             :      all consumer tiles; bytes_written_accdb is the bytes written by
     346             :      the accdb tile itself (background preevict + compaction), used to
     347             :      compute the prewrite ratio. */
     348             :   ulong bytes_read;
     349             :   ulong bytes_copied;
     350             :   ulong bytes_written;
     351             :   ulong bytes_written_accdb;
     352             :   ulong read_ops;
     353             :   ulong write_ops;
     354             : };
     355             : 
     356             : typedef struct fd_gui_accounts_stats fd_gui_accounts_stats_t;
     357             : 
     358             : struct fd_gui_leader_slot {
     359             :   ulong slot;
     360             :   fd_hash_t block_hash;
     361             :   long  leader_start_time; /* UNIX timestamp of when we first became leader in this slot */
     362             :   long  leader_end_time;   /* UNIX timestamp of when we stopped being leader in this slot */
     363             : 
     364             :   /* Stem tiles can exist in one of 8 distinct activity regimes at any
     365             :      given moment.  One of these regimes, caughtup_postfrag, is the
     366             :      only regime where a tile is in a spin loop without doing any
     367             :      useful work.  This info is useful from a monitoring perspective
     368             :      because it lets us estimate CPU utilization on a pinned core.
     369             : 
     370             :      Every 10ms, the gui tile samples the amount of time tiles spent
     371             :      in each regime in the past 10ms.  This sample is used to infer
     372             :      the CPU utilization in the past 10ms.  This utilization is
     373             :      streamed live to WebSocket clients.
     374             : 
     375             :      In additional to live utilization, we are interested in recording
     376             :      utilization during one of this validator's leader slots.  The gui
     377             :      tile is continuously recording samples to storage with capacity
     378             :      FD_GUI_TILE_TIMER_SNAP_CNT. The sample index is recorded at the
     379             :      start and end of a leader slot, and the number of samples is
     380             :      downsampled to be at most FD_GUI_TILE_TIMER_LEADER_DOWNSAMPLE_CNT
     381             :      samples (e.g. if there was an unusually long leader slot) and
     382             :      inserted into historical storage with capacity FD_GUI_LEADER_CNT.
     383             : 
     384             :      The tile_timers pointer references trailing storage allocated
     385             :      in fd_gui_footprint, with gui->tile_cnt elements per sample.
     386             :      Sized as tile_timers[ FD_GUI_TILE_TIMER_LEADER_DOWNSAMPLE_CNT ][ tile_cnt ]. */
     387             :   fd_gui_tile_timers_t * tile_timers;
     388             :   ulong                  tile_timers_sample_cnt;
     389             : 
     390             :   fd_gui_scheduler_counts_t scheduler_counts[ FD_GUI_SCHEDULER_COUNT_LEADER_DOWNSAMPLE_CNT ][ 1 ];
     391             :   ulong                     scheduler_counts_sample_cnt;
     392             : 
     393             :   struct {
     394             :     uint microblocks_upper_bound; /* An upper bound on the number of microblocks in the slot.  If the number of
     395             :                                      microblocks observed is equal to this, the slot can be considered over.
     396             :                                      Generally, the bound is set to a "final" state by a done packing message,
     397             :                                      which sets it to the exact number of microblocks, but sometimes this message
     398             :                                      is not sent, if the max upper bound published by poh was already correct. */
     399             :     uint begin_microblocks; /* The number of microblocks we have seen be started (sent) from pack to banks. */
     400             :     uint end_microblocks;   /* The number of microblocks we have seen be ended (sent) from banks to poh.  The
     401             :                                slot is only considered over if the begin and end microblocks seen are both equal
     402             :                                to the microblock upper bound. */
     403             : 
     404             :     ulong   start_offset; /* The smallest pack transaction index for this slot. The first transaction for this slot will
     405             :                              be written to gui->txs[ start_offset%FD_GUI_TXN_HISTORY_SZ ]. */
     406             :     ulong   end_offset;   /* The largest pack transaction index for this slot, plus 1. The last transaction for this
     407             :                              slot will be written to gui->txs[ (end_offset-1)%FD_GUI_TXN_HISTORY_SZ ]. */
     408             :   } txs;
     409             : 
     410             :   fd_done_packing_t scheduler_stats[ 1 ];
     411             : 
     412             :   /* The initial, maximum number of microblocks that could be packed
     413             :      into this slot. */
     414             :   ulong max_microblocks;
     415             : 
     416             :   uchar unbecame_leader: 1;
     417             : };
     418             : 
     419             : typedef struct fd_gui_leader_slot fd_gui_leader_slot_t;
     420             : 
     421             : struct fd_gui_turbine_slot {
     422             :  ulong slot;
     423             :  long timestamp;
     424             : };
     425             : 
     426             : typedef struct fd_gui_turbine_slot fd_gui_turbine_slot_t;
     427             : 
     428             : struct fd_gui_slot_staged_shred_event {
     429             :   long   timestamp;
     430             :   ulong  slot;
     431             :   ushort shred_idx;
     432             :   uchar  event;
     433             : };
     434             : 
     435             : typedef struct fd_gui_slot_staged_shred_event fd_gui_slot_staged_shred_event_t;
     436             : 
     437             : struct __attribute__((packed)) fd_gui_slot_history_shred_event {
     438             :   long   timestamp;
     439             :   ushort shred_idx;
     440             :   uchar  event;
     441             : };
     442             : 
     443             : typedef struct fd_gui_slot_history_shred_event fd_gui_slot_history_shred_event_t;
     444             : 
     445             : struct fd_gui_slot_ranking {
     446             :   ulong slot;
     447             :   ulong value;
     448             :   int   type;
     449             : };
     450             : typedef struct fd_gui_slot_ranking fd_gui_slot_ranking_t;
     451             : 
     452             : struct fd_gui_slot_rankings {
     453             :   fd_gui_slot_ranking_t largest_tips           [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     454             :   fd_gui_slot_ranking_t largest_fees           [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     455             :   fd_gui_slot_ranking_t largest_rewards        [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     456             :   fd_gui_slot_ranking_t largest_duration       [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     457             :   fd_gui_slot_ranking_t largest_compute_units  [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     458             :   fd_gui_slot_ranking_t largest_skipped        [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     459             :   fd_gui_slot_ranking_t largest_rewards_per_cu [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     460             :   fd_gui_slot_ranking_t smallest_tips          [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     461             :   fd_gui_slot_ranking_t smallest_fees          [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     462             :   fd_gui_slot_ranking_t smallest_rewards       [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     463             :   fd_gui_slot_ranking_t smallest_rewards_per_cu[ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     464             :   fd_gui_slot_ranking_t smallest_duration      [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     465             :   fd_gui_slot_ranking_t smallest_compute_units [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     466             :   fd_gui_slot_ranking_t smallest_skipped       [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     467             : };
     468             : 
     469             : typedef struct fd_gui_slot_rankings fd_gui_slot_rankings_t;
     470             : 
     471             : struct fd_gui_ephemeral_slot {
     472             :   ulong slot; /* ULONG_MAX indicates invalid/evicted */
     473             :   long timestamp_arrival_nanos;
     474             : };
     475             : typedef struct fd_gui_ephemeral_slot fd_gui_ephemeral_slot_t;
     476             : 
     477             : struct __attribute__((packed)) fd_gui_txn {
     478             :   uchar signature[ FD_TXN_SIGNATURE_SZ ];
     479             :   ulong transaction_fee;
     480             :   ulong priority_fee;
     481             :   ulong tips;
     482             :   long timestamp_arrival_nanos;
     483             : 
     484             :   /* compute_units_requested has both execution and non-execution cus */
     485             :   uint compute_units_requested : 21; /* <= 1.4M */
     486             :   uint compute_units_consumed  : 21; /* <= 1.4M */
     487             :   uint bank_idx                :  6; /* in [0, 64) */
     488             :   uint error_code              :  6; /* in [0, 64) */
     489             : 
     490             :   /* relative to leader start */
     491             :   float           microblock_start_ns_dt;
     492             :   float           microblock_end_ns_dt;
     493             : 
     494             :   /* relative to microblock_start */
     495             :   fd_txn_ns_dt_t txn_ns_dt;
     496             : 
     497             :   uchar flags; /* assigned with the FD_GUI_TXN_FLAGS_* macros */
     498             :   uchar source_tpu; /* FD_TXN_M_TPU_SOURCE_* */
     499             :   uint  source_ipv4;
     500             :   uint  microblock_idx;
     501             : };
     502             : 
     503             : typedef struct fd_gui_txn fd_gui_txn_t;
     504             : 
     505             : struct fd_gui_txn_waterfall {
     506             :   struct {
     507             :     ulong quic;
     508             :     ulong udp;
     509             :     ulong gossip;
     510             :     ulong block_engine;
     511             :     ulong pack_cranked;
     512             :   } in;
     513             : 
     514             :   struct {
     515             :     ulong net_overrun;
     516             :     ulong quic_overrun;
     517             :     ulong quic_frag_drop;
     518             :     ulong quic_abandoned;
     519             :     ulong tpu_quic_invalid;
     520             :     ulong tpu_udp_invalid;
     521             :     ulong verify_overrun;
     522             :     ulong verify_parse;
     523             :     ulong verify_failed;
     524             :     ulong verify_duplicate;
     525             :     ulong dedup_duplicate;
     526             :     ulong resolv_lut_failed;
     527             :     ulong resolv_expired;
     528             :     ulong resolv_ancient;
     529             :     ulong resolv_no_ledger;
     530             :     ulong resolv_retained;
     531             :     ulong pack_invalid;
     532             :     ulong pack_invalid_bundle;
     533             :     ulong pack_expired;
     534             :     ulong pack_already_executed;
     535             :     ulong pack_retained;
     536             :     ulong pack_wait_full;
     537             :     ulong pack_leader_slow;
     538             :     ulong bank_invalid;
     539             :     ulong bank_nonce_already_advanced;
     540             :     ulong bank_nonce_advance_failed;
     541             :     ulong bank_nonce_wrong_blockhash;
     542             :     ulong block_success;
     543             :     ulong block_fail;
     544             :   } out;
     545             : };
     546             : 
     547             : typedef struct fd_gui_txn_waterfall fd_gui_txn_waterfall_t;
     548             : 
     549             : struct fd_gui_tile_stats {
     550             :   long  sample_time_nanos;
     551             : 
     552             :   ulong net_in_rx_bytes;           /* Number of bytes received by the net or sock tile*/
     553             :   ulong quic_conn_cnt;             /* Number of active QUIC connections */
     554             :   fd_histf_t bundle_rx_delay_hist; /* Histogram of bundle rx delay */
     555             :   ulong bundle_rtt_smoothed_nanos; /* RTT (nanoseconds) moving average */
     556             :   ulong verify_drop_cnt;           /* Number of transactions dropped by verify tiles */
     557             :   ulong verify_total_cnt;          /* Number of transactions received by verify tiles */
     558             :   ulong dedup_drop_cnt;            /* Number of transactions dropped by dedup tile */
     559             :   ulong dedup_total_cnt;           /* Number of transactions received by dedup tile */
     560             :   ulong pack_buffer_cnt;           /* Number of buffered transactions in the pack tile */
     561             :   ulong pack_buffer_capacity;      /* Total size of the pack transaction buffer */
     562             :   ulong bank_txn_exec_cnt;         /* Number of transactions processed by the bank tile */
     563             :   ulong net_out_tx_bytes;          /* Number of bytes sent by the net or sock tile */
     564             : };
     565             : 
     566             : typedef struct fd_gui_tile_stats fd_gui_tile_stats_t;
     567             : 
     568             : struct fd_gui_slot {
     569             :   ulong slot;
     570             :   ulong parent_slot;
     571             :   ulong vote_slot;
     572             :   ulong reset_slot;
     573             :   long  completed_time;
     574             :   uint  max_compute_units;
     575             :   int   mine;
     576             :   int   skipped;
     577             :   int   must_republish;
     578             :   int   level;
     579             :   uint  compute_units;
     580             :   ulong transaction_fee;
     581             :   ulong priority_fee;
     582             :   ulong tips;
     583             :   uint  shred_cnt;
     584             :   uchar vote_latency;
     585             : 
     586             :   uint vote_success;
     587             :   uint vote_failed;
     588             :   uint nonvote_success;
     589             :   uint nonvote_failed;
     590             : 
     591             :   /* Some slot info is only tracked for our own leader slots. These
     592             :      slots are kept in a separate buffer. */
     593             :   ulong leader_history_idx;
     594             : 
     595             :   fd_gui_txn_waterfall_t waterfall_begin[ 1 ];
     596             :   fd_gui_txn_waterfall_t waterfall_end[ 1 ];
     597             : 
     598             :   fd_gui_tile_stats_t tile_stats_begin[ 1 ];
     599             :   fd_gui_tile_stats_t tile_stats_end[ 1 ];
     600             : 
     601             :   struct {
     602             :     ulong start_offset; /* gui->shreds.history[ start_offset % FD_GUI_SHREDS_HISTORY_SZ ] is the first shred event in
     603             :                            contiguous chunk of events in the shred history corresponding to this slot. */
     604             :     ulong end_offset;   /* One past the last shred event in the contiguous chunk of events in the shred history
     605             :                            corresponding to this slot. */
     606             :   } shreds;
     607             : };
     608             : 
     609             : typedef struct fd_gui_slot fd_gui_slot_t;
     610             : 
     611             : struct fd_gui_boot_progress {
     612             :   uchar phase;
     613             :   long joining_gossip_time_nanos;
     614             :   struct {
     615             :     ulong  slot;
     616             :     uint   peer_addr;
     617             :     ushort peer_port;
     618             :     ulong  total_bytes_compressed;
     619             :     long   reset_time_nanos;          /* UNIX nanosecond timestamp */
     620             :     long   sample_time_nanos;
     621             :     ulong  reset_cnt;
     622             : 
     623             :     ulong read_bytes_compressed;
     624             :     char  read_path[ PATH_MAX+30UL ]; /* URL or filesystem path.  30 is fd_cstr_nlen( "https://255.255.255.255:12345/", ULONG_MAX ) */
     625             : 
     626             :     ulong decompress_bytes_decompressed;
     627             :     ulong decompress_bytes_compressed;
     628             : 
     629             :     ulong insert_bytes_decompressed;
     630             :     char  insert_path[ PATH_MAX ];
     631             :     ulong insert_accounts_current;
     632             : 
     633             :     ulong snapwr_in_bytes_decompressed;
     634             :     ulong snapwr_out_bytes_decompressed;
     635             :     ulong snapwr_accounts_current;
     636             :   } loading_snapshot[ FD_GUI_BOOT_PROGRESS_SNAPSHOT_CNT ];
     637             : 
     638             :   ulong wfs_total_stake;
     639             :   ulong wfs_connected_stake;
     640             :   ulong wfs_total_peers;
     641             :   ulong wfs_connected_peers;
     642             :   ulong wfs_attempt;
     643             : 
     644             :   long  catching_up_time_nanos;
     645             :   ulong catching_up_first_replay_slot;
     646             : };
     647             : 
     648             : typedef struct fd_gui_boot_progress fd_gui_boot_progress_t;
     649             : 
     650             : struct fd_gui {
     651             :   fd_http_server_t * http;
     652             :   fd_topo_t const * topo;
     653             :   fd_accdb_shmem_t const * accdb_shmem;
     654             : 
     655             :   double tick_per_ns;
     656             : 
     657             :   ulong tile_cnt;
     658             : 
     659             :   long next_sample_400millis;
     660             :   long next_sample_100millis;
     661             :   long next_sample_50millis;
     662             :   long next_sample_25millis;
     663             :   long next_sample_10millis;
     664             : 
     665             :   ulong leader_slot;
     666             : 
     667             :   struct {
     668             :     fd_pubkey_t identity_key[ 1 ];
     669             :     int         has_vote_key;
     670             :     fd_pubkey_t vote_key[ 1 ];
     671             :     char vote_key_base58[ FD_BASE58_ENCODED_32_SZ ];
     672             :     char identity_key_base58[ FD_BASE58_ENCODED_32_SZ ];
     673             : 
     674             :     int          is_full_client;
     675             :     char const * version;
     676             :     char const * cluster;
     677             : 
     678             :     char   wfs_bank_hash[ FD_BASE58_ENCODED_32_SZ ];
     679             :     ushort expected_shred_version;
     680             :     int    wfs_enabled;
     681             : 
     682             :     ulong vote_distance;
     683             :     int vote_state;
     684             : 
     685             :     long  startup_time_nanos;
     686             : 
     687             :     union {
     688             :       struct { /* frankendancer only */
     689             :       uchar phase;
     690             :       int   startup_got_full_snapshot;
     691             : 
     692             :       ulong  startup_incremental_snapshot_slot;
     693             :       uint   startup_incremental_snapshot_peer_ip_addr;
     694             :         ushort startup_incremental_snapshot_peer_port;
     695             :         double startup_incremental_snapshot_elapsed_secs;
     696             :         double startup_incremental_snapshot_remaining_secs;
     697             :         double startup_incremental_snapshot_throughput;
     698             :         ulong  startup_incremental_snapshot_total_bytes;
     699             :         ulong  startup_incremental_snapshot_current_bytes;
     700             : 
     701             :         ulong  startup_full_snapshot_slot;
     702             :         uint   startup_full_snapshot_peer_ip_addr;
     703             :         ushort startup_full_snapshot_peer_port;
     704             :         double startup_full_snapshot_elapsed_secs;
     705             :         double startup_full_snapshot_remaining_secs;
     706             :         double startup_full_snapshot_throughput;
     707             :         ulong  startup_full_snapshot_total_bytes;
     708             :         ulong  startup_full_snapshot_current_bytes;
     709             : 
     710             :         ulong startup_ledger_slot;
     711             :         ulong startup_ledger_max_slot;
     712             : 
     713             :         ulong startup_waiting_for_supermajority_slot;
     714             :         ulong startup_waiting_for_supermajority_stake_pct;
     715             :       } startup_progress;
     716             :       fd_gui_boot_progress_t boot_progress;
     717             :     };
     718             : 
     719             :     fd_gui_boot_progress_t prev_boot_progress;
     720             : 
     721             :     int schedule_strategy;
     722             : 
     723             :     ulong identity_account_balance;
     724             :     ulong vote_account_balance;
     725             :     ulong estimated_slot_duration_nanos;
     726             : 
     727             :     ulong sock_tile_cnt;
     728             :     ulong net_tile_cnt;
     729             :     ulong quic_tile_cnt;
     730             :     ulong verify_tile_cnt;
     731             :     ulong resolh_tile_cnt;
     732             :     ulong resolv_tile_cnt;
     733             :     ulong bank_tile_cnt;
     734             :     ulong execle_tile_cnt;
     735             :     ulong execrp_tile_cnt;
     736             :     ulong shred_tile_cnt;
     737             : 
     738             :     ulong slot_rooted;
     739             :     ulong slot_optimistically_confirmed;
     740             :     ulong slot_completed;
     741             :     ulong slot_estimated;
     742             :     ulong slot_caught_up;
     743             :     ulong slot_repair;
     744             :     ulong slot_turbine;
     745             :     ulong slot_reset;
     746             :     ulong slot_storage;
     747             :     ulong active_fork_cnt;
     748             : 
     749             :     fd_gui_ephemeral_slot_t slots_max_turbine[ FD_GUI_TURBINE_SLOT_HISTORY_SZ+1UL ];
     750             :     fd_gui_ephemeral_slot_t slots_max_repair [ FD_GUI_REPAIR_SLOT_HISTORY_SZ +1UL ];
     751             : 
     752             :     /* catchup_* and late_votes are run-length encoded. i.e. adjacent
     753             :        pairs represent contiguous runs */
     754             :     ulong catch_up_turbine[ FD_GUI_TURBINE_CATCH_UP_HISTORY_SZ ];
     755             :     ulong catch_up_turbine_sz;
     756             : 
     757             :     ulong catch_up_repair[ FD_GUI_REPAIR_CATCH_UP_HISTORY_SZ ];
     758             :     ulong catch_up_repair_sz;
     759             : 
     760             :     ulong late_votes[ MAX_SLOTS_PER_EPOCH ];
     761             :     ulong late_votes_sz;
     762             : 
     763             :     ulong estimated_tps_history_idx;
     764             :     struct {
     765             :      ulong vote_failed;
     766             :      ulong vote_success;
     767             :      ulong nonvote_success;
     768             :      ulong nonvote_failed;
     769             :     } estimated_tps_history[ FD_GUI_TPS_HISTORY_SAMPLE_CNT ];
     770             : 
     771             :     fd_gui_network_stats_t network_stats_current[ 1 ];
     772             :     fd_gui_network_stats_t network_stats_prev[ 1 ];
     773             :     int                    network_stats_has_prev;
     774             : 
     775             :     /* EMA-smoothed network throughput (bytes/sec) with a 1-second
     776             :        half-life. */
     777             :     double                   ingress_ema[ FD_GUI_NET_PROTO_CNT ];
     778             :     double                   egress_ema[ FD_GUI_NET_PROTO_CNT ];
     779             :     long                     net_rate_prev_ts;
     780             :     int                      net_rate_ema_ready;
     781             :     fd_gui_rate_entry_t *    ingress_maxq;
     782             :     fd_gui_rate_entry_t *    egress_maxq;
     783             : 
     784             :     fd_gui_accounts_stats_t accounts_stats_reference[ 1 ];
     785             :     fd_gui_accounts_stats_t accounts_stats_current  [ 1 ];
     786             :     int                     accounts_stats_have_reference;
     787             :     /* Triangular-weighted moving window over per-snap deltas.  Snap
     788             :        cadence is ~100ms, window is FD_GUI_ACCDB_WIN_SAMPLES samples
     789             :        (~5s).  The output rate for any metric is:
     790             : 
     791             :          rate = sum( w[i] * delta[i] ) / sum( w[i] * dt[i] )
     792             : 
     793             :        where w[i] is the triangular weight (newest sample heaviest,
     794             :        oldest weight=1).  This is fully caught up to a new rate after
     795             :        the window length but smoother than a boxcar (no cliff edge as
     796             :        samples age out). */
     797           0 : #   define FD_GUI_ACCDB_WIN_SAMPLES 50UL
     798             :     ulong                   accdb_win_idx;        /* next write index */
     799             :     ulong                   accdb_win_count;      /* samples filled, capped at FD_GUI_ACCDB_WIN_SAMPLES */
     800             :     long                    accdb_win_dt_nanos [ FD_GUI_ACCDB_WIN_SAMPLES ];
     801             : 
     802             :     /* Aggregate delta rings (units per snap). */
     803             :     ulong                   agg_acquired_win          [ FD_GUI_ACCDB_WIN_SAMPLES ];
     804             :     ulong                   agg_acquired_writable_win [ FD_GUI_ACCDB_WIN_SAMPLES ];
     805             :     ulong                   agg_bytes_read_win        [ FD_GUI_ACCDB_WIN_SAMPLES ];
     806             :     ulong                   agg_bytes_copied_win      [ FD_GUI_ACCDB_WIN_SAMPLES ];
     807             :     ulong                   agg_bytes_written_win     [ FD_GUI_ACCDB_WIN_SAMPLES ];
     808             :     ulong                   agg_bytes_written_accdb_win[FD_GUI_ACCDB_WIN_SAMPLES ];
     809             :     ulong                   agg_read_ops_win          [ FD_GUI_ACCDB_WIN_SAMPLES ];
     810             :     ulong                   agg_write_ops_win         [ FD_GUI_ACCDB_WIN_SAMPLES ];
     811             :     ulong                   agg_relocated_bytes_win   [ FD_GUI_ACCDB_WIN_SAMPLES ];
     812             :     ulong                   agg_misses_win            [ FD_GUI_ACCDB_WIN_SAMPLES ];
     813             : 
     814             :     /* Per-class delta rings (units per snap). */
     815             :     ulong                   class_acq_win         [ FD_ACCDB_CACHE_CLASS_CNT ][ FD_GUI_ACCDB_WIN_SAMPLES ];
     816             :     ulong                   class_acq_wr_win      [ FD_ACCDB_CACHE_CLASS_CNT ][ FD_GUI_ACCDB_WIN_SAMPLES ];
     817             :     ulong                   class_not_found_win   [ FD_ACCDB_CACHE_CLASS_CNT ][ FD_GUI_ACCDB_WIN_SAMPLES ];
     818             :     ulong                   class_evicted_win     [ FD_ACCDB_CACHE_CLASS_CNT ][ FD_GUI_ACCDB_WIN_SAMPLES ];
     819             :     ulong                   class_preevicted_win  [ FD_ACCDB_CACHE_CLASS_CNT ][ FD_GUI_ACCDB_WIN_SAMPLES ];
     820             :     ulong                   class_commit_new_win  [ FD_ACCDB_CACHE_CLASS_CNT ][ FD_GUI_ACCDB_WIN_SAMPLES ];
     821             :     ulong                   class_commit_over_win [ FD_ACCDB_CACHE_CLASS_CNT ][ FD_GUI_ACCDB_WIN_SAMPLES ];
     822             : 
     823             :     /* Per-partition triangular-weighted windows for read/write rates.
     824             :        Sized to match the accdb partition pool ceiling (8192).  Rates
     825             :        are derived in fd_gui_printf via fd_gui_accdb_weighted_rate. */
     826           0 : #   define FD_GUI_MAX_PARTITIONS 8192UL
     827             :     ulong                   partition_cnt;            /* live count from accdb_shmem; <= FD_GUI_MAX_PARTITIONS */
     828             :     ulong                   partition_read_ops_win    [ FD_GUI_MAX_PARTITIONS ][ FD_GUI_ACCDB_WIN_SAMPLES ];
     829             :     ulong                   partition_bytes_read_win  [ FD_GUI_MAX_PARTITIONS ][ FD_GUI_ACCDB_WIN_SAMPLES ];
     830             :     ulong                   partition_write_ops_win   [ FD_GUI_MAX_PARTITIONS ][ FD_GUI_ACCDB_WIN_SAMPLES ];
     831             :     ulong                   partition_bytes_written_win[FD_GUI_MAX_PARTITIONS ][ FD_GUI_ACCDB_WIN_SAMPLES ];
     832             : 
     833             :     /* Per-partition snapshots (most recent values, for non-rate fields:
     834             :        offset, layer, write_offset, bytes_freed, ticks, compaction state). */
     835             :     fd_accdb_shmem_partition_info_t partitions[ FD_GUI_MAX_PARTITIONS ];
     836             : 
     837             :     /* Cumulative counters from the previous snap for delta computation. */
     838             :     ulong                   partition_prev_read_ops    [ FD_GUI_MAX_PARTITIONS ];
     839             :     ulong                   partition_prev_bytes_read  [ FD_GUI_MAX_PARTITIONS ];
     840             :     ulong                   partition_prev_write_ops   [ FD_GUI_MAX_PARTITIONS ];
     841             :     ulong                   partition_prev_bytes_written[FD_GUI_MAX_PARTITIONS ];
     842             : 
     843             :     /* Per-tile accdb stats.  At init we walk the topology and assign a
     844             :        slot to each tile that uses the account database (execle, execrp,
     845             :        replay, tower, rpc, resolv, snapwr).  Each slot keeps cumulative
     846             :        previous values for delta computation and a triangular-weighted
     847             :        delta ring (same cadence / weighting as the aggregate rings). */
     848             : #   define FD_GUI_MAX_ACCDB_TILES 64UL
     849             :     /* Tile kinds.  Determines which subset of metrics to read. */
     850           0 : #   define FD_GUI_ACCDB_TILE_KIND_RW     0  /* execle, execrp, replay, tower */
     851           0 : #   define FD_GUI_ACCDB_TILE_KIND_RO     1  /* rpc, resolv */
     852           0 : #   define FD_GUI_ACCDB_TILE_KIND_SNAPWR 2  /* snapwr (direct disk writer during snapshot load) */
     853           0 : #   define FD_GUI_ACCDB_TILE_KIND_ACCDB  3  /* accdb tile itself (prewrite + compaction writes) */
     854             :     ulong                   accdb_tile_cnt;
     855             :     ushort                  accdb_tile_topo_idx [ FD_GUI_MAX_ACCDB_TILES ]; /* index into topo->tiles */
     856             :     uchar                   accdb_tile_kind     [ FD_GUI_MAX_ACCDB_TILES ];
     857             : 
     858             :     /* Most-recent cumulative values per tile, plus the snapshot from
     859             :        the previous snap for delta computation. */
     860             :     ulong                   tile_cur_acquired          [ FD_GUI_MAX_ACCDB_TILES ];
     861             :     ulong                   tile_cur_acquired_writable [ FD_GUI_MAX_ACCDB_TILES ];
     862             :     ulong                   tile_cur_bytes_read        [ FD_GUI_MAX_ACCDB_TILES ];
     863             :     ulong                   tile_cur_bytes_copied      [ FD_GUI_MAX_ACCDB_TILES ];
     864             :     ulong                   tile_cur_bytes_written     [ FD_GUI_MAX_ACCDB_TILES ];
     865             :     ulong                   tile_cur_read_ops          [ FD_GUI_MAX_ACCDB_TILES ];
     866             :     ulong                   tile_cur_write_ops         [ FD_GUI_MAX_ACCDB_TILES ];
     867             :     ulong                   tile_cur_misses            [ FD_GUI_MAX_ACCDB_TILES ];
     868             :     ulong                   tile_cur_evicted           [ FD_GUI_MAX_ACCDB_TILES ];
     869             :     ulong                   tile_cur_committed         [ FD_GUI_MAX_ACCDB_TILES ];
     870             :     ulong                   tile_cur_acquire_calls     [ FD_GUI_MAX_ACCDB_TILES ];
     871             :     uchar                   tile_cur_status            [ FD_GUI_MAX_ACCDB_TILES ]; /* 1=running, 2=shutdown */
     872             : 
     873             :     ulong                   tile_prev_acquired         [ FD_GUI_MAX_ACCDB_TILES ];
     874             :     ulong                   tile_prev_acquired_writable[ FD_GUI_MAX_ACCDB_TILES ];
     875             :     ulong                   tile_prev_bytes_read       [ FD_GUI_MAX_ACCDB_TILES ];
     876             :     ulong                   tile_prev_bytes_copied     [ FD_GUI_MAX_ACCDB_TILES ];
     877             :     ulong                   tile_prev_bytes_written    [ FD_GUI_MAX_ACCDB_TILES ];
     878             :     ulong                   tile_prev_read_ops         [ FD_GUI_MAX_ACCDB_TILES ];
     879             :     ulong                   tile_prev_write_ops        [ FD_GUI_MAX_ACCDB_TILES ];
     880             :     ulong                   tile_prev_misses           [ FD_GUI_MAX_ACCDB_TILES ];
     881             :     ulong                   tile_prev_evicted          [ FD_GUI_MAX_ACCDB_TILES ];
     882             :     ulong                   tile_prev_committed        [ FD_GUI_MAX_ACCDB_TILES ];
     883             :     ulong                   tile_prev_acquire_calls    [ FD_GUI_MAX_ACCDB_TILES ];
     884             : 
     885             :     /* Per-tile delta rings. */
     886             :     ulong                   tile_acquired_win         [ FD_GUI_MAX_ACCDB_TILES ][ FD_GUI_ACCDB_WIN_SAMPLES ];
     887             :     ulong                   tile_acquired_writable_win[ FD_GUI_MAX_ACCDB_TILES ][ FD_GUI_ACCDB_WIN_SAMPLES ];
     888             :     ulong                   tile_bytes_read_win       [ FD_GUI_MAX_ACCDB_TILES ][ FD_GUI_ACCDB_WIN_SAMPLES ];
     889             :     ulong                   tile_bytes_copied_win     [ FD_GUI_MAX_ACCDB_TILES ][ FD_GUI_ACCDB_WIN_SAMPLES ];
     890             :     ulong                   tile_bytes_written_win    [ FD_GUI_MAX_ACCDB_TILES ][ FD_GUI_ACCDB_WIN_SAMPLES ];
     891             :     ulong                   tile_read_ops_win         [ FD_GUI_MAX_ACCDB_TILES ][ FD_GUI_ACCDB_WIN_SAMPLES ];
     892             :     ulong                   tile_write_ops_win        [ FD_GUI_MAX_ACCDB_TILES ][ FD_GUI_ACCDB_WIN_SAMPLES ];
     893             :     ulong                   tile_misses_win           [ FD_GUI_MAX_ACCDB_TILES ][ FD_GUI_ACCDB_WIN_SAMPLES ];
     894             :     ulong                   tile_evicted_win          [ FD_GUI_MAX_ACCDB_TILES ][ FD_GUI_ACCDB_WIN_SAMPLES ];
     895             :     ulong                   tile_committed_win        [ FD_GUI_MAX_ACCDB_TILES ][ FD_GUI_ACCDB_WIN_SAMPLES ];
     896             :     ulong                   tile_acquire_calls_win    [ FD_GUI_MAX_ACCDB_TILES ][ FD_GUI_ACCDB_WIN_SAMPLES ];
     897             : 
     898             :     /* 60s-history rings for the per-tile sparkline.  Each bucket is the
     899             :        sum of per-snap deltas that fell into that bucket window.
     900             :        index 0 = current bucket (in-flight), older buckets follow.  When
     901             :        a bucket interval elapses we shift right (older buckets drop off
     902             :        the end) and start a new index-0 bucket.  240 buckets x 250ms =
     903             :        60 second window. */
     904           0 : #   define FD_GUI_ACCDB_SPARKLINE_SAMPLES   240UL
     905           0 : #   define FD_GUI_ACCDB_SPARKLINE_BUCKET_NS 250000000L
     906             :     long                    tile_sparkline_bucket_start_nanos [ FD_GUI_MAX_ACCDB_TILES ];
     907             :     ulong                   tile_sparkline_acq_bucket         [ FD_GUI_MAX_ACCDB_TILES ];
     908             :     ulong                   tile_sparkline_acq_wr_bucket      [ FD_GUI_MAX_ACCDB_TILES ];
     909             :     /* Per-second rates (units/second) for the last N completed buckets.
     910             :        Newest at index 0, oldest at the end.  Filled lazily as snaps
     911             :        complete each bucket interval. */
     912             :     double                  tile_sparkline_acq_history    [ FD_GUI_MAX_ACCDB_TILES ][ FD_GUI_ACCDB_SPARKLINE_SAMPLES ];
     913             :     double                  tile_sparkline_acq_wr_history [ FD_GUI_MAX_ACCDB_TILES ][ FD_GUI_ACCDB_SPARKLINE_SAMPLES ];
     914             :     ulong                   tile_sparkline_count          [ FD_GUI_MAX_ACCDB_TILES ];  /* completed buckets, capped at FD_GUI_ACCDB_SPARKLINE_SAMPLES */
     915             : 
     916             :     fd_gui_txn_waterfall_t txn_waterfall_reference[ 1 ];
     917             :     fd_gui_txn_waterfall_t txn_waterfall_current[ 1 ];
     918             : 
     919             :     fd_gui_tile_stats_t tile_stats_reference[ 1 ];
     920             :     fd_gui_tile_stats_t tile_stats_current[ 1 ];
     921             : 
     922             :     ulong progcache_history_idx;
     923             :     ulong progcache_hits_history   [ FD_GUI_PROGCACHE_HISTORY_CNT ];
     924             :     ulong progcache_lookups_history[ FD_GUI_PROGCACHE_HISTORY_CNT ];
     925             :     ulong progcache_hits_1min;
     926             :     ulong progcache_lookups_1min;
     927             : 
     928             :     ulong                  tile_timers_snap_idx;
     929             :     ulong                  tile_timers_snap_idx_slot_start;
     930             :     /* Temporary storage for samples.  Will be downsampled into
     931             :        leader history on slot end.  Sized as
     932             :        tile_timers_snap[ FD_GUI_TILE_TIMER_SNAP_CNT ][ tile_cnt ] */
     933             :     fd_gui_tile_timers_t * tile_timers_snap;
     934             : 
     935             :     ulong                     scheduler_counts_snap_idx;
     936             :     ulong                     scheduler_counts_snap_idx_slot_start;
     937             :     /* Temporary storage for samples. Will be downsampled into leader history on slot end. */
     938             :     fd_gui_scheduler_counts_t scheduler_counts_snap[ FD_GUI_SCHEDULER_COUNT_SNAP_CNT ][ 1 ];
     939             : 
     940             :     /* Topo tile indices in display order, built once on init. */
     941             :     ulong tile[ FD_TOPO_MAX_TILES ];
     942             :     ulong tile_cnt;
     943             :   } summary;
     944             : 
     945             :   fd_gui_slot_t slots[ FD_GUI_SLOTS_CNT ][ 1 ];
     946             : 
     947             :   /* used for estimating slot duration */
     948             :   fd_gui_turbine_slot_t turbine_slots[ FD_GUI_TURBINE_RECV_TIMESTAMPS ];
     949             : 
     950             :   fd_gui_leader_slot_t leader_slots[ FD_GUI_LEADER_CNT ][ 1 ];
     951             :   ulong leader_slots_cnt;
     952             : 
     953             :   fd_gui_txn_t txs[ FD_GUI_TXN_HISTORY_SZ ][ 1 ];
     954             :   ulong pack_txn_idx; /* The pack index of the most recently received transaction */
     955             : 
     956             :   ulong tower_cnt;
     957             :   fd_vote_acc_vote_t tower[ FD_TOWER_VOTE_MAX ];
     958             : 
     959             :   struct {
     960             :     int has_block_engine;
     961             :     char name[ 16 ];
     962             :     char url[ 256 ];
     963             :     char ip_cstr[ 40 ]; /* IPv4 or IPv6 cstr */
     964             :     int status;
     965             :   } block_engine;
     966             : 
     967             :   struct {
     968             :     int has_epoch[ 2 ];
     969             : 
     970             :     struct {
     971             :       ulong epoch;
     972             :       long start_time;
     973             :       long end_time;
     974             : 
     975             :       ulong my_total_slots;
     976             :       ulong my_skipped_slots;
     977             : 
     978             :       ulong start_slot;
     979             :       ulong end_slot;
     980             :       fd_epoch_leaders_t * lsched;
     981             :       uchar __attribute__((aligned(FD_EPOCH_LEADERS_ALIGN))) _lsched[ FD_EPOCH_LEADERS_FOOTPRINT(MAX_COMPRESSED_STAKE_WEIGHTS, MAX_SLOTS_PER_EPOCH) ];
     982             :       fd_vote_stake_weight_t stakes[ MAX_COMPRESSED_STAKE_WEIGHTS ];
     983             : 
     984             :       ulong rankings_slot; /* One more than the largest slot we've processed into our rankings */
     985             :       fd_gui_slot_rankings_t rankings[ 1 ]; /* global slot rankings */
     986             :       fd_gui_slot_rankings_t my_rankings[ 1 ]; /* my slots only */
     987             :     } epochs[ 2 ];
     988             :   } epoch;
     989             : 
     990             :   struct {  /* frankendancer only */
     991             :     ulong                     peer_cnt;
     992             :     struct fd_gui_gossip_peer peers[ FD_GUI_MAX_PEER_CNT ];
     993             :   } gossip;
     994             : 
     995             :   struct {  /* frankendancer only */
     996             :     ulong                      vote_account_cnt;
     997             :     struct fd_gui_vote_account vote_accounts[ FD_GUI_MAX_PEER_CNT ];
     998             :   } vote_account;
     999             : 
    1000             :   struct {  /* frankendancer only */
    1001             :     ulong                        info_cnt;
    1002             :     struct fd_gui_validator_info info[ FD_GUI_MAX_PEER_CNT ];
    1003             :   } validator_info;
    1004             : 
    1005             :   fd_gui_peers_ctx_t * peers; /* full-client */
    1006             : 
    1007             :   struct {
    1008             :     ulong leader_shred_cnt;      /* A gauge counting the number of leader shreds seen on the SHRED_OUT link.  Resets at
    1009             :                                     the end of a leader slot.  This works because leader fecs are published in order. */
    1010             :     ulong staged_next_broadcast; /* staged[ staged_next_broadcast % FD_GUI_SHREDS_STAGING_SZ ] is the first shred event
    1011             :                                     that hasn't yet been broadcast to WebSocket clients */
    1012             :     ulong staged_head;            /* staged_head % FD_GUI_SHREDS_STAGING_SZ is the first valid event in staged */
    1013             :     ulong staged_tail;            /* staged_tail % FD_GUI_SHREDS_STAGING_SZ is one past the last valid event in staged */
    1014             :     fd_gui_slot_staged_shred_event_t  staged [ FD_GUI_SHREDS_STAGING_SZ ];
    1015             : 
    1016             :     ulong history_slot;          /* the largest slot store in history */
    1017             :     ulong history_tail;          /* history_tail % FD_GUI_SHREDS_HISTORY_SZ is one past the last valid event in history */
    1018             :     fd_gui_slot_history_shred_event_t history[ FD_GUI_SHREDS_HISTORY_SZ ];
    1019             : 
    1020             :     /* scratch space for archiving staged events */
    1021             :     fd_gui_slot_staged_shred_event_t _staged_scratch [ FD_GUI_SHREDS_STAGING_SZ ];
    1022             :   } shreds; /* full client */
    1023             : };
    1024             : 
    1025             : typedef struct fd_gui fd_gui_t;
    1026             : 
    1027             : /* fd_gui_staged_push returns a pointer to the next free staging slot
    1028             :    and advances staged_tail.  If the ring is full staged_head is
    1029             :    advanced first so the oldest entry is silently dropped. */
    1030             : static inline fd_gui_slot_staged_shred_event_t *
    1031           0 : fd_gui_staged_push( fd_gui_t * gui ) {
    1032           0 :   if( FD_UNLIKELY( gui->shreds.staged_tail - gui->shreds.staged_head >= FD_GUI_SHREDS_STAGING_SZ ) ) {
    1033           0 :     gui->shreds.staged_head = gui->shreds.staged_tail - FD_GUI_SHREDS_STAGING_SZ + 1UL;
    1034           0 :     if( FD_UNLIKELY( gui->shreds.staged_next_broadcast < gui->shreds.staged_head ) ) {
    1035           0 :       gui->shreds.staged_next_broadcast = gui->shreds.staged_head;
    1036           0 :     }
    1037           0 :   }
    1038           0 :   fd_gui_slot_staged_shred_event_t * dst =
    1039           0 :       &gui->shreds.staged[ gui->shreds.staged_tail % FD_GUI_SHREDS_STAGING_SZ ];
    1040           0 :   gui->shreds.staged_tail++;
    1041           0 :   return dst;
    1042           0 : }
    1043             : 
    1044             : FD_PROTOTYPES_BEGIN
    1045             : 
    1046             : FD_FN_CONST ulong
    1047             : fd_gui_align( void );
    1048             : 
    1049             : ulong
    1050             : fd_gui_footprint( ulong tile_cnt );
    1051             : 
    1052             : void *
    1053             : fd_gui_new( void *                   shmem,
    1054             :             fd_http_server_t *       http,
    1055             :             char const *             version,
    1056             :             char const *             cluster,
    1057             :             uchar const *            identity_key,
    1058             :             int                      has_vote_key,
    1059             :             uchar const *            vote_key,
    1060             :             int                      is_full_client,
    1061             :             int                      snapshots_enabled,
    1062             :             int                      is_voting,
    1063             :             int                      schedule_strategy,
    1064             :             char const *             wfs_expected_bank_hash_cstr,
    1065             :             ushort                   expected_shred_version,
    1066             :             fd_topo_t const *        topo,
    1067             :             fd_accdb_shmem_t const * accdb_shmem,
    1068             :             long                     now );
    1069             : 
    1070             : fd_gui_t *
    1071             : fd_gui_join( void * shmem );
    1072             : 
    1073             : void
    1074             : fd_gui_set_identity( fd_gui_t *    gui,
    1075             :                      uchar const * identity_pubkey );
    1076             : 
    1077             : void
    1078             : fd_gui_ws_open( fd_gui_t *  gui,
    1079             :                 ulong       conn_id,
    1080             :                 long now );
    1081             : 
    1082             : int
    1083             : fd_gui_ws_message( fd_gui_t *    gui,
    1084             :                    ulong         ws_conn_id,
    1085             :                    uchar const * data,
    1086             :                    ulong         data_len );
    1087             : 
    1088             : void
    1089             : fd_gui_became_leader( fd_gui_t * gui,
    1090             :                       ulong      slot,
    1091             :                       long       start_time_nanos,
    1092             :                       long       end_time_nanos,
    1093             :                       ulong      max_compute_units,
    1094             :                       ulong      max_microblocks );
    1095             : 
    1096             : void
    1097             : fd_gui_unbecame_leader( fd_gui_t *                gui,
    1098             :                         ulong                     _slot,
    1099             :                         fd_done_packing_t const * done_packing,
    1100             :                         long                      now );
    1101             : 
    1102             : void
    1103             : fd_gui_microblock_execution_begin( fd_gui_t *   gui,
    1104             :                                    long         tspub_ns,
    1105             :                                    ulong        _slot,
    1106             :                                    fd_txn_e_t * txns,
    1107             :                                    ulong        txn_cnt,
    1108             :                                    uint         microblock_idx,
    1109             :                                    ulong        pack_txn_idx );
    1110             : 
    1111             : void
    1112             : fd_gui_microblock_execution_end( fd_gui_t *     gui,
    1113             :                                  long           tspub_ns,
    1114             :                                  ulong          bank_idx,
    1115             :                                  ulong          _slot,
    1116             :                                  ulong          txn_cnt,
    1117             :                                  fd_txn_p_t *   txns,
    1118             :                                  ulong          pack_txn_idx,
    1119             :                                  fd_txn_ns_dt_t txn_ns_dt,
    1120             :                                  ulong          tips );
    1121             : 
    1122             : int
    1123             : fd_gui_poll( fd_gui_t * gui, long now );
    1124             : 
    1125             : void
    1126             : fd_gui_handle_block_engine_update( fd_gui_t *                              gui,
    1127             :                                    fd_bundle_block_engine_update_t const * update );
    1128             : 
    1129             : void
    1130             : fd_gui_handle_shred( fd_gui_t * gui,
    1131             :                      ulong      slot,
    1132             :                      ulong      shred_idx,
    1133             :                      int        is_turbine,
    1134             :                      long       tsorig );
    1135             : 
    1136             : void
    1137             : fd_gui_handle_leader_fec( fd_gui_t * gui,
    1138             :                           ulong      slot,
    1139             :                           ulong      fec_shred_cnt,
    1140             :                           int        is_end_of_slot,
    1141             :                           long       tsorig );
    1142             : 
    1143             : void
    1144             : fd_gui_handle_exec_txn_done( fd_gui_t * gui,
    1145             :                              ulong      slot,
    1146             :                              ulong      start_shred_idx,
    1147             :                              ulong      end_shred_idx,
    1148             :                              long       tsorig_ns,
    1149             :                              long       tspub_ns );
    1150             : 
    1151             : void
    1152             : fd_gui_handle_repair_slot( fd_gui_t * gui, ulong slot, long now );
    1153             : 
    1154             : void
    1155             : fd_gui_handle_repair_request( fd_gui_t * gui, ulong slot, ulong shred_idx, long now );
    1156             : 
    1157             : void
    1158             : fd_gui_handle_snapshot_update( fd_gui_t *                 gui,
    1159             :                                fd_snapct_update_t const * msg );
    1160             : 
    1161             : void
    1162             : fd_gui_stage_snapshot_manifest( fd_gui_t *                       gui,
    1163             :                                  fd_snapshot_manifest_t const *    manifest );
    1164             : 
    1165             : void
    1166             : fd_gui_handle_leader_schedule( fd_gui_t *                    gui,
    1167             :                                fd_stake_weight_msg_t const * leader_schedule,
    1168             :                                long                          now );
    1169             : 
    1170             : void
    1171             : fd_gui_handle_epoch_info( fd_gui_t *                  gui,
    1172             :                           fd_epoch_info_msg_t const * epoch_info,
    1173             :                           long                        now );
    1174             : 
    1175             : void
    1176             : fd_gui_handle_votes_update( fd_gui_t *                        gui,
    1177             :                                    fd_tower_slot_confirmed_t const * votes );
    1178             : 
    1179             : void
    1180             : fd_gui_handle_tower_update( fd_gui_t *                   gui,
    1181             :                             fd_tower_slot_done_t const * msg,
    1182             :                             long                         now );
    1183             : 
    1184             : void
    1185             : fd_gui_handle_replay_update( fd_gui_t *                         gui,
    1186             :                              fd_replay_slot_completed_t const * slot_completed,
    1187             :                              ulong                              vote_slot,
    1188             :                              long                               now );
    1189             : 
    1190             : void
    1191             : fd_gui_handle_genesis_hash( fd_gui_t *        gui,
    1192             :                             fd_hash_t const * msg );
    1193             : 
    1194             : static inline ulong
    1195           0 : fd_gui_current_epoch_idx( fd_gui_t * gui ) {
    1196           0 :   ulong epoch_idx = ULONG_MAX;
    1197           0 :   ulong epoch     = ULONG_MAX;
    1198           0 :   for( ulong i = 0UL; i<2UL; i++ ) {
    1199           0 :     if( FD_LIKELY( gui->epoch.has_epoch[ i ] ) ) {
    1200             :       /* the "current" epoch is the smaller one */
    1201           0 :       if( FD_LIKELY( gui->epoch.epochs[ i ].epoch<epoch ) ) {
    1202           0 :         epoch = gui->epoch.epochs[ i ].epoch;
    1203           0 :         epoch_idx = i;
    1204           0 :       }
    1205           0 :     }
    1206           0 :   }
    1207           0 :   return epoch_idx;
    1208           0 : }
    1209             : 
    1210             : static inline fd_gui_slot_t *
    1211           0 : fd_gui_get_slot( fd_gui_t const * gui, ulong _slot ) {
    1212           0 :   fd_gui_slot_t const * slot = gui->slots[ _slot % FD_GUI_SLOTS_CNT ];
    1213           0 :   if( FD_UNLIKELY( slot->slot==ULONG_MAX || _slot==ULONG_MAX || slot->slot!=_slot ) ) return NULL;
    1214           0 :   return (fd_gui_slot_t *)slot;
    1215           0 : }
    1216             : 
    1217             : static inline fd_gui_slot_t const *
    1218           0 : fd_gui_get_slot_const( fd_gui_t const * gui, ulong _slot ) {
    1219           0 :   return fd_gui_get_slot( gui, _slot );
    1220           0 : }
    1221             : 
    1222             : static inline fd_gui_leader_slot_t *
    1223           0 : fd_gui_get_leader_slot( fd_gui_t const * gui, ulong _slot ) {
    1224           0 :   fd_gui_slot_t const * slot = fd_gui_get_slot( gui, _slot );
    1225           0 :   if( FD_UNLIKELY( !slot
    1226           0 :                 || !slot->mine
    1227           0 :                 || slot->leader_history_idx==ULONG_MAX
    1228           0 :                 || slot->leader_history_idx + FD_GUI_LEADER_CNT < gui->leader_slots_cnt
    1229           0 :                 || gui->leader_slots[ slot->leader_history_idx % FD_GUI_LEADER_CNT ]->slot!=_slot ) ) return NULL;
    1230           0 :   return (fd_gui_leader_slot_t *)gui->leader_slots[ slot->leader_history_idx % FD_GUI_LEADER_CNT ];
    1231           0 : }
    1232             : 
    1233             : static inline fd_gui_leader_slot_t const *
    1234           0 : fd_gui_get_leader_slot_const( fd_gui_t const * gui, ulong _slot ) {
    1235           0 :   return fd_gui_get_leader_slot( gui, _slot );
    1236           0 : }
    1237             : 
    1238             : /* fd_gui_get_root_slot returns a handle to the closest ancestor of slot
    1239             :    that is a root, if available, otherwise NULL. */
    1240             : static inline fd_gui_slot_t *
    1241             : fd_gui_get_root_slot( fd_gui_t const * gui,
    1242           0 :                       ulong            slot ) {
    1243           0 :   fd_gui_slot_t * c = fd_gui_get_slot( gui, slot );
    1244           0 :   while( c ) {
    1245           0 :     if( FD_UNLIKELY( c->level>=FD_GUI_SLOT_LEVEL_ROOTED ) ) return c;
    1246           0 :     c = fd_gui_get_slot( gui, c->parent_slot );
    1247           0 :   }
    1248           0 :   return NULL;
    1249           0 : }
    1250             : 
    1251             : /* fd_gui_slot_is_ancestor returns 1 if anc is known to be an ancestor
    1252             :    of slot (on the same fork), 0 otherwise. */
    1253             : static inline int
    1254             : fd_gui_slot_is_ancestor( fd_gui_t const * gui,
    1255             :                          ulong            anc,
    1256           0 :                          ulong            slot ) {
    1257           0 :   fd_gui_slot_t * c = fd_gui_get_slot( gui, slot );
    1258           0 :   while( c ) {
    1259           0 :     if( FD_UNLIKELY( c->slot==anc ) ) return 1;
    1260           0 :     c = fd_gui_get_slot( gui, c->parent_slot );
    1261           0 :   }
    1262           0 :   return 0;
    1263           0 : }
    1264             : 
    1265             : /* fd_gui_get_parent_slot_on_fork returns a handle to the parent of slot
    1266             :    on the fork ending on frontier_slot.  If slot is unknown or skipped,
    1267             :    the closest (by slot number) valid parent on the fork is returned.
    1268             : 
    1269             :    NULL if slot is not an ancestor of frontier slot or if the parent is
    1270             :    unknown. */
    1271             : static inline fd_gui_slot_t *
    1272             : fd_gui_get_parent_slot_on_fork( fd_gui_t const * gui,
    1273             :                                 ulong            frontier_slot,
    1274           0 :                                 ulong            slot ) {
    1275           0 :   fd_gui_slot_t * c = fd_gui_get_slot( gui, frontier_slot );
    1276           0 :   while( c ) {
    1277           0 :     if( FD_UNLIKELY( c->slot<=slot ) ) return NULL;
    1278           0 :     fd_gui_slot_t * p = fd_gui_get_slot( gui, c->parent_slot );
    1279           0 :     if( FD_UNLIKELY( p && p->slot<=slot-1UL ) ) return p;
    1280           0 :     c = p;
    1281           0 :   }
    1282           0 :   return NULL;
    1283           0 : }
    1284             : 
    1285             : /* fd_gui_is_skipped_on_fork returns 1 if slot is skipped on the fork
    1286             :    starting at anc and ending at des, 0 otherwise. */
    1287             : static inline int
    1288             : fd_gui_is_skipped_on_fork( fd_gui_t const * gui,
    1289             :                            ulong            anc,
    1290             :                            ulong            des,
    1291           0 :                            ulong            slot ) {
    1292           0 :   fd_gui_slot_t const * c = fd_gui_get_slot( gui, des );
    1293           0 :   while( c ) {
    1294           0 :     if( FD_UNLIKELY( anc==c->slot ) ) return 0; /* on the fork, not skipped */
    1295           0 :     fd_gui_slot_t const * p = fd_gui_get_slot( gui, c->parent_slot );
    1296           0 :     if( FD_UNLIKELY( p && p->slot<slot && c->slot>slot ) ) return 1; /* in-between two nodes, skipped */
    1297           0 :     c = p;
    1298           0 :   }
    1299             : 
    1300           0 :   return 0; /* slot not between anc and des, or is unknown */
    1301           0 : }
    1302             : 
    1303             : FD_PROTOTYPES_END
    1304             : 
    1305             : #endif /* HEADER_fd_src_disco_gui_fd_gui_h */

Generated by: LCOV version 1.14