LCOV - code coverage report
Current view: top level - disco/gui - fd_gui.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 128 0.0 %
Date: 2026-02-23 05:51:03 Functions: 0 36 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/tower/fd_tower_tile.h"
      14             : #include "../../choreo/tower/fd_tower.h"
      15             : #include "../../choreo/tower/fd_tower_serdes.h"
      16             : #include "../../flamenco/leaders/fd_leaders.h"
      17             : #include "../../flamenco/types/fd_types_custom.h"
      18             : #include "../../util/fd_util_base.h"
      19             : #include "../../util/hist/fd_histf.h"
      20             : #include "../../waltz/http/fd_http_server.h"
      21             : 
      22             : /* frankendancer only */
      23             : #define FD_GUI_MAX_PEER_CNT ( 40200UL)
      24             : 
      25             : /* frankendancer only */
      26           0 : #define FD_GUI_START_PROGRESS_TYPE_INITIALIZING                       ( 0)
      27           0 : #define FD_GUI_START_PROGRESS_TYPE_SEARCHING_FOR_FULL_SNAPSHOT        ( 1)
      28           0 : #define FD_GUI_START_PROGRESS_TYPE_DOWNLOADING_FULL_SNAPSHOT          ( 2)
      29           0 : #define FD_GUI_START_PROGRESS_TYPE_SEARCHING_FOR_INCREMENTAL_SNAPSHOT ( 3)
      30           0 : #define FD_GUI_START_PROGRESS_TYPE_DOWNLOADING_INCREMENTAL_SNAPSHOT   ( 4)
      31           0 : #define FD_GUI_START_PROGRESS_TYPE_CLEANING_BLOCK_STORE               ( 5)
      32           0 : #define FD_GUI_START_PROGRESS_TYPE_CLEANING_ACCOUNTS                  ( 6)
      33           0 : #define FD_GUI_START_PROGRESS_TYPE_LOADING_LEDGER                     ( 7)
      34           0 : #define FD_GUI_START_PROGRESS_TYPE_PROCESSING_LEDGER                  ( 8)
      35           0 : #define FD_GUI_START_PROGRESS_TYPE_STARTING_SERVICES                  ( 9)
      36           0 : #define FD_GUI_START_PROGRESS_TYPE_HALTED                             (10)
      37           0 : #define FD_GUI_START_PROGRESS_TYPE_WAITING_FOR_SUPERMAJORITY          (11)
      38           0 : #define FD_GUI_START_PROGRESS_TYPE_RUNNING                            (12)
      39             : 
      40             : /* frankendancer only */
      41             : struct fd_gui_gossip_peer {
      42             :   fd_pubkey_t pubkey[ 1 ];
      43             :   ulong       wallclock;
      44             :   ushort      shred_version;
      45             : 
      46             :   int has_version;
      47             :   struct {
      48             :     ushort major;
      49             :     ushort minor;
      50             :     ushort patch;
      51             : 
      52             :     int    has_commit;
      53             :     uint   commit;
      54             : 
      55             :     uint   feature_set;
      56             :   } version;
      57             : 
      58             :   struct {
      59             :     uint   ipv4;
      60             :     ushort port;
      61             :   } sockets[ 12 ];
      62             : };
      63             : 
      64             : /* frankendancer only */
      65             : struct fd_gui_vote_account {
      66             :   fd_pubkey_t pubkey[ 1 ];
      67             :   fd_pubkey_t vote_account[ 1 ];
      68             : 
      69             :   ulong       activated_stake;
      70             :   ulong       last_vote;
      71             :   ulong       root_slot;
      72             :   ulong       epoch_credits;
      73             :   uchar       commission;
      74             :   int         delinquent;
      75             : };
      76             : 
      77             : /* frankendancer only */
      78             : struct fd_gui_validator_info {
      79             :   fd_pubkey_t pubkey[ 1 ];
      80             : 
      81             :   char name[ 64 ];
      82             :   char website[ 128 ];
      83             :   char details[ 256 ];
      84             :   char icon_uri[ 128 ];
      85             : };
      86             : 
      87             : /* frankendancer only */
      88             : #define FD_GUI_SLOT_LEADER_UNSTARTED (0UL)
      89             : #define FD_GUI_SLOT_LEADER_STARTED   (1UL)
      90             : #define FD_GUI_SLOT_LEADER_ENDED     (2UL)
      91             : 
      92           0 : #define FD_GUI_SLOTS_CNT                           (864000UL) /* 2x 432000 */
      93           0 : #define FD_GUI_LEADER_CNT                          (4096UL)
      94             : 
      95           0 : #define FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS (10L)
      96           0 : #define FD_GUI_TPS_HISTORY_SAMPLE_CNT              (150UL)
      97             : 
      98           0 : #define FD_GUI_TILE_TIMER_SNAP_CNT                   (512UL)
      99             : #define FD_GUI_TILE_TIMER_LEADER_DOWNSAMPLE_CNT      (50UL)  /* 500ms / 10ms */
     100           0 : #define FD_GUI_SCHEDULER_COUNT_SNAP_CNT              (512UL)
     101             : #define FD_GUI_SCHEDULER_COUNT_LEADER_DOWNSAMPLE_CNT (50UL)  /* 500ms / 10ms */
     102             : #define FD_GUI_TILE_TIMER_TILE_CNT                   (256UL)
     103             : 
     104           0 : #define FD_GUI_VOTE_STATE_NON_VOTING (0)
     105           0 : #define FD_GUI_VOTE_STATE_VOTING     (1)
     106           0 : #define FD_GUI_VOTE_STATE_DELINQUENT (2)
     107             : 
     108           0 : #define FD_GUI_BOOT_PROGRESS_TYPE_JOINING_GOSSIP               (1)
     109           0 : #define FD_GUI_BOOT_PROGRESS_TYPE_LOADING_FULL_SNAPSHOT        (2)
     110           0 : #define FD_GUI_BOOT_PROGRESS_TYPE_LOADING_INCREMENTAL_SNAPSHOT (3)
     111           0 : #define FD_GUI_BOOT_PROGRESS_TYPE_CATCHING_UP                  (4)
     112           0 : #define FD_GUI_BOOT_PROGRESS_TYPE_RUNNING                      (5)
     113             : 
     114           0 : #define FD_GUI_BOOT_PROGRESS_FULL_SNAPSHOT_IDX        (0UL)
     115           0 : #define FD_GUI_BOOT_PROGRESS_INCREMENTAL_SNAPSHOT_IDX (1UL)
     116           0 : #define FD_GUI_BOOT_PROGRESS_SNAPSHOT_CNT             (2UL)
     117             : 
     118           0 : #define FD_GUI_SLOT_LEVEL_INCOMPLETE               (0)
     119           0 : #define FD_GUI_SLOT_LEVEL_COMPLETED                (1)
     120           0 : #define FD_GUI_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED (2)
     121           0 : #define FD_GUI_SLOT_LEVEL_ROOTED                   (3)
     122           0 : #define FD_GUI_SLOT_LEVEL_FINALIZED                (4)
     123             : 
     124             : /* Ideally, we would store an entire epoch's worth of transactions.  If
     125             :    we assume any given validator will have at most 5% stake, and average
     126             :    transactions per slot is around 10_000, then an epoch will have about
     127             :    432_000*10_000*0.05 transactions (~2^28).
     128             : 
     129             :    Unfortunately, the transaction struct is 100+ bytes.  If we sized the
     130             :    array to 2^28 entries then the memory required would be ~26GB.  In
     131             :    order to keep memory usage to a more reasonable level, we'll
     132             :    arbitrarily use a fourth of that size. */
     133           0 : #define FD_GUI_TXN_HISTORY_SZ (1UL<<26UL)
     134             : 
     135           0 : #define FD_GUI_TXN_FLAGS_STARTED         ( 1U)
     136           0 : #define FD_GUI_TXN_FLAGS_ENDED           ( 2U)
     137           0 : #define FD_GUI_TXN_FLAGS_IS_SIMPLE_VOTE  ( 4U)
     138           0 : #define FD_GUI_TXN_FLAGS_FROM_BUNDLE     ( 8U)
     139           0 : #define FD_GUI_TXN_FLAGS_LANDED_IN_BLOCK (16U)
     140             : 
     141           0 : #define FD_GUI_TURBINE_RECV_TIMESTAMPS (750UL)
     142             : 
     143             : /* One use case for tracking ingress shred slot is to estimate when we
     144             :    have caught up to the tip of the blockchain.  A naive approach would
     145             :    be to track the maximum seen slot.
     146             : 
     147             :    maximum_seen_slot = fd_ulong_max( maximum_seen_slot, new_slot_from_shred_tile );
     148             : 
     149             :    Unfortunately, this doesn't always work because a validator can send
     150             :    a slot number that is arbitrarily large on a false fork. Also, these
     151             :    shreds can be for a repair response, which can be arbitrarily small.
     152             : 
     153             :    The prospects here seem bleak, but not all hope is lost!  We know
     154             :    that for a sufficiently large historical time window there is a high
     155             :    probability that at least some of the slots we observe will be valid
     156             :    recent turbine slots. For a sufficiently small window there is a high
     157             :    probability that all the observed shred slots are non-malicious (i.e.
     158             :    not arbitrarily large).
     159             : 
     160             :    In practice shred slots are almost always non-malicious. We can keep
     161             :    a history of the 12 largest slots we've seen in the past 4.8 seconds.
     162             :    We'll consider the "tip" of the blockchain to be the maximum slot in
     163             :    our history. This way, if we receive maliciously large slot number,
     164             :    it will be evicted after 4.8 seconds. If we receive a small slot from
     165             :    a repair response it will be ignored because we've seen other larger
     166             :    slots, meaning that our estimate is eventually consistent. For
     167             :    monitoring purposes this is sufficient.
     168             : 
     169             :    The worst case scenario is that this validator receives an incorrect
     170             :    shred slot slot more than once every 3 leader rotations. Before the
     171             :    previous incorrect slot is evicted from the history, a new one takes
     172             :    it's place and we wouldn't never get a correct estimate of the tip of
     173             :    the chain.  We also would indefinitely think that that we haven't
     174             :    caught up. This would require the chain having perpetually malicious
     175             :    leaders with adjacent rotations.  If this happens, Solana has bigger
     176             :    problems. */
     177           0 : #define FD_GUI_TURBINE_SLOT_HISTORY_SZ (  12UL )
     178             : 
     179             : /* Like the turbine slot, the latest repair slot can also swing to
     180             :    arbitrarily large values due to a malicious fork switch.  The gui
     181             :    provides the same guarantees for freshness and accuracy.  This
     182             :    history is somewhat larger to handle the increased repair bandwidth
     183             :    during catch up. */
     184           0 : #define FD_GUI_REPAIR_SLOT_HISTORY_SZ  ( 512UL )
     185             : 
     186             : /* FD_GUI_*_CATCH_UP_HISTORY_SZ is the capacity of the record of slots
     187             :    seen from repair or turbine during the catch up stage at startup.
     188             :    These buffers are run-length encoded, so they will typically be very
     189             :    small.  The worst-case scenario is unbounded, so bounds here are
     190             :    determined heuristically. */
     191           0 : #define FD_GUI_REPAIR_CATCH_UP_HISTORY_SZ  (4096UL)
     192           0 : #define FD_GUI_TURBINE_CATCH_UP_HISTORY_SZ (4096UL)
     193             : 
     194             : /* FD_GUI_SHREDS_STAGING_SZ is number of shred events we'll retain in
     195             :    in a small staging area.  The lifecycle of a shred looks something
     196             :    like the following
     197             : 
     198             :    states] turbine -> repairing (optional) ->  processing                   -> waiting_for_siblings -> slot_complete
     199             :    events]         ^-repair_requested      ^-shred_received/shred_repaired  ^-shred_replayed        ^-max(shred_replayed)
     200             : 
     201             :    We're interested in recording timestamps for state transitions (which
     202             :    these docs call "shred events").  Unfortunately, due to forking,
     203             :    duplicate packets, etc we can't make any guarantees about ordering or
     204             :    uniqueness for these event timestamps.  Instead the GUI just records
     205             :    timestamps for all events as they occur and put them into an array.
     206             :    Newly recorded event timestamps are also broadcast live to WebSocket
     207             :    consumers.
     208             : 
     209             :    The amount of shred events for non-finalized blocks can't really be
     210             :    bounded, so we use generous estimates here to set a memory bound. */
     211           0 : #define FD_GUI_MAX_SHREDS_PER_BLOCK  (32UL*1024UL)
     212           0 : #define FD_GUI_MAX_EVENTS_PER_SHRED  (       32UL)
     213           0 : #define FD_GUI_SHREDS_STAGING_SZ     (32UL * FD_GUI_MAX_SHREDS_PER_BLOCK * FD_GUI_MAX_EVENTS_PER_SHRED)
     214             : 
     215             : /* FD_GUI_SHREDS_HISTORY_SZ the number of shred events in our historical
     216             :    shred store.  Shred events here belong to finalized slots which means
     217             :    we won't record any additional shred updates for these slots.
     218             : 
     219             :    All shred events for a given slot will be places in a contiguous
     220             :    chunk in the array, and the bounding indicies are stored in the
     221             :    fd_gui_slot_t slot history.  Within a slot chunk, shred events are
     222             :    ordered in the ordered they were recorded by the gui tile.
     223             : 
     224             :    Ideally, we have enough space to store an epoch's worth of events,
     225             :    but we are limited by realistic memory consumption.  Instead, we pick
     226             :    bound heuristically. */
     227           0 : #define FD_GUI_SHREDS_HISTORY_SZ     (432000UL*2000UL*4UL / 6UL)
     228             : 
     229           0 : #define FD_GUI_SLOT_SHRED_REPAIR_REQUEST          (0UL)
     230           0 : #define FD_GUI_SLOT_SHRED_SHRED_RECEIVED_TURBINE  (1UL)
     231           0 : #define FD_GUI_SLOT_SHRED_SHRED_RECEIVED_REPAIR   (2UL)
     232           0 : #define FD_GUI_SLOT_SHRED_SHRED_REPLAY_EXEC_DONE  (3UL)
     233           0 : #define FD_GUI_SLOT_SHRED_SHRED_SLOT_COMPLETE     (4UL)
     234             : /* #define FD_GUI_SLOT_SHRED_SHRED_REPLAY_EXEC_START (5UL) // UNUSED */
     235           0 : #define FD_GUI_SLOT_SHRED_SHRED_PUBLISHED         (6UL)
     236             : 
     237           0 : #define FD_GUI_SLOT_RANKINGS_SZ (100UL)
     238           0 : #define FD_GUI_SLOT_RANKING_TYPE_ASC  (0)
     239           0 : #define FD_GUI_SLOT_RANKING_TYPE_DESC (1)
     240             : 
     241             : struct fd_gui_tile_timers {
     242             :   ulong timers[ FD_METRICS_ENUM_TILE_REGIME_CNT ];
     243             :   ulong sched_timers[ FD_METRICS_ENUM_CPU_REGIME_CNT ];
     244             : 
     245             :   int    in_backp;
     246             :   ushort last_cpu;
     247             :   uchar  status;
     248             :   ulong  heartbeat;
     249             :   ulong  backp_cnt;
     250             :   ulong  nvcsw;
     251             :   ulong  nivcsw;
     252             :   ulong  minflt;
     253             :   ulong  majflt;
     254             : };
     255             : 
     256             : typedef struct fd_gui_tile_timers fd_gui_tile_timers_t;
     257             : 
     258             : struct fd_gui_scheduler_counts {
     259             :   long sample_time_ns;
     260             :   ulong regular;
     261             :   ulong votes;
     262             :   ulong conflicting;
     263             :   ulong bundles;
     264             : };
     265             : 
     266             : typedef struct fd_gui_scheduler_counts fd_gui_scheduler_counts_t;
     267             : 
     268             : struct fd_gui_network_stats {
     269             :   /* total bytes accumulated */
     270             :   struct {
     271             :     ulong turbine;
     272             :     ulong gossip;
     273             :     ulong tpu;
     274             :     ulong repair;
     275             :     ulong metric;
     276             :   } in, out;
     277             : };
     278             : 
     279             : typedef struct fd_gui_network_stats fd_gui_network_stats_t;
     280             : 
     281             : struct fd_gui_leader_slot {
     282             :   ulong slot;
     283             :   fd_hash_t block_hash;
     284             :   long  leader_start_time; /* UNIX timestamp of when we first became leader in this slot */
     285             :   long  leader_end_time;   /* UNIX timestamp of when we stopped being leader in this slot */
     286             : 
     287             :   /* Stem tiles can exist in one of 8 distinct activity regimes at any
     288             :      given moment.  One of these regimes, caughtup_postfrag, is the
     289             :      only regime where a tile is in a spin loop without doing any
     290             :      useful work.  This info is useful from a monitoring perspective
     291             :      because it lets us estimate CPU utilization on a pinned core.
     292             : 
     293             :      Every 10ms, the gui tile samples the amount of time tiles spent
     294             :      in each regime in the past 10ms.  This sample is used to infer
     295             :      the CPU utilization in the past 10ms.  This utilization is
     296             :      streamed live to WebSocket clients.
     297             : 
     298             :      In additional to live utilization, we are interested in recording
     299             :      utilization during one of this validator's leader slots.  The gui
     300             :      tile is continuously recording samples to storage with capacity
     301             :      FD_GUI_TILE_TIMER_SNAP_CNT. The sample index is recorded at the
     302             :      start and end of a leader slot, and the number of samples is
     303             :      downsampled to be at most FD_GUI_TILE_TIMER_LEADER_DOWNSAMPLE_CNT
     304             :      samples (e.g. if there was an unusually long leader slot) and
     305             :      inserted into historical storage with capacity FD_GUI_LEADER_CNT.
     306             :      FD_GUI_TILE_TIMER_TILE_CNT is the maximum number of tiles supported. */
     307             :   fd_gui_tile_timers_t tile_timers[ FD_GUI_TILE_TIMER_LEADER_DOWNSAMPLE_CNT ][ FD_GUI_TILE_TIMER_TILE_CNT ];
     308             :   ulong                tile_timers_sample_cnt;
     309             : 
     310             :   fd_gui_scheduler_counts_t scheduler_counts[ FD_GUI_SCHEDULER_COUNT_LEADER_DOWNSAMPLE_CNT ][ 1 ];
     311             :   ulong                     scheduler_counts_sample_cnt;
     312             : 
     313             :   struct {
     314             :     uint microblocks_upper_bound; /* An upper bound on the number of microblocks in the slot.  If the number of
     315             :                                      microblocks observed is equal to this, the slot can be considered over.
     316             :                                      Generally, the bound is set to a "final" state by a done packing message,
     317             :                                      which sets it to the exact number of microblocks, but sometimes this message
     318             :                                      is not sent, if the max upper bound published by poh was already correct. */
     319             :     uint begin_microblocks; /* The number of microblocks we have seen be started (sent) from pack to banks. */
     320             :     uint end_microblocks;   /* The number of microblocks we have seen be ended (sent) from banks to poh.  The
     321             :                                slot is only considered over if the begin and end microblocks seen are both equal
     322             :                                to the microblock upper bound. */
     323             : 
     324             :     ulong   start_offset; /* The smallest pack transaction index for this slot. The first transaction for this slot will
     325             :                              be written to gui->txs[ start_offset%FD_GUI_TXN_HISTORY_SZ ]. */
     326             :     ulong   end_offset;   /* The largest pack transaction index for this slot, plus 1. The last transaction for this
     327             :                              slot will be written to gui->txs[ (start_offset-1)%FD_GUI_TXN_HISTORY_SZ ]. */
     328             :   } txs;
     329             : 
     330             :   fd_done_packing_t scheduler_stats[ 1 ];
     331             : 
     332             :   uchar unbecame_leader: 1;
     333             : };
     334             : 
     335             : typedef struct fd_gui_leader_slot fd_gui_leader_slot_t;
     336             : 
     337             : struct fd_gui_turbine_slot {
     338             :  ulong slot;
     339             :  long timestamp;
     340             : };
     341             : 
     342             : typedef struct fd_gui_turbine_slot fd_gui_turbine_slot_t;
     343             : 
     344             : struct fd_gui_slot_completed {
     345             :   ulong slot;
     346             :   long  completed_time;
     347             :   ulong parent_slot;
     348             :   uint  max_compute_units;
     349             :   uint  total_txn_cnt;
     350             :   uint  vote_txn_cnt;
     351             :   uint  failed_txn_cnt;
     352             :   uint  nonvote_failed_txn_cnt;
     353             :   ulong transaction_fee;
     354             :   ulong priority_fee;
     355             :   ulong tips;
     356             :   uint  compute_units;
     357             :   uint  shred_cnt;
     358             : };
     359             : 
     360             : typedef struct fd_gui_slot_completed fd_gui_slot_completed_t;
     361             : 
     362             : struct fd_gui_slot_staged_shred_event {
     363             :   long   timestamp;
     364             :   ulong  slot;
     365             :   ushort shred_idx;
     366             :   uchar  event;
     367             : };
     368             : 
     369             : typedef struct fd_gui_slot_staged_shred_event fd_gui_slot_staged_shred_event_t;
     370             : 
     371             : struct __attribute__((packed)) fd_gui_slot_history_shred_event {
     372             :   long   timestamp;
     373             :   ushort shred_idx;
     374             :   uchar  event;
     375             : };
     376             : 
     377             : typedef struct fd_gui_slot_history_shred_event fd_gui_slot_history_shred_event_t;
     378             : 
     379             : struct fd_gui_slot_ranking {
     380             :   ulong slot;
     381             :   ulong value;
     382             :   int   type;
     383             : };
     384             : typedef struct fd_gui_slot_ranking fd_gui_slot_ranking_t;
     385             : 
     386             : struct fd_gui_slot_rankings {
     387             :   fd_gui_slot_ranking_t largest_tips           [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     388             :   fd_gui_slot_ranking_t largest_fees           [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     389             :   fd_gui_slot_ranking_t largest_rewards        [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     390             :   fd_gui_slot_ranking_t largest_duration       [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     391             :   fd_gui_slot_ranking_t largest_compute_units  [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     392             :   fd_gui_slot_ranking_t largest_skipped        [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     393             :   fd_gui_slot_ranking_t largest_rewards_per_cu [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     394             :   fd_gui_slot_ranking_t smallest_tips          [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     395             :   fd_gui_slot_ranking_t smallest_fees          [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     396             :   fd_gui_slot_ranking_t smallest_rewards       [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     397             :   fd_gui_slot_ranking_t smallest_rewards_per_cu[ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     398             :   fd_gui_slot_ranking_t smallest_duration      [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     399             :   fd_gui_slot_ranking_t smallest_compute_units [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     400             :   fd_gui_slot_ranking_t smallest_skipped       [ FD_GUI_SLOT_RANKINGS_SZ+1UL ];
     401             : };
     402             : 
     403             : typedef struct fd_gui_slot_rankings fd_gui_slot_rankings_t;
     404             : 
     405             : struct fd_gui_ephemeral_slot {
     406             :   ulong slot; /* ULONG_MAX indicates invalid/evicted */
     407             :   long timestamp_arrival_nanos;
     408             : };
     409             : typedef struct fd_gui_ephemeral_slot fd_gui_ephemeral_slot_t;
     410             : 
     411             : struct __attribute__((packed)) fd_gui_txn {
     412             :   uchar signature[ FD_TXN_SIGNATURE_SZ ];
     413             :   ulong transaction_fee;
     414             :   ulong priority_fee;
     415             :   ulong tips;
     416             :   long timestamp_arrival_nanos;
     417             : 
     418             :   /* compute_units_requested has both execution and non-execution cus */
     419             :   uint compute_units_requested : 21; /* <= 1.4M */
     420             :   uint compute_units_consumed  : 21; /* <= 1.4M */
     421             :   uint bank_idx                :  6; /* in [0, 64) */
     422             :   uint error_code              :  6; /* in [0, 64) */
     423             :   int timestamp_delta_start_nanos;
     424             :   int timestamp_delta_end_nanos;
     425             : 
     426             :   /* txn_{}_pct is used as a fraction of the total microblock
     427             :      duration. For example, txn_load_end_pct can be used to find the
     428             :      time when this transaction started executing:
     429             : 
     430             :      timestamp_delta_start_exec_nanos = (
     431             :        (timestamp_delta_end_nanos-timestamp_delta_start_nanos) *
     432             :        ((double)txn_{}_pct/USHORT_MAX)
     433             :      ) */
     434             :   uchar txn_start_pct;
     435             :   uchar txn_load_end_pct;
     436             :   uchar txn_end_pct;
     437             :   uchar txn_preload_end_pct;
     438             :   uchar flags; /* assigned with the FD_GUI_TXN_FLAGS_* macros */
     439             :   uchar source_tpu; /* FD_TXN_M_TPU_SOURCE_* */
     440             :   uint  source_ipv4;
     441             :   uint  microblock_idx;
     442             : };
     443             : 
     444             : typedef struct fd_gui_txn fd_gui_txn_t;
     445             : 
     446             : struct fd_gui_txn_waterfall {
     447             :   struct {
     448             :     ulong quic;
     449             :     ulong udp;
     450             :     ulong gossip;
     451             :     ulong block_engine;
     452             :     ulong pack_cranked;
     453             :   } in;
     454             : 
     455             :   struct {
     456             :     ulong net_overrun;
     457             :     ulong quic_overrun;
     458             :     ulong quic_frag_drop;
     459             :     ulong quic_abandoned;
     460             :     ulong tpu_quic_invalid;
     461             :     ulong tpu_udp_invalid;
     462             :     ulong verify_overrun;
     463             :     ulong verify_parse;
     464             :     ulong verify_failed;
     465             :     ulong verify_duplicate;
     466             :     ulong dedup_duplicate;
     467             :     ulong resolv_lut_failed;
     468             :     ulong resolv_expired;
     469             :     ulong resolv_ancient;
     470             :     ulong resolv_no_ledger;
     471             :     ulong resolv_retained;
     472             :     ulong pack_invalid;
     473             :     ulong pack_invalid_bundle;
     474             :     ulong pack_expired;
     475             :     ulong pack_already_executed;
     476             :     ulong pack_retained;
     477             :     ulong pack_wait_full;
     478             :     ulong pack_leader_slow;
     479             :     ulong bank_invalid;
     480             :     ulong bank_nonce_already_advanced;
     481             :     ulong bank_nonce_advance_failed;
     482             :     ulong bank_nonce_wrong_blockhash;
     483             :     ulong block_success;
     484             :     ulong block_fail;
     485             :   } out;
     486             : };
     487             : 
     488             : typedef struct fd_gui_txn_waterfall fd_gui_txn_waterfall_t;
     489             : 
     490             : struct fd_gui_tile_stats {
     491             :   long  sample_time_nanos;
     492             : 
     493             :   ulong net_in_rx_bytes;           /* Number of bytes received by the net or sock tile*/
     494             :   ulong quic_conn_cnt;             /* Number of active QUIC connections */
     495             :   fd_histf_t bundle_rx_delay_hist; /* Histogram of bundle rx delay */
     496             :   ulong bundle_rtt_smoothed_nanos; /* RTT (nanoseconds) moving average */
     497             :   ulong verify_drop_cnt;           /* Number of transactions dropped by verify tiles */
     498             :   ulong verify_total_cnt;          /* Number of transactions received by verify tiles */
     499             :   ulong dedup_drop_cnt;            /* Number of transactions dropped by dedup tile */
     500             :   ulong dedup_total_cnt;           /* Number of transactions received by dedup tile */
     501             :   ulong pack_buffer_cnt;           /* Number of buffered transactions in the pack tile */
     502             :   ulong pack_buffer_capacity;      /* Total size of the pack transaction buffer */
     503             :   ulong bank_txn_exec_cnt;         /* Number of transactions processed by the bank tile */
     504             :   ulong net_out_tx_bytes;          /* Number of bytes sent by the net or sock tile */
     505             : };
     506             : 
     507             : typedef struct fd_gui_tile_stats fd_gui_tile_stats_t;
     508             : 
     509             : struct fd_gui_slot {
     510             :   ulong slot;
     511             :   ulong parent_slot;
     512             :   ulong vote_slot;
     513             :   ulong reset_slot;
     514             :   long  completed_time;
     515             :   uint  max_compute_units;
     516             :   int   mine;
     517             :   int   skipped;
     518             :   int   must_republish;
     519             :   int   level;
     520             :   uint  total_txn_cnt;
     521             :   uint  vote_txn_cnt;
     522             :   uint  failed_txn_cnt;
     523             :   uint  nonvote_failed_txn_cnt;
     524             :   uint  compute_units;
     525             :   ulong transaction_fee;
     526             :   ulong priority_fee;
     527             :   ulong tips;
     528             :   uint  shred_cnt;
     529             :   uchar vote_latency;
     530             : 
     531             :   /* Some slot info is only tracked for our own leader slots. These
     532             :      slots are kept in a separate buffer. */
     533             :   ulong leader_history_idx;
     534             : 
     535             :   fd_gui_txn_waterfall_t waterfall_begin[ 1 ];
     536             :   fd_gui_txn_waterfall_t waterfall_end[ 1 ];
     537             : 
     538             :   fd_gui_tile_stats_t tile_stats_begin[ 1 ];
     539             :   fd_gui_tile_stats_t tile_stats_end[ 1 ];
     540             : 
     541             :   struct {
     542             :     ulong start_offset; /* gui->shreds.history[ start_offset % FD_GUI_SHREDS_HISTORY_SZ ] is the first shred event in
     543             :                            contiguous chunk of events in the shred history corresponding to this slot. */
     544             :     ulong end_offset;   /* gui->shreds.history[ end_offset % FD_GUI_SHREDS_HISTORY_SZ ] is the last shred event in
     545             :                            contiguous chunk of events in the shred history corresponding to this slot. */
     546             :   } shreds;
     547             : };
     548             : 
     549             : typedef struct fd_gui_slot fd_gui_slot_t;
     550             : 
     551             : struct fd_gui {
     552             :   fd_http_server_t * http;
     553             :   fd_topo_t * topo;
     554             : 
     555             :   long next_sample_400millis;
     556             :   long next_sample_100millis;
     557             :   long next_sample_50millis;
     558             :   long next_sample_25millis;
     559             :   long next_sample_10millis;
     560             : 
     561             :   ulong leader_slot;
     562             : 
     563             :   struct {
     564             :     fd_pubkey_t identity_key[ 1 ];
     565             :     int         has_vote_key;
     566             :     fd_pubkey_t vote_key[ 1 ];
     567             :     char vote_key_base58[ FD_BASE58_ENCODED_32_SZ ];
     568             :     char identity_key_base58[ FD_BASE58_ENCODED_32_SZ ];
     569             : 
     570             :     int          is_full_client;
     571             :     char const * version;
     572             :     char const * cluster;
     573             : 
     574             :     ulong vote_distance;
     575             :     int vote_state;
     576             : 
     577             :     long  startup_time_nanos;
     578             : 
     579             :     union {
     580             :       struct { /* frankendancer only */
     581             :       uchar phase;
     582             :       int   startup_got_full_snapshot;
     583             : 
     584             :       ulong  startup_incremental_snapshot_slot;
     585             :       uint   startup_incremental_snapshot_peer_ip_addr;
     586             :         ushort startup_incremental_snapshot_peer_port;
     587             :         double startup_incremental_snapshot_elapsed_secs;
     588             :         double startup_incremental_snapshot_remaining_secs;
     589             :         double startup_incremental_snapshot_throughput;
     590             :         ulong  startup_incremental_snapshot_total_bytes;
     591             :         ulong  startup_incremental_snapshot_current_bytes;
     592             : 
     593             :         ulong  startup_full_snapshot_slot;
     594             :         uint   startup_full_snapshot_peer_ip_addr;
     595             :         ushort startup_full_snapshot_peer_port;
     596             :         double startup_full_snapshot_elapsed_secs;
     597             :         double startup_full_snapshot_remaining_secs;
     598             :         double startup_full_snapshot_throughput;
     599             :         ulong  startup_full_snapshot_total_bytes;
     600             :         ulong  startup_full_snapshot_current_bytes;
     601             : 
     602             :         ulong startup_ledger_slot;
     603             :         ulong startup_ledger_max_slot;
     604             : 
     605             :         ulong startup_waiting_for_supermajority_slot;
     606             :         ulong startup_waiting_for_supermajority_stake_pct;
     607             :       } startup_progress;
     608             :       struct { /* used in the full client */
     609             :         uchar phase;
     610             :         long joining_gossip_time_nanos;
     611             :         struct {
     612             :           ulong  slot;
     613             :           uint   peer_addr;
     614             :           ushort peer_port;
     615             :           ulong  total_bytes_compressed;
     616             :           long   reset_time_nanos;          /* UNIX nanosecond timestamp */
     617             :           long   sample_time_nanos;
     618             :           ulong  reset_cnt;
     619             : 
     620             :           ulong read_bytes_compressed;
     621             :           char  read_path[ PATH_MAX+30UL ]; /* URL or filesystem path.  30 is fd_cstr_nlen( "https://255.255.255.255:12345/", ULONG_MAX ) */
     622             : 
     623             :           ulong decompress_bytes_decompressed;
     624             :           ulong decompress_bytes_compressed;
     625             : 
     626             :           ulong insert_bytes_decompressed;
     627             :           char  insert_path[ PATH_MAX ];
     628             :           ulong insert_accounts_current;
     629             :         } loading_snapshot[ FD_GUI_BOOT_PROGRESS_SNAPSHOT_CNT ];
     630             : 
     631             :         long  catching_up_time_nanos;
     632             :         ulong catching_up_first_replay_slot;
     633             :       } boot_progress;
     634             :     };
     635             : 
     636             :     int schedule_strategy;
     637             : 
     638             :     ulong identity_account_balance;
     639             :     ulong vote_account_balance;
     640             :     ulong estimated_slot_duration_nanos;
     641             : 
     642             :     ulong sock_tile_cnt;
     643             :     ulong net_tile_cnt;
     644             :     ulong quic_tile_cnt;
     645             :     ulong verify_tile_cnt;
     646             :     ulong resolh_tile_cnt;
     647             :     ulong resolv_tile_cnt;
     648             :     ulong bank_tile_cnt;
     649             :     ulong execle_tile_cnt;
     650             :     ulong shred_tile_cnt;
     651             : 
     652             :     ulong slot_rooted;
     653             :     ulong slot_optimistically_confirmed;
     654             :     ulong slot_completed;
     655             :     ulong slot_estimated;
     656             :     ulong slot_caught_up;
     657             :     ulong slot_repair;
     658             :     ulong slot_turbine;
     659             :     ulong slot_reset;
     660             :     ulong slot_storage;
     661             :     ulong active_fork_cnt;
     662             : 
     663             :     fd_gui_ephemeral_slot_t slots_max_turbine[ FD_GUI_TURBINE_SLOT_HISTORY_SZ+1UL ];
     664             :     fd_gui_ephemeral_slot_t slots_max_repair [ FD_GUI_REPAIR_SLOT_HISTORY_SZ +1UL ];
     665             : 
     666             :     /* catchup_* and late_votes are run-length encoded. i.e. adjacent
     667             :        pairs represent contiguous runs */
     668             :     ulong catch_up_turbine[ FD_GUI_TURBINE_CATCH_UP_HISTORY_SZ ];
     669             :     ulong catch_up_turbine_sz;
     670             : 
     671             :     ulong catch_up_repair[ FD_GUI_REPAIR_CATCH_UP_HISTORY_SZ ];
     672             :     ulong catch_up_repair_sz;
     673             : 
     674             :     ulong late_votes[ MAX_SLOTS_PER_EPOCH ];
     675             :     ulong late_votes_sz;
     676             : 
     677             :     ulong estimated_tps_history_idx;
     678             :     ulong estimated_tps_history[ FD_GUI_TPS_HISTORY_SAMPLE_CNT ][ 3UL ];
     679             : 
     680             :     fd_gui_network_stats_t network_stats_current[ 1 ];
     681             : 
     682             :     fd_gui_txn_waterfall_t txn_waterfall_reference[ 1 ];
     683             :     fd_gui_txn_waterfall_t txn_waterfall_current[ 1 ];
     684             : 
     685             :     fd_gui_tile_stats_t tile_stats_reference[ 1 ];
     686             :     fd_gui_tile_stats_t tile_stats_current[ 1 ];
     687             : 
     688             :     ulong                tile_timers_snap_idx;
     689             :     ulong                tile_timers_snap_idx_slot_start;
     690             :     /* Temporary storage for samples. Will be downsampled into leader history on slot end. */
     691             :     fd_gui_tile_timers_t tile_timers_snap[ FD_GUI_TILE_TIMER_SNAP_CNT ][ FD_GUI_TILE_TIMER_TILE_CNT ];
     692             : 
     693             :     ulong                     scheduler_counts_snap_idx;
     694             :     ulong                     scheduler_counts_snap_idx_slot_start;
     695             :     /* Temporary storage for samples. Will be downsampled into leader history on slot end. */
     696             :     fd_gui_scheduler_counts_t scheduler_counts_snap[ FD_GUI_SCHEDULER_COUNT_SNAP_CNT ][ 1 ];
     697             :   } summary;
     698             : 
     699             :   fd_gui_slot_t slots[ FD_GUI_SLOTS_CNT ][ 1 ];
     700             : 
     701             :   /* used for estimating slot duration */
     702             :   fd_gui_turbine_slot_t turbine_slots[ FD_GUI_TURBINE_RECV_TIMESTAMPS ];
     703             : 
     704             :   fd_gui_leader_slot_t leader_slots[ FD_GUI_LEADER_CNT ][ 1 ];
     705             :   ulong leader_slots_cnt;
     706             : 
     707             :   fd_gui_txn_t txs[ FD_GUI_TXN_HISTORY_SZ ][ 1 ];
     708             :   ulong pack_txn_idx; /* The pack index of the most recently received transaction */
     709             : 
     710             :   ulong tower_cnt;
     711             :   fd_vote_acc_vote_t tower[ FD_TOWER_VOTE_MAX ];
     712             : 
     713             :   struct {
     714             :     int has_block_engine;
     715             :     char name[ 16 ];
     716             :     char url[ 256 ];
     717             :     char ip_cstr[ 40 ]; /* IPv4 or IPv6 cstr */
     718             :     int status;
     719             :   } block_engine;
     720             : 
     721             :   struct {
     722             :     int has_epoch[ 2 ];
     723             : 
     724             :     struct {
     725             :       ulong epoch;
     726             :       long start_time;
     727             :       long end_time;
     728             : 
     729             :       ulong my_total_slots;
     730             :       ulong my_skipped_slots;
     731             : 
     732             :       ulong start_slot;
     733             :       ulong end_slot;
     734             :       ulong excluded_stake;
     735             :       fd_epoch_leaders_t * lsched;
     736             :       uchar __attribute__((aligned(FD_EPOCH_LEADERS_ALIGN))) _lsched[ FD_EPOCH_LEADERS_FOOTPRINT(MAX_STAKED_LEADERS, MAX_SLOTS_PER_EPOCH) ];
     737             :       fd_vote_stake_weight_t stakes[ MAX_STAKED_LEADERS ];
     738             : 
     739             :       ulong rankings_slot; /* One more than the largest slot we've processed into our rankings */
     740             :       fd_gui_slot_rankings_t rankings[ 1 ]; /* global slot rankings */
     741             :       fd_gui_slot_rankings_t my_rankings[ 1 ]; /* my slots only */
     742             :     } epochs[ 2 ];
     743             :   } epoch;
     744             : 
     745             :   struct {  /* frankendancer only */
     746             :     ulong                     peer_cnt;
     747             :     struct fd_gui_gossip_peer peers[ FD_GUI_MAX_PEER_CNT ];
     748             :   } gossip;
     749             : 
     750             :   struct {  /* frankendancer only */
     751             :     ulong                      vote_account_cnt;
     752             :     struct fd_gui_vote_account vote_accounts[ FD_GUI_MAX_PEER_CNT ];
     753             :   } vote_account;
     754             : 
     755             :   struct {  /* frankendancer only */
     756             :     ulong                        info_cnt;
     757             :     struct fd_gui_validator_info info[ FD_GUI_MAX_PEER_CNT ];
     758             :   } validator_info;
     759             : 
     760             :   fd_gui_peers_ctx_t * peers; /* full-client */
     761             : 
     762             :   struct {
     763             :     ulong leader_shred_cnt;      /* A gauge counting the number of leader shreds seen on the SHRED_OUT link.  Resets at
     764             :                                     the end of a leader slot.  This works because leader fecs are published in order. */
     765             :     ulong staged_next_broadcast; /* staged[ staged_next_broadcast % FD_GUI_SHREDS_STAGING_SZ ] is the first shred event
     766             :                                     that hasn't yet been broadcast to WebSocket clients */
     767             :     ulong staged_head;            /* staged_head % FD_GUI_SHREDS_STAGING_SZ is the first valid event in staged */
     768             :     ulong staged_tail;            /* staged_tail % FD_GUI_SHREDS_STAGING_SZ is one past the last valid event in staged */
     769             :     fd_gui_slot_staged_shred_event_t  staged [ FD_GUI_SHREDS_STAGING_SZ ];
     770             : 
     771             :     ulong history_slot;          /* the largest slot store in history */
     772             :     ulong history_tail;          /* history_tail % FD_GUI_SHREDS_HISTORY_SZ is one past the last valid event in history */
     773             :     fd_gui_slot_history_shred_event_t history[ FD_GUI_SHREDS_HISTORY_SZ ];
     774             : 
     775             :     /* scratch space for stable sorts */
     776             :     fd_gui_slot_staged_shred_event_t _staged_scratch [ FD_GUI_SHREDS_STAGING_SZ ];
     777             :     fd_gui_slot_staged_shred_event_t _staged_scratch2[ FD_GUI_SHREDS_STAGING_SZ ];
     778             :   } shreds; /* full client */
     779             : };
     780             : 
     781             : typedef struct fd_gui fd_gui_t;
     782             : 
     783             : FD_PROTOTYPES_BEGIN
     784             : 
     785             : FD_FN_CONST ulong
     786             : fd_gui_align( void );
     787             : 
     788             : FD_FN_CONST ulong
     789             : fd_gui_footprint( void );
     790             : 
     791             : void *
     792             : fd_gui_new( void *                shmem,
     793             :             fd_http_server_t *    http,
     794             :             char const *          version,
     795             :             char const *          cluster,
     796             :             uchar const *         identity_key,
     797             :             int                   has_vote_key,
     798             :             uchar const *         vote_key,
     799             :             int                   is_full_client,
     800             :             int                   snapshots_enabled,
     801             :             int                   is_voting,
     802             :             int                   schedule_strategy,
     803             :             fd_topo_t *           topo,
     804             :             long                  now );
     805             : 
     806             : fd_gui_t *
     807             : fd_gui_join( void * shmem );
     808             : 
     809             : void
     810             : fd_gui_set_identity( fd_gui_t *    gui,
     811             :                      uchar const * identity_pubkey );
     812             : 
     813             : void
     814             : fd_gui_ws_open( fd_gui_t *  gui,
     815             :                 ulong       conn_id,
     816             :                 long now );
     817             : 
     818             : int
     819             : fd_gui_ws_message( fd_gui_t *    gui,
     820             :                    ulong         ws_conn_id,
     821             :                    uchar const * data,
     822             :                    ulong         data_len );
     823             : 
     824             : void
     825             : fd_gui_plugin_message( fd_gui_t *    gui,
     826             :                        ulong         plugin_msg,
     827             :                        uchar const * msg,
     828             :                        long          now );
     829             : 
     830             : void
     831             : fd_gui_became_leader( fd_gui_t * gui,
     832             :                       ulong      slot,
     833             :                       long       start_time_nanos,
     834             :                       long       end_time_nanos,
     835             :                       ulong      max_compute_units,
     836             :                       ulong      max_microblocks );
     837             : 
     838             : void
     839             : fd_gui_unbecame_leader( fd_gui_t *                gui,
     840             :                         ulong                     _slot,
     841             :                         fd_done_packing_t const * done_packing,
     842             :                         long                      now );
     843             : 
     844             : void
     845             : fd_gui_microblock_execution_begin( fd_gui_t *   gui,
     846             :                                    long         now,
     847             :                                    ulong        _slot,
     848             :                                    fd_txn_e_t * txns,
     849             :                                    ulong        txn_cnt,
     850             :                                    uint         microblock_idx,
     851             :                                    ulong        pack_txn_idx );
     852             : 
     853             : void
     854             : fd_gui_microblock_execution_end( fd_gui_t *   gui,
     855             :                                  long         now,
     856             :                                  ulong        bank_idx,
     857             :                                  ulong        _slot,
     858             :                                  ulong        txn_cnt,
     859             :                                  fd_txn_p_t * txns,
     860             :                                  ulong        pack_txn_idx,
     861             :                                  uchar        txn_start_pct,
     862             :                                  uchar        txn_load_end_pct,
     863             :                                  uchar        txn_end_pct,
     864             :                                  uchar        txn_preload_end_pct,
     865             :                                  ulong        tips );
     866             : 
     867             : int
     868             : fd_gui_poll( fd_gui_t * gui, long now );
     869             : 
     870             : void
     871             : fd_gui_handle_block_engine_update( fd_gui_t *                              gui,
     872             :                                    fd_bundle_block_engine_update_t const * update );
     873             : 
     874             : void
     875             : fd_gui_handle_shred( fd_gui_t * gui,
     876             :                      ulong      slot,
     877             :                      ulong      shred_idx,
     878             :                      int        is_turbine,
     879             :                      long       tsorig );
     880             : 
     881             : void
     882             : fd_gui_handle_leader_fec( fd_gui_t * gui,
     883             :                           ulong      slot,
     884             :                           ulong      fec_shred_cnt,
     885             :                           int        is_end_of_slot,
     886             :                           long       tsorig );
     887             : 
     888             : void
     889             : fd_gui_handle_exec_txn_done( fd_gui_t * gui,
     890             :                              ulong      slot,
     891             :                              ulong      start_shred_idx,
     892             :                              ulong      end_shred_idx,
     893             :                              long       tsorig_ns,
     894             :                              long       tspub_ns );
     895             : 
     896             : void
     897             : fd_gui_handle_repair_slot( fd_gui_t * gui, ulong slot, long now );
     898             : 
     899             : void
     900             : fd_gui_handle_repair_request( fd_gui_t * gui, ulong slot, ulong shred_idx, long now );
     901             : 
     902             : void
     903             : fd_gui_handle_snapshot_update( fd_gui_t *                 gui,
     904             :                                fd_snapct_update_t const * msg );
     905             : 
     906             : void
     907             : fd_gui_handle_leader_schedule( fd_gui_t *                    gui,
     908             :                                fd_stake_weight_msg_t const * leader_schedule,
     909             :                                long                          now );
     910             : 
     911             : void
     912             : fd_gui_handle_epoch_info( fd_gui_t *                  gui,
     913             :                           fd_epoch_info_msg_t const * epoch_info,
     914             :                           long                        now );
     915             : 
     916             : void
     917             : fd_gui_handle_notarization_update( fd_gui_t *                        gui,
     918             :                                    fd_tower_slot_confirmed_t const * notar );
     919             : 
     920             : void
     921             : fd_gui_handle_tower_update( fd_gui_t *                   gui,
     922             :                             fd_tower_slot_done_t const * msg,
     923             :                             long                         now );
     924             : 
     925             : void
     926             : fd_gui_handle_replay_update( fd_gui_t *                gui,
     927             :                              fd_gui_slot_completed_t * slot_completed,
     928             :                              fd_hash_t const *         block_hash,
     929             :                              ulong                     vote_slot,
     930             :                              ulong                     storage_slot,
     931             :                              ulong                     root_slot,
     932             :                              ulong                     identity_balance,
     933             :                              long                      now );
     934             : 
     935             : void
     936             : fd_gui_handle_genesis_hash( fd_gui_t *    gui,
     937             :                             uchar const * msg );
     938             : 
     939             : static inline ulong
     940           0 : fd_gui_current_epoch_idx( fd_gui_t * gui ) {
     941           0 :   ulong epoch_idx = ULONG_MAX;
     942           0 :   ulong epoch     = ULONG_MAX;
     943           0 :   for( ulong i = 0UL; i<2UL; i++ ) {
     944           0 :     if( FD_LIKELY( gui->epoch.has_epoch[ i ] ) ) {
     945             :       /* the "current" epoch is the smaller one */
     946           0 :       if( FD_LIKELY( gui->epoch.epochs[ i ].epoch<epoch ) ) {
     947           0 :         epoch = gui->epoch.epochs[ i ].epoch;
     948           0 :         epoch_idx = i;
     949           0 :       }
     950           0 :     }
     951           0 :   }
     952           0 :   return epoch_idx;
     953           0 : }
     954             : 
     955             : static inline fd_gui_slot_t *
     956           0 : fd_gui_get_slot( fd_gui_t const * gui, ulong _slot ) {
     957           0 :   fd_gui_slot_t const * slot = gui->slots[ _slot % FD_GUI_SLOTS_CNT ];
     958           0 :   if( FD_UNLIKELY( slot->slot==ULONG_MAX || _slot==ULONG_MAX || slot->slot!=_slot ) ) return NULL;
     959           0 :   return (fd_gui_slot_t *)slot;
     960           0 : }
     961             : 
     962             : static inline fd_gui_slot_t const *
     963           0 : fd_gui_get_slot_const( fd_gui_t const * gui, ulong _slot ) {
     964           0 :   return fd_gui_get_slot( gui, _slot );
     965           0 : }
     966             : 
     967             : static inline fd_gui_leader_slot_t *
     968           0 : fd_gui_get_leader_slot( fd_gui_t const * gui, ulong _slot ) {
     969           0 :   fd_gui_slot_t const * slot = fd_gui_get_slot( gui, _slot );
     970           0 :   if( FD_UNLIKELY( !slot
     971           0 :                 || !slot->mine
     972           0 :                 || slot->leader_history_idx==ULONG_MAX
     973           0 :                 || slot->leader_history_idx + FD_GUI_LEADER_CNT < gui->leader_slots_cnt
     974           0 :                 || gui->leader_slots[ slot->leader_history_idx % FD_GUI_LEADER_CNT ]->slot!=_slot ) ) return NULL;
     975           0 :   return (fd_gui_leader_slot_t *)gui->leader_slots[ slot->leader_history_idx % FD_GUI_LEADER_CNT ];
     976           0 : }
     977             : 
     978             : static inline fd_gui_leader_slot_t const *
     979           0 : fd_gui_get_leader_slot_const( fd_gui_t const * gui, ulong _slot ) {
     980           0 :   return fd_gui_get_leader_slot( gui, _slot );
     981           0 : }
     982             : 
     983             : /* fd_gui_get_root_slot returns a handle to the closest ancestor of slot
     984             :    that is a root, if available, otherwise NULL. */
     985             : static inline fd_gui_slot_t *
     986             : fd_gui_get_root_slot( fd_gui_t const * gui,
     987           0 :                       ulong            slot ) {
     988           0 :   fd_gui_slot_t * c = fd_gui_get_slot( gui, slot );
     989           0 :   while( c ) {
     990           0 :     if( FD_UNLIKELY( c->level>=FD_GUI_SLOT_LEVEL_ROOTED ) ) return c;
     991           0 :     c = fd_gui_get_slot( gui, c->parent_slot );
     992           0 :   }
     993           0 :   return NULL;
     994           0 : }
     995             : 
     996             : /* fd_gui_slot_is_ancestor returns 1 if anc is known to be an ancestor
     997             :    of slot (on the same fork), 0 otherwise. */
     998             : static inline int
     999             : fd_gui_slot_is_ancestor( fd_gui_t const * gui,
    1000             :                          ulong            anc,
    1001           0 :                          ulong            slot ) {
    1002           0 :   fd_gui_slot_t * c = fd_gui_get_slot( gui, slot );
    1003           0 :   while( c ) {
    1004           0 :     if( FD_UNLIKELY( c->slot==anc ) ) return 1;
    1005           0 :     c = fd_gui_get_slot( gui, c->parent_slot );
    1006           0 :   }
    1007           0 :   return 0;
    1008           0 : }
    1009             : 
    1010             : /* fd_gui_get_parent_slot_on_fork returns a handle to the parent of slot
    1011             :    on the fork ending on frontier_slot.  If slot is unknown or skipped,
    1012             :    the closest (by slot number) valid parent on the fork is returned.
    1013             : 
    1014             :    NULL if slot is not an ancestor of frontier slot or if the parent is
    1015             :    unknown. */
    1016             : static inline fd_gui_slot_t *
    1017             : fd_gui_get_parent_slot_on_fork( fd_gui_t const * gui,
    1018             :                                 ulong            frontier_slot,
    1019           0 :                                 ulong            slot ) {
    1020           0 :   fd_gui_slot_t * c = fd_gui_get_slot( gui, frontier_slot );
    1021           0 :   while( c ) {
    1022           0 :     if( FD_UNLIKELY( c->slot<=slot ) ) return NULL;
    1023           0 :     fd_gui_slot_t * p = fd_gui_get_slot( gui, c->parent_slot );
    1024           0 :     if( FD_UNLIKELY( p && p->slot<=slot-1UL ) ) return p;
    1025           0 :     c = p;
    1026           0 :   }
    1027           0 :   return NULL;
    1028           0 : }
    1029             : 
    1030             : /* fd_gui_is_skipped_on_fork returns 1 if slot is skipped on the fork
    1031             :    starting at anc and ending at des, 0 otherwise. */
    1032             : static inline int
    1033             : fd_gui_is_skipped_on_fork( fd_gui_t const * gui,
    1034             :                            ulong            anc,
    1035             :                            ulong            des,
    1036           0 :                            ulong            slot ) {
    1037           0 :   fd_gui_slot_t const * c = fd_gui_get_slot( gui, des );
    1038           0 :   while( c ) {
    1039           0 :     if( FD_UNLIKELY( anc==c->slot ) ) return 0; /* on the fork, not skipped */
    1040           0 :     fd_gui_slot_t const * p = fd_gui_get_slot( gui, c->parent_slot );
    1041           0 :     if( FD_UNLIKELY( p && p->slot<slot && c->slot>slot ) ) return 1; /* in-between two nodes, skipped */
    1042           0 :     c = p;
    1043           0 :   }
    1044             : 
    1045           0 :   return 0; /* slot not between anc and des, or is unknown */
    1046           0 : }
    1047             : 
    1048             : FD_PROTOTYPES_END
    1049             : 
    1050             : #endif /* HEADER_fd_src_disco_gui_fd_gui_h */

Generated by: LCOV version 1.14