LCOV - code coverage report
Current view: top level - discoh/guih - fd_guih.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 139 0.0 %
Date: 2026-09-17 04:28:31 Functions: 0 33 0.0 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_discoh_guih_fd_guih_h
       2             : #define HEADER_fd_src_discoh_guih_fd_guih_h
       3             : 
       4             : #include "../../disco/topo/fd_topo.h"
       5             : 
       6             : #include "../../ballet/txn/fd_txn.h"
       7             : #include "../../disco/tiles.h"
       8             : #include "../../disco/fd_txn_p.h"
       9             : #include "../../disco/bundle/fd_bundle_tile.h"
      10             : #include "../../discof/restore/fd_snapct_tile.h"
      11             : #include "../../discof/restore/utils/fd_ssmsg.h"
      12             : #include "../../discof/tower/fd_tower_tile.h"
      13             : #include "../../discof/replay/fd_replay_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 "../../util/fd_util_base.h"
      18             : #include "../../util/hist/fd_histf.h"
      19             : #include "../../util/math/fd_stat.h" /* fd_sort_up_ulong_* */
      20             : #include "../../waltz/http/fd_http_server.h"
      21             : #include "../../waltz/http/fd_url.h"
      22             : 
      23             : #include <math.h> /* exp */
      24             : 
      25             : /* frankendancer only */
      26             : #define FD_GUIH_MAX_PEER_CNT (108000UL)
      27             : 
      28             : /* frankendancer only */
      29           0 : #define FD_GUIH_START_PROGRESS_TYPE_INITIALIZING                       ( 0)
      30           0 : #define FD_GUIH_START_PROGRESS_TYPE_SEARCHING_FOR_FULL_SNAPSHOT        ( 1)
      31           0 : #define FD_GUIH_START_PROGRESS_TYPE_DOWNLOADING_FULL_SNAPSHOT          ( 2)
      32           0 : #define FD_GUIH_START_PROGRESS_TYPE_SEARCHING_FOR_INCREMENTAL_SNAPSHOT ( 3)
      33           0 : #define FD_GUIH_START_PROGRESS_TYPE_DOWNLOADING_INCREMENTAL_SNAPSHOT   ( 4)
      34           0 : #define FD_GUIH_START_PROGRESS_TYPE_CLEANING_BLOCK_STORE               ( 5)
      35           0 : #define FD_GUIH_START_PROGRESS_TYPE_CLEANING_ACCOUNTS                  ( 6)
      36           0 : #define FD_GUIH_START_PROGRESS_TYPE_LOADING_LEDGER                     ( 7)
      37           0 : #define FD_GUIH_START_PROGRESS_TYPE_PROCESSING_LEDGER                  ( 8)
      38           0 : #define FD_GUIH_START_PROGRESS_TYPE_STARTING_SERVICES                  ( 9)
      39           0 : #define FD_GUIH_START_PROGRESS_TYPE_HALTED                             (10)
      40           0 : #define FD_GUIH_START_PROGRESS_TYPE_WAITING_FOR_SUPERMAJORITY          (11)
      41           0 : #define FD_GUIH_START_PROGRESS_TYPE_RUNNING                            (12)
      42             : 
      43           0 : #define FD_GUIH_NETWORK_EMA_HALF_LIFE_NS (1000000000L) /* 1 second in nanoseconds */
      44           0 : #define FD_GUIH_NET_PROTO_CNT            (6UL)         /* turbine, gossip, tpu, repair, rserve, metric */
      45           0 : #define FD_GUIH_NET_RATE_MAX_WINDOW_NS   (300L*1000L*1000L*1000L) /* 5 minutes in nanoseconds */
      46             : 
      47             : /* fd_guih_ema computes an adaptive exponential moving average tick.
      48             :    Given the previous EMA value, a new sample, timestamps, and a
      49             :    half-life (all in nanoseconds), returns the updated EMA.  On the
      50             :    first call (last_update_nanos==0) the new sample is returned as-is
      51             :    to seed the series. */
      52             : 
      53             : static inline double
      54             : fd_guih_ema( long   last_update_nanos,
      55             :              long   now_nanos,
      56             :              double new_sample,
      57             :              double prev_ema,
      58           0 :              long   half_life_ns ) {
      59           0 :   if( FD_UNLIKELY( last_update_nanos==0L ) ) return new_sample;
      60             : 
      61           0 :   long dt = now_nanos - last_update_nanos;
      62           0 :   if( FD_UNLIKELY( dt<=0L ) ) return prev_ema;
      63             : 
      64           0 :   double alpha = 1.0 - exp( -0.69314718055994 * (double)dt / (double)half_life_ns );
      65           0 :   return alpha * new_sample + (1.0 - alpha) * prev_ema;
      66           0 : }
      67             : 
      68             : /* Monotonic deque element for sliding-window max tracking of
      69             :    EMA-smoothed network throughput. */
      70             : struct fd_guih_rate_entry {
      71             :   long   ts_nanos;
      72             :   double value;
      73             : };
      74             : typedef struct fd_guih_rate_entry fd_guih_rate_entry_t;
      75             : 
      76             : /* At 100 ms sampling, 5 minutes = 3000 samples. */
      77             : #define DEQUE_NAME fd_guih_rate_deque
      78           0 : #define DEQUE_T    fd_guih_rate_entry_t
      79           0 : #define DEQUE_MAX  4096UL
      80             : #include "../../util/tmpl/fd_deque.c"
      81             : 
      82             : struct FD_TYPE_PACKED fd_guih_gossip_peer {
      83             :   fd_pubkey_t pubkey[ 1 ];
      84             :   ulong       wallclock;
      85             :   ushort      shred_version;
      86             : 
      87             :   uchar has_version;
      88             :   struct FD_TYPE_PACKED {
      89             :     ushort major;
      90             :     ushort minor;
      91             :     ushort patch;
      92             : 
      93             :     uchar  has_commit;
      94             :     uint   commit;
      95             : 
      96             :     uint   feature_set;
      97             :     ushort client_id;
      98             :   } version;
      99             : 
     100             :   struct FD_TYPE_PACKED {
     101             :     uint   ipv4;
     102             :     ushort port;
     103             :   } sockets[ 12 ];
     104             : };
     105             : 
     106             : typedef struct fd_guih_gossip_peer fd_guih_gossip_peer_t;
     107             : 
     108             : struct FD_TYPE_PACKED fd_guih_vote_account {
     109             :   fd_pubkey_t vote_account[ 1 ];
     110             :   fd_pubkey_t pubkey[ 1 ];
     111             : 
     112             :   ulong       activated_stake;
     113             :   ulong       last_vote;
     114             :   ulong       root_slot;
     115             :   ulong       epoch_credits;
     116             :   uchar       commission;
     117             :   uchar       delinquent;
     118             :   uchar       _reserved[ 14 ];
     119             : };
     120             : 
     121             : typedef struct fd_guih_vote_account fd_guih_vote_account_t;
     122             : 
     123             : struct FD_TYPE_PACKED fd_guih_validator_info {
     124             :   fd_pubkey_t pubkey[ 1 ];
     125             : 
     126             :   char name[ 64 ];
     127             :   char website[ 128 ];
     128             :   char details[ 256 ];
     129             :   char icon_uri[ 128 ];
     130             : };
     131             : 
     132             : typedef struct fd_guih_validator_info fd_guih_validator_info_t;
     133             : 
     134             : /* frankendancer only */
     135             : #define FD_GUIH_SLOT_LEADER_UNSTARTED (0UL)
     136             : #define FD_GUIH_SLOT_LEADER_STARTED   (1UL)
     137             : #define FD_GUIH_SLOT_LEADER_ENDED     (2UL)
     138             : 
     139           0 : #define FD_GUIH_SLOTS_CNT                           (864000UL) /* 2x 432000 */
     140           0 : #define FD_GUIH_LEADER_CNT                          (4096UL)
     141             : 
     142           0 : #define FD_GUIH_TPS_HISTORY_WINDOW_DURATION_SECONDS (10L)
     143           0 : #define FD_GUIH_TPS_HISTORY_SAMPLE_CNT              (150UL)
     144             : 
     145             : #define FD_GUIH_PROGCACHE_HISTORY_CNT               (600UL) /* 60s / 100ms */
     146             : 
     147           0 : #define FD_GUIH_TILE_TIMER_SNAP_CNT                   (512UL)
     148           0 : #define FD_GUIH_TILE_TIMER_LEADER_DOWNSAMPLE_CNT      (50UL)  /* 500ms / 10ms */
     149           0 : #define FD_GUIH_SCHEDULER_COUNT_SNAP_CNT              (512UL)
     150             : #define FD_GUIH_SCHEDULER_COUNT_LEADER_DOWNSAMPLE_CNT (50UL)  /* 500ms / 10ms */
     151             : 
     152           0 : #define FD_GUIH_VOTE_STATE_NON_VOTING (0)
     153           0 : #define FD_GUIH_VOTE_STATE_VOTING     (1)
     154           0 : #define FD_GUIH_VOTE_STATE_DELINQUENT (2)
     155             : 
     156             : #define FD_GUIH_BOOT_PROGRESS_TYPE_JOINING_GOSSIP               (1)
     157             : #define FD_GUIH_BOOT_PROGRESS_TYPE_LOADING_FULL_SNAPSHOT        (2)
     158             : #define FD_GUIH_BOOT_PROGRESS_TYPE_LOADING_INCREMENTAL_SNAPSHOT (3)
     159             : #define FD_GUIH_BOOT_PROGRESS_TYPE_WAITING_FOR_SUPERMAJORITY    (4)
     160             : #define FD_GUIH_BOOT_PROGRESS_TYPE_CATCHING_UP                  (5)
     161             : #define FD_GUIH_BOOT_PROGRESS_TYPE_RUNNING                      (6)
     162             : 
     163             : #define FD_GUIH_BOOT_PROGRESS_FULL_SNAPSHOT_IDX        (0UL)
     164             : #define FD_GUIH_BOOT_PROGRESS_INCREMENTAL_SNAPSHOT_IDX (1UL)
     165             : #define FD_GUIH_BOOT_PROGRESS_SNAPSHOT_CNT             (2UL)
     166             : 
     167           0 : #define FD_GUIH_SLOT_LEVEL_INCOMPLETE               (0)
     168           0 : #define FD_GUIH_SLOT_LEVEL_COMPLETED                (1)
     169           0 : #define FD_GUIH_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED (2)
     170           0 : #define FD_GUIH_SLOT_LEVEL_ROOTED                   (3)
     171           0 : #define FD_GUIH_SLOT_LEVEL_FINALIZED                (4)
     172             : 
     173             : /* Ideally, we would store an entire epoch's worth of transactions.  If
     174             :    we assume any given validator will have at most 5% stake, and average
     175             :    transactions per slot is around 10_000, then an epoch will have about
     176             :    432_000*10_000*0.05 transactions (~2^28).
     177             : 
     178             :    Unfortunately, the transaction struct is 100+ bytes.  If we sized the
     179             :    array to 2^28 entries then the memory required would be ~26GB.  In
     180             :    order to keep memory usage to a more reasonable level, we'll
     181             :    arbitrarily use a fourth of that size. */
     182           0 : #define FD_GUIH_TXN_HISTORY_SZ (1UL<<26UL)
     183             : 
     184           0 : #define FD_GUIH_TXN_FLAGS_STARTED         ( 1U)
     185           0 : #define FD_GUIH_TXN_FLAGS_ENDED           ( 2U)
     186           0 : #define FD_GUIH_TXN_FLAGS_IS_SIMPLE_VOTE  ( 4U)
     187           0 : #define FD_GUIH_TXN_FLAGS_FROM_BUNDLE     ( 8U)
     188           0 : #define FD_GUIH_TXN_FLAGS_LANDED_IN_BLOCK (16U)
     189             : 
     190           0 : #define FD_GUIH_TURBINE_RECV_TIMESTAMPS (750UL)
     191             : 
     192             : /* One use case for tracking ingress shred slot is to estimate when we
     193             :    have caught up to the tip of the blockchain.  A naive approach would
     194             :    be to track the maximum seen slot.
     195             : 
     196             :    maximum_seen_slot = fd_ulong_max( maximum_seen_slot, new_slot_from_shred_tile );
     197             : 
     198             :    Unfortunately, this doesn't always work because a validator can send
     199             :    a slot number that is arbitrarily large on a false fork. Also, these
     200             :    shreds can be for a repair response, which can be arbitrarily small.
     201             : 
     202             :    The prospects here seem bleak, but not all hope is lost!  We know
     203             :    that for a sufficiently large historical time window there is a high
     204             :    probability that at least some of the slots we observe will be valid
     205             :    recent turbine slots. For a sufficiently small window there is a high
     206             :    probability that all the observed shred slots are non-malicious (i.e.
     207             :    not arbitrarily large).
     208             : 
     209             :    In practice shred slots are almost always non-malicious. We can keep
     210             :    a history of the 12 largest slots we've seen in the past 4.8 seconds.
     211             :    We'll consider the "tip" of the blockchain to be the maximum slot in
     212             :    our history. This way, if we receive maliciously large slot number,
     213             :    it will be evicted after 4.8 seconds. If we receive a small slot from
     214             :    a repair response it will be ignored because we've seen other larger
     215             :    slots, meaning that our estimate is eventually consistent. For
     216             :    monitoring purposes this is sufficient.
     217             : 
     218             :    The worst case scenario is that this validator receives an incorrect
     219             :    shred slot slot more than once every 3 leader rotations. Before the
     220             :    previous incorrect slot is evicted from the history, a new one takes
     221             :    it's place and we wouldn't never get a correct estimate of the tip of
     222             :    the chain.  We also would indefinitely think that that we haven't
     223             :    caught up. This would require the chain having perpetually malicious
     224             :    leaders with adjacent rotations.  If this happens, Solana has bigger
     225             :    problems. */
     226           0 : #define FD_GUIH_TURBINE_SLOT_HISTORY_SZ (  12UL )
     227             : 
     228             : /* Like the turbine slot, the latest repair slot can also swing to
     229             :    arbitrarily large values due to a malicious fork switch.  The gui
     230             :    provides the same guarantees for freshness and accuracy.  This
     231             :    history is somewhat larger to handle the increased repair bandwidth
     232             :    during catch up. */
     233           0 : #define FD_GUIH_REPAIR_SLOT_HISTORY_SZ  ( 512UL )
     234             : 
     235             : /* FD_GUIH_*_CATCH_UP_HISTORY_SZ is the capacity of the record of slots
     236             :    seen from repair or turbine during the catch up stage at startup.
     237             :    These buffers are run-length encoded, so they will typically be very
     238             :    small.  The worst-case scenario is unbounded, so bounds here are
     239             :    determined heuristically. */
     240           0 : #define FD_GUIH_REPAIR_CATCH_UP_HISTORY_SZ  (4096UL)
     241             : #define FD_GUIH_TURBINE_CATCH_UP_HISTORY_SZ (4096UL)
     242             : 
     243             : /* FD_GUIH_SHREDS_STAGING_SZ is number of shred events we'll retain in
     244             :    in a small staging area.  The lifecycle of a shred looks something
     245             :    like the following
     246             : 
     247             :    states] turbine -> repairing (optional) ->  processing                   -> waiting_for_siblings -> slot_complete
     248             :    events]         ^-repair_requested      ^-shred_received/shred_repaired  ^-shred_replayed        ^-max(shred_replayed)
     249             : 
     250             :    We're interested in recording timestamps for state transitions (which
     251             :    these docs call "shred events").  Unfortunately, due to forking,
     252             :    duplicate packets, etc we can't make any guarantees about ordering or
     253             :    uniqueness for these event timestamps.  Instead the GUI just records
     254             :    timestamps for all events as they occur and put them into an array.
     255             :    Newly recorded event timestamps are also broadcast live to WebSocket
     256             :    consumers.
     257             : 
     258             :    The amount of shred events for non-finalized blocks can't really be
     259             :    bounded, so we use generous estimates here to set a memory bound. */
     260           0 : #define FD_GUIH_MAX_SHREDS_PER_BLOCK  (32UL*1024UL)
     261           0 : #define FD_GUIH_MAX_EVENTS_PER_SHRED  (       32UL)
     262           0 : #define FD_GUIH_SHREDS_STAGING_SZ     (32UL * FD_GUIH_MAX_SHREDS_PER_BLOCK * FD_GUIH_MAX_EVENTS_PER_SHRED)
     263             : 
     264             : /* FD_GUIH_SHREDS_HISTORY_SZ the number of shred events in our historical
     265             :    shred store.  Shred events here belong to finalized slots which means
     266             :    we won't record any additional shred updates for these slots.
     267             : 
     268             :    All shred events for a given slot will be places in a contiguous
     269             :    chunk in the array, and the bounding indices are stored in the
     270             :    fd_guih_slot_t slot history.  Within a slot chunk, shred events are
     271             :    ordered in the ordered they were recorded by the gui tile.
     272             : 
     273             :    Ideally, we have enough space to store an epoch's worth of events,
     274             :    but we are limited by realistic memory consumption.  Instead, we pick
     275             :    bound heuristically. */
     276           0 : #define FD_GUIH_SHREDS_HISTORY_SZ     (432000UL*2000UL*4UL / 12UL)
     277             : 
     278             : #define FD_GUIH_SLOT_SHRED_REPAIR_REQUEST          (0UL)
     279             : #define FD_GUIH_SLOT_SHRED_SHRED_RECEIVED_TURBINE  (1UL)
     280             : #define FD_GUIH_SLOT_SHRED_SHRED_RECEIVED_REPAIR   (2UL)
     281             : #define FD_GUIH_SLOT_SHRED_SHRED_REPLAY_EXEC_DONE  (3UL)
     282             : #define FD_GUIH_SLOT_SHRED_SHRED_SLOT_COMPLETE     (4UL)
     283             : /* #define FD_GUIH_SLOT_SHRED_SHRED_REPLAY_EXEC_START (5UL) // UNUSED */
     284             : #define FD_GUIH_SLOT_SHRED_SHRED_PUBLISHED         (6UL)
     285             : 
     286           0 : #define FD_GUIH_SLOT_RANKINGS_SZ (100UL)
     287           0 : #define FD_GUIH_SLOT_RANKING_TYPE_ASC  (0)
     288           0 : #define FD_GUIH_SLOT_RANKING_TYPE_DESC (1)
     289             : 
     290             : struct fd_guih_tile_timers {
     291             :   ulong timers[ FD_METRICS_ENUM_TILE_REGIME_CNT ];
     292             :   ulong sched_timers[ FD_METRICS_ENUM_CPU_REGIME_CNT ];
     293             : 
     294             :   int    in_backp;
     295             :   ushort last_cpu;
     296             :   uchar  status;
     297             :   ulong  heartbeat;
     298             :   ulong  backp_cnt;
     299             :   ulong  nvcsw;
     300             :   ulong  nivcsw;
     301             :   ulong  minflt;
     302             :   ulong  majflt;
     303             :   ulong  interrupts;
     304             :   ulong  tlb_shootdowns;
     305             :   ulong  timer_ticks;
     306             : };
     307             : 
     308             : typedef struct fd_guih_tile_timers fd_guih_tile_timers_t;
     309             : 
     310             : struct fd_guih_scheduler_counts {
     311             :   long sample_time_ns;
     312             :   ulong regular;
     313             :   ulong votes;
     314             :   ulong conflicting;
     315             :   ulong bundles;
     316             : };
     317             : 
     318             : typedef struct fd_guih_scheduler_counts fd_guih_scheduler_counts_t;
     319             : 
     320             : struct fd_guih_network_stats {
     321             :   /* total bytes accumulated */
     322             :   struct {
     323             :     ulong turbine;
     324             :     ulong gossip;
     325             :     ulong tpu;
     326             :     ulong repair;
     327             :     ulong rserve;
     328             :     ulong metric;
     329             :   } in, out;
     330             : };
     331             : 
     332             : typedef struct fd_guih_network_stats fd_guih_network_stats_t;
     333             : 
     334             : struct fd_guih_leader_slot {
     335             :   ulong slot;
     336             :   fd_hash_t block_hash;
     337             :   long  leader_start_time; /* UNIX timestamp of when we first became leader in this slot */
     338             :   long  leader_end_time;   /* UNIX timestamp of when we stopped being leader in this slot */
     339             : 
     340             :   /* Stem tiles can exist in one of 8 distinct activity regimes at any
     341             :      given moment.  One of these regimes, caughtup_postfrag, is the
     342             :      only regime where a tile is in a spin loop without doing any
     343             :      useful work.  This info is useful from a monitoring perspective
     344             :      because it lets us estimate CPU utilization on a pinned core.
     345             : 
     346             :      Every 10ms, the gui tile samples the amount of time tiles spent
     347             :      in each regime in the past 10ms.  This sample is used to infer
     348             :      the CPU utilization in the past 10ms.  This utilization is
     349             :      streamed live to WebSocket clients.
     350             : 
     351             :      In additional to live utilization, we are interested in recording
     352             :      utilization during one of this validator's leader slots.  The gui
     353             :      tile is continuously recording samples to storage with capacity
     354             :      FD_GUIH_TILE_TIMER_SNAP_CNT. The sample index is recorded at the
     355             :      start and end of a leader slot, and the number of samples is
     356             :      downsampled to be at most FD_GUIH_TILE_TIMER_LEADER_DOWNSAMPLE_CNT
     357             :      samples (e.g. if there was an unusually long leader slot) and
     358             :      inserted into historical storage with capacity FD_GUIH_LEADER_CNT.
     359             : 
     360             :      The tile_timers pointer references trailing storage allocated
     361             :      in fd_guih_footprint, with gui->tile_cnt elements per sample.
     362             :      Sized as tile_timers[ FD_GUIH_TILE_TIMER_LEADER_DOWNSAMPLE_CNT ][ tile_cnt ]. */
     363             :   fd_guih_tile_timers_t * tile_timers;
     364             :   ulong                  tile_timers_sample_cnt;
     365             : 
     366             :   fd_guih_scheduler_counts_t scheduler_counts[ FD_GUIH_SCHEDULER_COUNT_LEADER_DOWNSAMPLE_CNT ][ 1 ];
     367             :   ulong                     scheduler_counts_sample_cnt;
     368             : 
     369             :   struct {
     370             :     uint microblocks_upper_bound; /* An upper bound on the number of microblocks in the slot.  If the number of
     371             :                                      microblocks observed is equal to this, the slot can be considered over.
     372             :                                      Generally, the bound is set to a "final" state by a done packing message,
     373             :                                      which sets it to the exact number of microblocks, but sometimes this message
     374             :                                      is not sent, if the max upper bound published by poh was already correct. */
     375             :     uint begin_microblocks; /* The number of microblocks we have seen be started (sent) from pack to banks. */
     376             :     uint end_microblocks;   /* The number of microblocks we have seen be ended (sent) from banks to poh.  The
     377             :                                slot is only considered over if the begin and end microblocks seen are both equal
     378             :                                to the microblock upper bound. */
     379             : 
     380             :     ulong   start_offset; /* The smallest pack transaction index for this slot. The first transaction for this slot will
     381             :                              be written to gui->txs[ start_offset%FD_GUIH_TXN_HISTORY_SZ ]. */
     382             :     ulong   end_offset;   /* The largest pack transaction index for this slot, plus 1. The last transaction for this
     383             :                              slot will be written to gui->txs[ (end_offset-1)%FD_GUIH_TXN_HISTORY_SZ ]. */
     384             :   } txs;
     385             : 
     386             :   fd_done_packing_t scheduler_stats[ 1 ];
     387             : 
     388             :   /* The initial, maximum number of microblocks that could be packed
     389             :      into this slot. */
     390             :   ulong max_microblocks;
     391             : 
     392             :   uchar unbecame_leader: 1;
     393             : };
     394             : 
     395             : typedef struct fd_guih_leader_slot fd_guih_leader_slot_t;
     396             : 
     397             : struct fd_guih_turbine_slot {
     398             :  ulong slot;
     399             :  long timestamp;
     400             : };
     401             : 
     402             : typedef struct fd_guih_turbine_slot fd_guih_turbine_slot_t;
     403             : 
     404             : struct fd_guih_slot_staged_shred_event {
     405             :   long   timestamp;
     406             :   ulong  slot;
     407             :   ushort shred_idx;
     408             :   uchar  event;
     409             : };
     410             : 
     411             : typedef struct fd_guih_slot_staged_shred_event fd_guih_slot_staged_shred_event_t;
     412             : 
     413             : struct FD_TYPE_PACKED fd_guih_slot_history_shred_event {
     414             :   long   timestamp;
     415             :   ushort shred_idx;
     416             :   uchar  event;
     417             : };
     418             : 
     419             : typedef struct fd_guih_slot_history_shred_event fd_guih_slot_history_shred_event_t;
     420             : 
     421             : struct fd_guih_slot_ranking {
     422             :   ulong slot;
     423             :   ulong value;
     424             :   int   type;
     425             : };
     426             : typedef struct fd_guih_slot_ranking fd_guih_slot_ranking_t;
     427             : 
     428             : struct fd_guih_slot_rankings {
     429             :   fd_guih_slot_ranking_t largest_tips           [ FD_GUIH_SLOT_RANKINGS_SZ+1UL ];
     430             :   fd_guih_slot_ranking_t largest_fees           [ FD_GUIH_SLOT_RANKINGS_SZ+1UL ];
     431             :   fd_guih_slot_ranking_t largest_rewards        [ FD_GUIH_SLOT_RANKINGS_SZ+1UL ];
     432             :   fd_guih_slot_ranking_t largest_duration       [ FD_GUIH_SLOT_RANKINGS_SZ+1UL ];
     433             :   fd_guih_slot_ranking_t largest_compute_units  [ FD_GUIH_SLOT_RANKINGS_SZ+1UL ];
     434             :   fd_guih_slot_ranking_t largest_skipped        [ FD_GUIH_SLOT_RANKINGS_SZ+1UL ];
     435             :   fd_guih_slot_ranking_t largest_rewards_per_cu [ FD_GUIH_SLOT_RANKINGS_SZ+1UL ];
     436             :   fd_guih_slot_ranking_t smallest_tips          [ FD_GUIH_SLOT_RANKINGS_SZ+1UL ];
     437             :   fd_guih_slot_ranking_t smallest_fees          [ FD_GUIH_SLOT_RANKINGS_SZ+1UL ];
     438             :   fd_guih_slot_ranking_t smallest_rewards       [ FD_GUIH_SLOT_RANKINGS_SZ+1UL ];
     439             :   fd_guih_slot_ranking_t smallest_rewards_per_cu[ FD_GUIH_SLOT_RANKINGS_SZ+1UL ];
     440             :   fd_guih_slot_ranking_t smallest_duration      [ FD_GUIH_SLOT_RANKINGS_SZ+1UL ];
     441             :   fd_guih_slot_ranking_t smallest_compute_units [ FD_GUIH_SLOT_RANKINGS_SZ+1UL ];
     442             :   fd_guih_slot_ranking_t smallest_skipped       [ FD_GUIH_SLOT_RANKINGS_SZ+1UL ];
     443             : };
     444             : 
     445             : typedef struct fd_guih_slot_rankings fd_guih_slot_rankings_t;
     446             : 
     447             : struct fd_guih_ephemeral_slot {
     448             :   ulong slot; /* ULONG_MAX indicates invalid/evicted */
     449             :   long timestamp_arrival_nanos;
     450             : };
     451             : typedef struct fd_guih_ephemeral_slot fd_guih_ephemeral_slot_t;
     452             : 
     453             : struct FD_TYPE_PACKED fd_guih_txn {
     454             :   uchar signature[ FD_TXN_SIGNATURE_SZ ];
     455             :   ulong transaction_fee;
     456             :   ulong priority_fee;
     457             :   ulong tips;
     458             :   long timestamp_arrival_nanos;
     459             : 
     460             :   /* compute_units_requested has both execution and non-execution cus */
     461             :   uint compute_units_requested : 21; /* <= 1.4M */
     462             :   uint compute_units_consumed  : 21; /* <= 1.4M */
     463             :   uint bank_idx                :  6; /* in [0, 64) */
     464             :   uint error_code              :  6; /* in [0, 64) */
     465             : 
     466             :   /* relative to leader start */
     467             :   float           microblock_start_ns_dt;
     468             :   float           microblock_end_ns_dt;
     469             : 
     470             :   /* relative to microblock_start */
     471             :   fd_txn_ns_dt_t txn_ns_dt;
     472             : 
     473             :   uchar flags; /* assigned with the FD_GUIH_TXN_FLAGS_* macros */
     474             :   uchar source_tpu; /* FD_TXN_M_TPU_SOURCE_* */
     475             :   uint  source_ipv4;
     476             :   uint  microblock_idx;
     477             : };
     478             : 
     479             : typedef struct fd_guih_txn fd_guih_txn_t;
     480             : 
     481             : struct fd_guih_txn_waterfall {
     482             :   struct {
     483             :     ulong quic;
     484             :     ulong udp;
     485             :     ulong gossip;
     486             :     ulong block_engine;
     487             :     ulong pack_cranked;
     488             :   } in;
     489             : 
     490             :   struct {
     491             :     ulong net_overrun;
     492             :     ulong quic_overrun;
     493             :     ulong quic_frag_drop;
     494             :     ulong quic_abandoned;
     495             :     ulong tpu_quic_invalid;
     496             :     ulong tpu_udp_invalid;
     497             :     ulong verify_overrun;
     498             :     ulong verify_parse;
     499             :     ulong verify_failed;
     500             :     ulong verify_duplicate;
     501             :     ulong dedup_duplicate;
     502             :     ulong resolv_lut_failed;
     503             :     ulong resolv_expired;
     504             :     ulong resolv_ancient;
     505             :     ulong resolv_no_ledger;
     506             :     ulong resolv_retained;
     507             :     ulong pack_invalid;
     508             :     ulong pack_invalid_bundle;
     509             :     ulong pack_expired;
     510             :     ulong pack_already_executed;
     511             :     ulong pack_retained;
     512             :     ulong pack_wait_full;
     513             :     ulong pack_leader_slow;
     514             :     ulong bank_invalid;
     515             :     ulong bank_nonce_already_advanced;
     516             :     ulong bank_nonce_advance_failed;
     517             :     ulong bank_nonce_wrong_blockhash;
     518             :     ulong block_success;
     519             :     ulong block_fail;
     520             :   } out;
     521             : };
     522             : 
     523             : typedef struct fd_guih_txn_waterfall fd_guih_txn_waterfall_t;
     524             : 
     525             : struct fd_guih_tile_stats {
     526             :   long  sample_time_nanos;
     527             : 
     528             :   ulong net_in_rx_bytes;           /* Number of bytes received by the net or sock tile*/
     529             :   ulong quic_conn_cnt;             /* Number of active QUIC connections */
     530             :   fd_histf_t bundle_rx_delay_hist; /* Histogram of bundle rx delay */
     531             :   ulong bundle_rtt_smoothed_nanos; /* RTT (nanoseconds) moving average */
     532             :   ulong verify_drop_cnt;           /* Number of transactions dropped by verify tiles */
     533             :   ulong verify_total_cnt;          /* Number of transactions received by verify tiles */
     534             :   ulong dedup_drop_cnt;            /* Number of transactions dropped by dedup tile */
     535             :   ulong dedup_total_cnt;           /* Number of transactions received by dedup tile */
     536             :   ulong pack_buffer_cnt;           /* Number of buffered transactions in the pack tile */
     537             :   ulong pack_buffer_capacity;      /* Total size of the pack transaction buffer */
     538             :   ulong bank_txn_exec_cnt;         /* Number of transactions processed by the bank tile */
     539             :   ulong net_out_tx_bytes;          /* Number of bytes sent by the net or sock tile */
     540             : };
     541             : 
     542             : typedef struct fd_guih_tile_stats fd_guih_tile_stats_t;
     543             : 
     544             : struct fd_guih_slot {
     545             :   ulong slot;
     546             :   ulong parent_slot;
     547             :   ulong vote_slot;
     548             :   ulong reset_slot;
     549             :   long  completed_time;
     550             :   uint  max_compute_units;
     551             :   int   mine;
     552             :   int   skipped;
     553             :   int   must_republish;
     554             :   int   level;
     555             :   uint  compute_units;
     556             :   ulong transaction_fee;
     557             :   ulong priority_fee;
     558             :   ulong tips;
     559             :   uint  shred_cnt;
     560             :   uchar vote_latency;
     561             : 
     562             :   uint vote_success;
     563             :   uint vote_failed;
     564             :   uint nonvote_success;
     565             :   uint nonvote_failed;
     566             : 
     567             :   /* Some slot info is only tracked for our own leader slots. These
     568             :      slots are kept in a separate buffer. */
     569             :   ulong leader_history_idx;
     570             : 
     571             :   fd_guih_txn_waterfall_t waterfall_begin[ 1 ];
     572             :   fd_guih_txn_waterfall_t waterfall_end[ 1 ];
     573             : 
     574             :   fd_guih_tile_stats_t tile_stats_begin[ 1 ];
     575             :   fd_guih_tile_stats_t tile_stats_end[ 1 ];
     576             : 
     577             :   struct {
     578             :     ulong start_offset; /* gui->shreds.history[ start_offset % FD_GUIH_SHREDS_HISTORY_SZ ] is the first shred event in
     579             :                            contiguous chunk of events in the shred history corresponding to this slot. */
     580             :     ulong end_offset;   /* One past the last shred event in the contiguous chunk of events in the shred history
     581             :                            corresponding to this slot. */
     582             :   } shreds;
     583             : };
     584             : 
     585             : typedef struct fd_guih_slot fd_guih_slot_t;
     586             : 
     587             : struct fd_guih_boot_progress {
     588             :   uchar phase;
     589             :   long joining_gossip_time_nanos;
     590             :   struct {
     591             :     ulong  slot;
     592             :     uint   peer_addr;
     593             :     ushort peer_port;
     594             :     ulong  total_bytes_compressed;
     595             :     long   reset_time_nanos;          /* UNIX nanosecond timestamp */
     596             :     long   sample_time_nanos;
     597             :     ulong  reset_cnt;
     598             : 
     599             :     ulong read_bytes_compressed;
     600             :     char  read_path[ PATH_MAX+30UL ]; /* URL or filesystem path.  30 is fd_cstr_nlen( "https://255.255.255.255:12345/", ULONG_MAX ) */
     601             : 
     602             :     ulong decompress_bytes_decompressed;
     603             :     ulong decompress_bytes_compressed;
     604             : 
     605             :     ulong insert_bytes_decompressed;
     606             :     char  insert_path[ PATH_MAX ];
     607             :     ulong insert_accounts_current;
     608             :   } loading_snapshot[ FD_GUIH_BOOT_PROGRESS_SNAPSHOT_CNT ];
     609             : 
     610             :   ulong wfs_total_stake;
     611             :   ulong wfs_connected_stake;
     612             :   ulong wfs_total_peers;
     613             :   ulong wfs_connected_peers;
     614             :   ulong wfs_attempt;
     615             : 
     616             :   long  catching_up_time_nanos;
     617             :   ulong catching_up_first_replay_slot;
     618             : };
     619             : 
     620             : typedef struct fd_guih_boot_progress fd_guih_boot_progress_t;
     621             : 
     622             : struct fd_guih {
     623             :   fd_http_server_t * http;
     624             :   fd_topo_t const * topo;
     625             : 
     626             :   ulong tile_cnt;
     627             : 
     628             :   long next_sample_400millis;
     629             :   long next_sample_100millis;
     630             :   long next_sample_50millis;
     631             :   long next_sample_25millis;
     632             :   long next_sample_10millis;
     633             : 
     634             :   ulong leader_slot;
     635             : 
     636             :   struct {
     637             :     fd_pubkey_t identity_key[ 1 ];
     638             :     int         has_vote_key;
     639             :     fd_pubkey_t vote_key[ 1 ];
     640             :     char vote_key_base58[ FD_BASE58_ENCODED_32_SZ ];
     641             :     char identity_key_base58[ FD_BASE58_ENCODED_32_SZ ];
     642             : 
     643             :     int          is_full_client;
     644             :     char const * version;
     645             :     char const * cluster;
     646             : 
     647             :     char   wfs_bank_hash[ FD_BASE58_ENCODED_32_SZ ];
     648             :     ushort expected_shred_version;
     649             :     int    wfs_enabled;
     650             : 
     651             :     ulong vote_distance;
     652             :     int vote_state;
     653             : 
     654             :     long  startup_time_nanos;
     655             : 
     656             :     union {
     657             :       struct { /* frankendancer only */
     658             :       uchar phase;
     659             :       int   startup_got_full_snapshot;
     660             : 
     661             :       ulong  startup_incremental_snapshot_slot;
     662             :       uint   startup_incremental_snapshot_peer_ip_addr;
     663             :         ushort startup_incremental_snapshot_peer_port;
     664             :         double startup_incremental_snapshot_elapsed_secs;
     665             :         double startup_incremental_snapshot_remaining_secs;
     666             :         double startup_incremental_snapshot_throughput;
     667             :         ulong  startup_incremental_snapshot_total_bytes;
     668             :         ulong  startup_incremental_snapshot_current_bytes;
     669             : 
     670             :         ulong  startup_full_snapshot_slot;
     671             :         uint   startup_full_snapshot_peer_ip_addr;
     672             :         ushort startup_full_snapshot_peer_port;
     673             :         double startup_full_snapshot_elapsed_secs;
     674             :         double startup_full_snapshot_remaining_secs;
     675             :         double startup_full_snapshot_throughput;
     676             :         ulong  startup_full_snapshot_total_bytes;
     677             :         ulong  startup_full_snapshot_current_bytes;
     678             : 
     679             :         ulong startup_ledger_slot;
     680             :         ulong startup_ledger_max_slot;
     681             : 
     682             :         ulong startup_waiting_for_supermajority_slot;
     683             :         ulong startup_waiting_for_supermajority_stake_pct;
     684             :       } startup_progress;
     685             :       fd_guih_boot_progress_t boot_progress;
     686             :     };
     687             : 
     688             :     fd_guih_boot_progress_t prev_boot_progress;
     689             : 
     690             :     int schedule_strategy;
     691             : 
     692             :     ulong identity_account_balance;
     693             :     ulong vote_account_balance;
     694             :     ulong estimated_slot_duration_nanos;
     695             : 
     696             :     ulong sock_tile_cnt;
     697             :     ulong mlx5_tile_cnt;
     698             :     ulong net_tile_cnt;
     699             :     ulong quic_tile_cnt;
     700             :     ulong verify_tile_cnt;
     701             :     ulong resolh_tile_cnt;
     702             :     ulong resolv_tile_cnt;
     703             :     ulong bank_tile_cnt;
     704             :     ulong execle_tile_cnt;
     705             :     ulong execrp_tile_cnt;
     706             :     ulong shred_tile_cnt;
     707             : 
     708             :     ulong slot_rooted;
     709             :     ulong slot_optimistically_confirmed;
     710             :     ulong slot_completed;
     711             :     ulong slot_estimated;
     712             :     ulong slot_caught_up;
     713             :     ulong slot_repair;
     714             :     ulong slot_turbine;
     715             :     ulong slot_reset;
     716             :     ulong slot_storage;
     717             :     ulong active_fork_cnt;
     718             : 
     719             :     fd_guih_ephemeral_slot_t slots_max_turbine[ FD_GUIH_TURBINE_SLOT_HISTORY_SZ+1UL ];
     720             :     fd_guih_ephemeral_slot_t slots_max_repair [ FD_GUIH_REPAIR_SLOT_HISTORY_SZ +1UL ];
     721             : 
     722             :     /* catchup_* and late_votes are run-length encoded. i.e. adjacent
     723             :        pairs represent contiguous runs */
     724             :     ulong catch_up_turbine[ FD_GUIH_TURBINE_CATCH_UP_HISTORY_SZ ];
     725             :     ulong catch_up_turbine_sz;
     726             : 
     727             :     ulong catch_up_repair[ FD_GUIH_REPAIR_CATCH_UP_HISTORY_SZ ];
     728             :     ulong catch_up_repair_sz;
     729             : 
     730             :     ulong late_votes[ MAX_SLOTS_PER_EPOCH ];
     731             :     ulong late_votes_sz;
     732             : 
     733             :     ulong estimated_tps_history_idx;
     734             :     struct {
     735             :      ulong vote_failed;
     736             :      ulong vote_success;
     737             :      ulong nonvote_success;
     738             :      ulong nonvote_failed;
     739             :     } estimated_tps_history[ FD_GUIH_TPS_HISTORY_SAMPLE_CNT ];
     740             : 
     741             :     fd_guih_network_stats_t network_stats_current[ 1 ];
     742             :     fd_guih_network_stats_t network_stats_prev[ 1 ];
     743             :     int                    network_stats_has_prev;
     744             : 
     745             :     /* EMA-smoothed network throughput (bytes/sec) with a 1-second
     746             :        half-life. */
     747             :     double                   ingress_ema[ FD_GUIH_NET_PROTO_CNT ];
     748             :     double                   egress_ema[ FD_GUIH_NET_PROTO_CNT ];
     749             :     long                     net_rate_prev_ts;
     750             :     int                      net_rate_ema_ready;
     751             :     fd_guih_rate_entry_t *    ingress_maxq;
     752             :     fd_guih_rate_entry_t *    egress_maxq;
     753             : 
     754             :     fd_guih_txn_waterfall_t txn_waterfall_reference[ 1 ];
     755             :     fd_guih_txn_waterfall_t txn_waterfall_current[ 1 ];
     756             : 
     757             :     fd_guih_tile_stats_t tile_stats_reference[ 1 ];
     758             :     fd_guih_tile_stats_t tile_stats_current[ 1 ];
     759             : 
     760             :     ulong progcache_history_idx;
     761             :     ulong progcache_hits_history   [ FD_GUIH_PROGCACHE_HISTORY_CNT ];
     762             :     ulong progcache_lookups_history[ FD_GUIH_PROGCACHE_HISTORY_CNT ];
     763             :     ulong progcache_hits_1min;
     764             :     ulong progcache_lookups_1min;
     765             : 
     766             :     ulong                  tile_timers_snap_idx;
     767             :     ulong                  tile_timers_snap_idx_slot_start;
     768             :     /* Temporary storage for samples.  Will be downsampled into
     769             :        leader history on slot end.  Sized as
     770             :        tile_timers_snap[ FD_GUIH_TILE_TIMER_SNAP_CNT ][ tile_cnt ] */
     771             :     fd_guih_tile_timers_t * tile_timers_snap;
     772             : 
     773             :     ulong                     scheduler_counts_snap_idx;
     774             :     ulong                     scheduler_counts_snap_idx_slot_start;
     775             :     /* Temporary storage for samples. Will be downsampled into leader history on slot end. */
     776             :     fd_guih_scheduler_counts_t scheduler_counts_snap[ FD_GUIH_SCHEDULER_COUNT_SNAP_CNT ][ 1 ];
     777             :   } summary;
     778             : 
     779             :   fd_guih_slot_t slots[ FD_GUIH_SLOTS_CNT ][ 1 ];
     780             : 
     781             :   /* used for estimating slot duration */
     782             :   fd_guih_turbine_slot_t turbine_slots[ FD_GUIH_TURBINE_RECV_TIMESTAMPS ];
     783             : 
     784             :   fd_guih_leader_slot_t leader_slots[ FD_GUIH_LEADER_CNT ][ 1 ];
     785             :   ulong leader_slots_cnt;
     786             : 
     787             :   fd_guih_txn_t txs[ FD_GUIH_TXN_HISTORY_SZ ][ 1 ];
     788             :   ulong pack_txn_idx; /* The pack index of the most recently received transaction */
     789             : 
     790             :   ulong tower_cnt;
     791             :   fd_vote_acc_vote_t tower[ FD_TOWER_VOTE_MAX ];
     792             : 
     793             :   struct {
     794             :     int has_block_engine;
     795             :     char name[ 16 ];
     796             :     char url[ FD_URL_MAX ];
     797             :     char ip_cstr[ 40 ]; /* IPv4 or IPv6 cstr */
     798             :     int status;
     799             :   } block_engine;
     800             : 
     801             :   struct {
     802             :     int has_epoch[ 2 ];
     803             : 
     804             :     struct {
     805             :       ulong epoch;
     806             :       long start_time;
     807             :       long end_time;
     808             : 
     809             :       ulong my_total_slots;
     810             :       ulong my_skipped_slots;
     811             : 
     812             :       ulong start_slot;
     813             :       ulong end_slot;
     814             :       ulong target_slot_duration_nanos;
     815             :       fd_epoch_leaders_t * lsched;
     816             :       uchar __attribute__((aligned(FD_EPOCH_LEADERS_ALIGN))) _lsched[ FD_EPOCH_LEADERS_FOOTPRINT(MAX_STAKE_WEIGHTS, MAX_SLOTS_PER_EPOCH) ];
     817             :       fd_vote_stake_weight_t stakes[ MAX_STAKE_WEIGHTS ];
     818             : 
     819             :       ulong rankings_slot; /* One more than the largest slot we've processed into our rankings */
     820             :       fd_guih_slot_rankings_t rankings[ 1 ]; /* global slot rankings */
     821             :       fd_guih_slot_rankings_t my_rankings[ 1 ]; /* my slots only */
     822             :     } epochs[ 2 ];
     823             :   } epoch;
     824             : 
     825             :   struct {  /* frankendancer only */
     826             :     ulong                     peer_cnt;
     827             :     struct fd_guih_gossip_peer peers[ FD_GUIH_MAX_PEER_CNT ];
     828             :   } gossip;
     829             : 
     830             :   struct {  /* frankendancer only */
     831             :     ulong                      vote_account_cnt;
     832             :     struct fd_guih_vote_account vote_accounts[ FD_GUIH_MAX_PEER_CNT ];
     833             :   } vote_account;
     834             : 
     835             :   struct {  /* frankendancer only */
     836             :     ulong                        info_cnt;
     837             :     struct fd_guih_validator_info info[ FD_GUIH_MAX_PEER_CNT ];
     838             :   } validator_info;
     839             : 
     840             :   struct {
     841             :     ulong leader_shred_cnt;      /* A gauge counting the number of leader shreds seen on the SHRED_OUT link.  Resets at
     842             :                                     the end of a leader slot.  This works because leader fecs are published in order. */
     843             :     ulong staged_next_broadcast; /* staged[ staged_next_broadcast % FD_GUIH_SHREDS_STAGING_SZ ] is the first shred event
     844             :                                     that hasn't yet been broadcast to WebSocket clients */
     845             :     ulong staged_head;            /* staged_head % FD_GUIH_SHREDS_STAGING_SZ is the first valid event in staged */
     846             :     ulong staged_tail;            /* staged_tail % FD_GUIH_SHREDS_STAGING_SZ is one past the last valid event in staged */
     847             :     fd_guih_slot_staged_shred_event_t  staged [ FD_GUIH_SHREDS_STAGING_SZ ];
     848             : 
     849             :     ulong history_slot;          /* the largest slot store in history */
     850             :     ulong history_tail;          /* history_tail % FD_GUIH_SHREDS_HISTORY_SZ is one past the last valid event in history */
     851             :     fd_guih_slot_history_shred_event_t history[ FD_GUIH_SHREDS_HISTORY_SZ ];
     852             : 
     853             :     /* scratch space for archiving staged events */
     854             :     fd_guih_slot_staged_shred_event_t _staged_scratch [ FD_GUIH_SHREDS_STAGING_SZ ];
     855             :   } shreds; /* full client */
     856             : };
     857             : 
     858             : typedef struct fd_guih fd_guih_t;
     859             : 
     860             : /* fd_guih_staged_push returns a pointer to the next free staging slot
     861             :    and advances staged_tail.  If the ring is full staged_head is
     862             :    advanced first so the oldest entry is silently dropped. */
     863             : static inline fd_guih_slot_staged_shred_event_t *
     864           0 : fd_guih_staged_push( fd_guih_t * gui ) {
     865           0 :   if( FD_UNLIKELY( gui->shreds.staged_tail - gui->shreds.staged_head >= FD_GUIH_SHREDS_STAGING_SZ ) ) {
     866           0 :     gui->shreds.staged_head = gui->shreds.staged_tail - FD_GUIH_SHREDS_STAGING_SZ + 1UL;
     867           0 :     if( FD_UNLIKELY( gui->shreds.staged_next_broadcast < gui->shreds.staged_head ) ) {
     868           0 :       gui->shreds.staged_next_broadcast = gui->shreds.staged_head;
     869           0 :     }
     870           0 :   }
     871           0 :   fd_guih_slot_staged_shred_event_t * dst =
     872           0 :       &gui->shreds.staged[ gui->shreds.staged_tail % FD_GUIH_SHREDS_STAGING_SZ ];
     873           0 :   gui->shreds.staged_tail++;
     874           0 :   return dst;
     875           0 : }
     876             : 
     877             : FD_PROTOTYPES_BEGIN
     878             : 
     879             : FD_FN_CONST ulong
     880             : fd_guih_align( void );
     881             : 
     882             : ulong
     883             : fd_guih_footprint( ulong tile_cnt );
     884             : 
     885             : void *
     886             : fd_guih_new( void *                shmem,
     887             :             fd_http_server_t *    http,
     888             :             char const *          version,
     889             :             char const *          cluster,
     890             :             uchar const *         identity_key,
     891             :             int                   has_vote_key,
     892             :             uchar const *         vote_key,
     893             :             int                   is_full_client,
     894             :             int                   snapshots_enabled,
     895             :             int                   is_voting,
     896             :             int                   schedule_strategy,
     897             :             char const *          wfs_expected_bank_hash_cstr,
     898             :             ushort                expected_shred_version,
     899             :             fd_topo_t const *     topo,
     900             :             long                  now );
     901             : 
     902             : fd_guih_t *
     903             : fd_guih_join( void * shmem );
     904             : 
     905             : void
     906             : fd_guih_set_identity( fd_guih_t *    gui,
     907             :                      uchar const * identity_pubkey );
     908             : 
     909             : void
     910             : fd_guih_ws_open( fd_guih_t *  gui,
     911             :                 ulong       conn_id,
     912             :                 long now );
     913             : 
     914             : int
     915             : fd_guih_ws_message( fd_guih_t *    gui,
     916             :                    ulong         ws_conn_id,
     917             :                    uchar const * data,
     918             :                    ulong         data_len );
     919             : 
     920             : void
     921             : fd_guih_plugin_message( fd_guih_t *   gui,
     922             :                        ulong        plugin_msg,
     923             :                        void const * msg,
     924             :                        long         now );
     925             : 
     926             : void
     927             : fd_guih_became_leader( fd_guih_t * gui,
     928             :                       ulong      slot,
     929             :                       long       start_time_nanos,
     930             :                       long       end_time_nanos,
     931             :                       ulong      max_compute_units,
     932             :                       ulong      max_microblocks );
     933             : 
     934             : void
     935             : fd_guih_unbecame_leader( fd_guih_t *                gui,
     936             :                         ulong                     _slot,
     937             :                         fd_done_packing_t const * done_packing,
     938             :                         long                      now );
     939             : 
     940             : void
     941             : fd_guih_microblock_execution_begin( fd_guih_t *   gui,
     942             :                                    long         tspub_ns,
     943             :                                    ulong        _slot,
     944             :                                    fd_txn_e_t * txns,
     945             :                                    ulong        txn_cnt,
     946             :                                    uint         microblock_idx,
     947             :                                    ulong        pack_txn_idx );
     948             : 
     949             : void
     950             : fd_guih_microblock_execution_end( fd_guih_t *     gui,
     951             :                                  long           tspub_ns,
     952             :                                  ulong          bank_idx,
     953             :                                  ulong          _slot,
     954             :                                  ulong          txn_cnt,
     955             :                                  fd_txn_p_t *   txns,
     956             :                                  ulong          pack_txn_idx,
     957             :                                  fd_txn_ns_dt_t txn_ns_dt,
     958             :                                  ulong          tips );
     959             : 
     960             : int
     961             : fd_guih_poll( fd_guih_t * gui, long now );
     962             : 
     963             : void
     964             : fd_guih_handle_block_engine_update( fd_guih_t *                              gui,
     965             :                                    fd_bundle_block_engine_update_t const * update );
     966             : 
     967             : void
     968             : fd_guih_handle_repair_slot( fd_guih_t * gui, ulong slot, long now );
     969             : 
     970             : void
     971             : fd_guih_handle_leader_schedule( fd_guih_t *                    gui,
     972             :                                fd_stake_weight_msg_t const * leader_schedule,
     973             :                                long                          now );
     974             : 
     975             : void
     976             : fd_guih_handle_genesis_hash( fd_guih_t *        gui,
     977             :                             fd_hash_t const * msg );
     978             : 
     979             : static inline ulong
     980           0 : fd_guih_current_epoch_idx( fd_guih_t * gui ) {
     981           0 :   ulong epoch_idx = ULONG_MAX;
     982           0 :   ulong epoch     = ULONG_MAX;
     983           0 :   for( ulong i = 0UL; i<2UL; i++ ) {
     984           0 :     if( FD_LIKELY( gui->epoch.has_epoch[ i ] ) ) {
     985             :       /* the "current" epoch is the smaller one */
     986           0 :       if( FD_LIKELY( gui->epoch.epochs[ i ].epoch<epoch ) ) {
     987           0 :         epoch = gui->epoch.epochs[ i ].epoch;
     988           0 :         epoch_idx = i;
     989           0 :       }
     990           0 :     }
     991           0 :   }
     992           0 :   return epoch_idx;
     993           0 : }
     994             : 
     995             : static inline fd_guih_slot_t *
     996           0 : fd_guih_get_slot( fd_guih_t const * gui, ulong _slot ) {
     997           0 :   fd_guih_slot_t const * slot = gui->slots[ _slot % FD_GUIH_SLOTS_CNT ];
     998           0 :   if( FD_UNLIKELY( slot->slot==ULONG_MAX || _slot==ULONG_MAX || slot->slot!=_slot ) ) return NULL;
     999           0 :   return (fd_guih_slot_t *)slot;
    1000           0 : }
    1001             : 
    1002             : static inline fd_guih_slot_t const *
    1003           0 : fd_guih_get_slot_const( fd_guih_t const * gui, ulong _slot ) {
    1004           0 :   return fd_guih_get_slot( gui, _slot );
    1005           0 : }
    1006             : 
    1007             : static inline fd_guih_leader_slot_t *
    1008           0 : fd_guih_get_leader_slot( fd_guih_t const * gui, ulong _slot ) {
    1009           0 :   fd_guih_slot_t const * slot = fd_guih_get_slot( gui, _slot );
    1010           0 :   if( FD_UNLIKELY( !slot
    1011           0 :                 || !slot->mine
    1012           0 :                 || slot->leader_history_idx==ULONG_MAX
    1013           0 :                 || slot->leader_history_idx + FD_GUIH_LEADER_CNT < gui->leader_slots_cnt
    1014           0 :                 || gui->leader_slots[ slot->leader_history_idx % FD_GUIH_LEADER_CNT ]->slot!=_slot ) ) return NULL;
    1015           0 :   return (fd_guih_leader_slot_t *)gui->leader_slots[ slot->leader_history_idx % FD_GUIH_LEADER_CNT ];
    1016           0 : }
    1017             : 
    1018             : static inline fd_guih_leader_slot_t const *
    1019           0 : fd_guih_get_leader_slot_const( fd_guih_t const * gui, ulong _slot ) {
    1020           0 :   return fd_guih_get_leader_slot( gui, _slot );
    1021           0 : }
    1022             : 
    1023             : /* fd_guih_get_root_slot returns a handle to the closest ancestor of slot
    1024             :    that is a root, if available, otherwise NULL. */
    1025             : static inline fd_guih_slot_t *
    1026             : fd_guih_get_root_slot( fd_guih_t const * gui,
    1027           0 :                       ulong            slot ) {
    1028           0 :   fd_guih_slot_t * c = fd_guih_get_slot( gui, slot );
    1029           0 :   while( c ) {
    1030           0 :     if( FD_UNLIKELY( c->level>=FD_GUIH_SLOT_LEVEL_ROOTED ) ) return c;
    1031           0 :     c = fd_guih_get_slot( gui, c->parent_slot );
    1032           0 :   }
    1033           0 :   return NULL;
    1034           0 : }
    1035             : 
    1036             : /* fd_guih_slot_is_ancestor returns 1 if anc is known to be an ancestor
    1037             :    of slot (on the same fork), 0 otherwise. */
    1038             : static inline int
    1039             : fd_guih_slot_is_ancestor( fd_guih_t const * gui,
    1040             :                          ulong            anc,
    1041           0 :                          ulong            slot ) {
    1042           0 :   fd_guih_slot_t * c = fd_guih_get_slot( gui, slot );
    1043           0 :   while( c ) {
    1044           0 :     if( FD_UNLIKELY( c->slot==anc ) ) return 1;
    1045           0 :     c = fd_guih_get_slot( gui, c->parent_slot );
    1046           0 :   }
    1047           0 :   return 0;
    1048           0 : }
    1049             : 
    1050             : /* fd_guih_get_parent_slot_on_fork returns a handle to the parent of slot
    1051             :    on the fork ending on frontier_slot.  If slot is unknown or skipped,
    1052             :    the closest (by slot number) valid parent on the fork is returned.
    1053             : 
    1054             :    NULL if slot is not an ancestor of frontier slot or if the parent is
    1055             :    unknown. */
    1056             : static inline fd_guih_slot_t *
    1057             : fd_guih_get_parent_slot_on_fork( fd_guih_t const * gui,
    1058             :                                 ulong            frontier_slot,
    1059           0 :                                 ulong            slot ) {
    1060           0 :   fd_guih_slot_t * c = fd_guih_get_slot( gui, frontier_slot );
    1061           0 :   while( c ) {
    1062           0 :     if( FD_UNLIKELY( c->slot<=slot ) ) return NULL;
    1063           0 :     fd_guih_slot_t * p = fd_guih_get_slot( gui, c->parent_slot );
    1064           0 :     if( FD_UNLIKELY( p && p->slot<=slot-1UL ) ) return p;
    1065           0 :     c = p;
    1066           0 :   }
    1067           0 :   return NULL;
    1068           0 : }
    1069             : 
    1070             : /* fd_guih_is_skipped_on_fork returns 1 if slot is skipped on the fork
    1071             :    starting at anc and ending at des, 0 otherwise. */
    1072             : static inline int
    1073             : fd_guih_is_skipped_on_fork( fd_guih_t const * gui,
    1074             :                            ulong            anc,
    1075             :                            ulong            des,
    1076           0 :                            ulong            slot ) {
    1077           0 :   fd_guih_slot_t const * c = fd_guih_get_slot( gui, des );
    1078           0 :   while( c ) {
    1079           0 :     if( FD_UNLIKELY( anc==c->slot ) ) return 0; /* on the fork, not skipped */
    1080           0 :     fd_guih_slot_t const * p = fd_guih_get_slot( gui, c->parent_slot );
    1081           0 :     if( FD_UNLIKELY( p && p->slot<slot && c->slot>slot ) ) return 1; /* in-between two nodes, skipped */
    1082           0 :     c = p;
    1083           0 :   }
    1084           0 : 
    1085           0 :   return 0; /* slot not between anc and des, or is unknown */
    1086           0 : }
    1087             : 
    1088             : FD_PROTOTYPES_END
    1089             : 
    1090             : #endif /* HEADER_fd_src_discoh_guih_fd_guih_h */

Generated by: LCOV version 1.14