LCOV - code coverage report
Current view: top level - disco/gui - fd_gui_peers.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 77 0.0 %
Date: 2026-10-22 18:10:43 Functions: 0 80 0.0 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_disco_gui_fd_gui_peers_h
       2             : #define HEADER_fd_src_disco_gui_fd_gui_peers_h
       3             : 
       4             : /* fd_gui_peers defines methods that maintain metrics and metadata about
       5             :    Solana cluster peers that are active on the Gossip network.
       6             : 
       7             :    Peer identifiers are added and removed by incoming update messages
       8             :    from the gossip tile. Additional information about the peer is
       9             :    obtained from other places and merged into the a large peers table
      10             :    with live updates.
      11             : 
      12             :    fd_gui_peers also defines methods for handling messages from a
      13             :    WebSocket client. These messages contain peer related information,
      14             :    including a live view of the peer table with the option to order the
      15             :    table a custom sort key. */
      16             : 
      17             : #include "fd_gui_config_parse.h"
      18             : #include "fd_gui_ema.h"
      19             : #include "fd_gui_gossip_bw.h"
      20             : 
      21             : #include "../../disco/metrics/generated/fd_metrics_enums.h"
      22             : #include "../../flamenco/gossip/fd_gossip_message.h"
      23             : #include "../../flamenco/leaders/fd_leaders_base.h"
      24             : 
      25             : #include "../../waltz/http/fd_http_server.h"
      26             : #include "../../discof/restore/utils/fd_ssmsg.h"
      27             : #include "../topo/fd_topo.h"
      28             : #include "../../util/fd_hash32.h"
      29             : 
      30             : #define FD_GUI_GEOIP_ZSTD_COMPRESSION_LEVEL 19
      31           0 : #define FD_GUI_GEOIP_ZSTD_WINDOW_LOG 23
      32             : #define ZSTD_STATIC_LINKING_ONLY
      33             : #include <zstd.h>
      34             : 
      35             : #include <math.h>
      36             : 
      37             : /* Node in an IP geolocation binary trie.  The trie is built from a
      38             :    compressed binary file with the following format:
      39             : 
      40             :    GeoIp Binary layout
      41             :   | country_code_cnt (8 bytes) |
      42             :   | country_codes (2*country_code_cnt bytes) |
      43             :   | city_names_cnt (8 bytes) |
      44             :   | city_names (see below) |
      45             :   | zero pad to 4-byte alignment |
      46             :   | seg_cnt (8 bytes) |
      47             :   | seg_start (4*seg_cnt bytes) |
      48             :   | seg_country (1*seg_cnt bytes) |
      49             :   | zero pad to 4-byte alignment |
      50             :   | seg_city (4*seg_cnt bytes) |
      51             : 
      52             :   country_code_cnt: ulong count of country codes (little-endian)
      53             :   country_codes: Array of 2-byte ASCII country codes, not null-terminated.
      54             :   city_names_cnt: ulong count of city names (little-endian).
      55             :   city_names: Concatenation of variable-length, null-terminated city names
      56             :   seg_cnt: ulong count of segments
      57             : 
      58             :   The segments partition the entire IPv4 space into disjoint,
      59             :   contiguous ranges: segment i covers [seg_start[i], seg_start[i+1])
      60             :   (host byte order, little-endian on disk; seg_start[0]==0 and the
      61             :   last segment extends to 2^32).  The generator flattens the source
      62             :   database's (possibly nested) CIDR records into this form with
      63             :   longest-prefix-match semantics, so lookup is a binary search over
      64             :   seg_start rather than a bit trie walk: the columnar arrays are used
      65             :   in place directly out of the decompressed image, making startup a
      66             :   single streaming decompress.  seg_country[i] is an index into
      67             :   country_codes, or 255 for unmapped space; seg_city[i] is an index
      68             :   into city_names, or UINT_MAX. */
      69             : 
      70           0 : #define FD_GUI_GEOIP_BIN_MAX          (128UL<<20) /* decompressed image cap */
      71           0 : #define FD_GUI_GEOIP_MAX_CITY_NAME_SZ (80UL)
      72             : #define FD_GUI_GEOIP_MAX_CITY_CNT     (160000UL)
      73             : #define FD_GUI_GEOIP_MAX_COUNTRY_CNT  (254UL)
      74             : 
      75             : struct fd_gui_wfs_peer {
      76             :   fd_pubkey_t identity_key;
      77             :   ulong       stake;
      78             :   int         is_online;
      79             :   long        update_time_nanos;
      80             : 
      81             :   ulong       fresh_prev;
      82             :   ulong       fresh_next;
      83             : };
      84             : typedef struct fd_gui_wfs_peer fd_gui_wfs_peer_t;
      85             : 
      86             : #define DLIST_NAME  wfs_fresh_dlist
      87             : #define DLIST_ELE_T fd_gui_wfs_peer_t
      88           0 : #define DLIST_PREV  fresh_prev
      89           0 : #define DLIST_NEXT  fresh_next
      90             : #include "../../util/tmpl/fd_dlist.c"
      91             : 
      92           0 : #define FD_GUI_PEERS_NODE_ADD    (1)
      93           0 : #define FD_GUI_PEERS_NODE_UPDATE (2)
      94           0 : #define FD_GUI_PEERS_NODE_DELETE (3)
      95             : 
      96           0 : #define FD_GUI_PEERS_CI_TABLE_SORT_KEY_CNT                 (256UL) /* maximum number of maintained active sort keys */
      97             : #define FD_GUI_PEERS_WS_VIEWPORT_MAX_SZ                    (200UL) /* the maximum number of rows a client can request for a table viewport */
      98           0 : #define FD_GUI_PEERS_WS_VIEWPORT_UPDATE_INTERVAL_MILLIS    ( 150L)
      99           0 : #define FD_GUI_PEERS_METRIC_RATE_UPDATE_INTERVAL_MILLIS    ( 150L)
     100           0 : #define FD_GUI_PEERS_GOSSIP_STATS_UPDATE_INTERVAL_MILLIS   ( 300L)
     101             : 
     102             : FD_STATIC_ASSERT( FD_CONTACT_INFO_TABLE_SIZE < UINT_MAX, gui_peer_idx_fits_uint );
     103             : 
     104           0 : #define FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT (64UL)
     105             : 
     106             : static inline void
     107             : fd_gui_peers_top_insert( ulong *  top,
     108             :                          double * val,
     109             :                          ulong *  cnt,
     110             :                          ulong    max,
     111             :                          ulong    idx,
     112           0 :                          double   v ) {
     113           0 :   ulong n = *cnt;
     114           0 :   if( FD_LIKELY( n==max ) ) {
     115           0 :     if( FD_LIKELY( !max || !(v>val[ n-1UL ]) ) ) return;
     116           0 :     n--; /* drop the smallest */
     117           0 :   }
     118           0 :   ulong i = n;
     119           0 :   while( i && v>val[ i-1UL ] ) { top[ i ] = top[ i-1UL ]; val[ i ] = val[ i-1UL ]; i--; }
     120           0 :   top[ i ] = idx;
     121           0 :   val[ i ] = v;
     122           0 :   *cnt = n+1UL;
     123           0 : }
     124             : 
     125             : /* Some table columns are rates of change, which require keeping a
     126             :    historical value / timestamp. */
     127             : struct fd_gui_peers_metric_rate {
     128             :   ulong        cur;
     129             :   ulong        ref;
     130             :   fd_gui_ema_t rate_ema; /* units per sec. live_table treaps use this field to sort table entries */
     131             :   long         update_timestamp_ns; /* time when cur was last copied over to ref */
     132             : };
     133             : typedef struct fd_gui_peers_metric_rate fd_gui_peers_metric_rate_t;
     134             : 
     135           0 : #define FD_GUI_PEERS_EMA_HALF_LIFE_NS (3000000000L)
     136             : 
     137             : struct fd_gui_peers_voter {
     138             :   fd_vote_stake_weight_t weight;
     139             :   ulong vote_slot;
     140             : };
     141             : typedef struct fd_gui_peers_voter fd_gui_peers_voter_t;
     142             : 
     143             : struct fd_gui_peers_voter_idx {
     144             :   fd_pubkey_t key;
     145             :   ulong       idx;
     146             : };
     147             : typedef struct fd_gui_peers_voter_idx fd_gui_peers_voter_idx_t;
     148             : 
     149             : /* fd_gui_peers_row_t holds all of the per-peer state that is read when
     150             :    formatting websocket viewport messages snapshotted into a client's
     151             :    viewport. */
     152             : struct fd_gui_peers_row {
     153             :   int valid;
     154             :   long update_time_nanos;
     155             :   fd_pubkey_t pubkey;
     156             :   long wallclock_nanos;
     157             :   fd_gossip_contact_info_t contact_info;
     158             :   char name[ FD_GUI_CONFIG_PARSE_VALIDATOR_INFO_NAME_SZ + 1UL ];
     159             : 
     160             :   fd_gui_peers_metric_rate_t gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_TYPE_CNT ];
     161             :   fd_gui_peers_metric_rate_t gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_TYPE_CNT ];
     162             :   fd_gui_peers_metric_rate_t gossvf_rx_sum; /* sum of gossvf_rx */
     163             :   fd_gui_peers_metric_rate_t gossip_tx_sum; /* sum of gossip_tx */
     164             : 
     165             :   int         has_vote_info;
     166             :   fd_pubkey_t vote_account;
     167             :   int         delinquent;
     168             :   ulong       stake;
     169             : 
     170             :   uchar       country_code_idx;
     171             :   uint        city_name_idx;
     172             : };
     173             : typedef struct fd_gui_peers_row fd_gui_peers_row_t;
     174             : 
     175             : struct fd_gui_peers_node {
     176             :   fd_gui_peers_row_t row;
     177             : 
     178             :   struct {
     179             :     ulong next;
     180             :     ulong prev;
     181             :   } pubkey_map;
     182             : 
     183             :   struct {
     184             :     ulong next;
     185             :     ulong prev;
     186             :   } sock_map;
     187             : 
     188             :   struct {
     189             :     uint parent;
     190             :     uint left;
     191             :     uint right;
     192             :     uint prio;
     193             :     uint next;
     194             :     uint prev;
     195             :   } treaps_live_table[ FD_GUI_PEERS_CI_TABLE_SORT_KEY_CNT ];
     196             :   struct {
     197             :     ulong next;
     198             :     ulong prev;
     199             :   } dlist_live_table;
     200             :   ulong sort_keys_live_table;
     201             : 
     202             :   /* Peers that received or sent bytes since their rates last settled
     203             :      to zero.  Only these need their rate EMAs advanced. */
     204             :   int bw_dirty;
     205             :   struct {
     206             :     ulong next;
     207             :     ulong prev;
     208             :   } bw_dirty_dlist;
     209             : };
     210             : typedef struct fd_gui_peers_node fd_gui_peers_node_t;
     211             : 
     212             : #define DLIST_NAME  fd_gui_peers_bw_dirty_dlist
     213             : #define DLIST_ELE_T fd_gui_peers_node_t
     214           0 : #define DLIST_PREV  bw_dirty_dlist.prev
     215           0 : #define DLIST_NEXT  bw_dirty_dlist.next
     216             : #include "../../util/tmpl/fd_dlist.c"
     217             : 
     218             : struct fd_gui_peers_gossip_stats {
     219             :   long  sample_time;
     220             :   ulong network_health_pull_response_msg_rx_success;
     221             :   ulong network_health_pull_response_msg_rx_failure;
     222             :   ulong network_health_push_msg_rx_success;
     223             :   ulong network_health_push_msg_rx_failure;
     224             :   ulong network_health_push_crds_rx_duplicate;
     225             :   ulong network_health_pull_response_crds_rx_duplicate;
     226             :   ulong network_health_push_crds_rx_success;
     227             :   ulong network_health_push_crds_rx_failure;
     228             :   ulong network_health_pull_response_crds_rx_success;
     229             :   ulong network_health_pull_response_crds_rx_failure;
     230             :   ulong network_health_push_msg_tx;
     231             :   ulong network_health_pull_response_msg_tx;
     232             :   ulong network_health_total_stake; /* lamports */
     233             :   ulong network_health_total_peers;
     234             :   ulong network_health_connected_stake; /* lamports */
     235             :   ulong network_health_connected_staked_peers;
     236             :   ulong network_health_connected_unstaked_peers;
     237             :   ulong network_ingress_total_bytes;
     238             :   ulong network_ingress_peer_sz;
     239             :   long  network_ingress_peer_bytes_per_sec   [ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ];
     240             :   char  network_ingress_peer_names           [ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ][ FD_GUI_CONFIG_PARSE_VALIDATOR_INFO_NAME_SZ + 1UL ];
     241             :   fd_pubkey_t network_ingress_peer_identities[ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ];
     242             :   long  network_ingress_total_bytes_per_sec;
     243             :   ulong network_egress_total_bytes;
     244             :   ulong network_egress_peer_sz;
     245             :   long  network_egress_peer_bytes_per_sec   [ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ];
     246             :   char  network_egress_peer_names           [ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ][ FD_GUI_CONFIG_PARSE_VALIDATOR_INFO_NAME_SZ + 1UL ];
     247             :   fd_pubkey_t network_egress_peer_identities[ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ];
     248             :   long  network_egress_total_bytes_per_sec;
     249             :   ulong storage_capacity;
     250             :   ulong storage_expired_cnt;
     251             :   ulong storage_evicted_cnt;
     252             :   ulong storage_active_cnt[ FD_METRICS_ENUM_CRDS_VALUE_TYPE_CNT ];
     253             :   ulong storage_cnt_tx    [ FD_METRICS_ENUM_CRDS_VALUE_TYPE_CNT ];
     254             :   ulong storage_bytes_tx  [ FD_METRICS_ENUM_CRDS_VALUE_TYPE_CNT ];
     255             :   ulong messages_push_rx_cnt;
     256             :   ulong messages_push_tx_cnt;
     257             :   ulong messages_pull_response_rx_cnt;
     258             :   ulong messages_pull_response_tx_cnt;
     259             :   ulong messages_bytes_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_TYPE_CNT ];
     260             :   ulong messages_count_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_TYPE_CNT ];
     261             :   ulong messages_bytes_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_TYPE_CNT ];
     262             :   ulong messages_count_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_TYPE_CNT ];
     263             : };
     264             : typedef struct fd_gui_peers_gossip_stats fd_gui_peers_gossip_stats_t;
     265             : 
     266             : #define POOL_NAME fd_gui_peers_node_info_pool
     267           0 : #define POOL_T    fd_gui_config_parse_info_t
     268           0 : #define POOL_NEXT pool.next
     269             : #include "../../util/tmpl/fd_pool.c"
     270             : 
     271             : #define MAP_NAME  fd_gui_peers_node_info_map
     272             : #define MAP_ELE_T fd_gui_config_parse_info_t
     273             : #define MAP_KEY_T fd_pubkey_t
     274           0 : #define MAP_KEY   pubkey
     275           0 : #define MAP_IDX_T ulong
     276           0 : #define MAP_NEXT  map.next
     277           0 : #define MAP_PREV  map.prev
     278           0 : #define MAP_KEY_HASH(k,s) (fd_hash32( (k)->uc, (s) ))
     279           0 : #define MAP_KEY_EQ(k0,k1) (!memcmp((k0)->uc, (k1)->uc, 32UL))
     280             : #define MAP_OPTIMIZE_RANDOM_ACCESS_REMOVAL 1
     281             : #include "../../util/tmpl/fd_map_chain.c"
     282             : 
     283             : #define MAP_NAME  fd_gui_peers_node_pubkey_map
     284           0 : #define MAP_ELE_T fd_gui_peers_node_t
     285             : #define MAP_KEY_T fd_pubkey_t
     286           0 : #define MAP_KEY   row.pubkey
     287           0 : #define MAP_IDX_T ulong
     288           0 : #define MAP_NEXT  pubkey_map.next
     289           0 : #define MAP_PREV  pubkey_map.prev
     290           0 : #define MAP_KEY_HASH(k,s) (fd_hash32( (k)->uc, (s) ))
     291           0 : #define MAP_KEY_EQ(k0,k1) (!memcmp((k0)->uc, (k1)->uc, 32UL))
     292             : #define MAP_OPTIMIZE_RANDOM_ACCESS_REMOVAL 1
     293             : #include "../../util/tmpl/fd_map_chain.c"
     294             : 
     295             : static inline ulong
     296             : fd_gui_peers_sock_key_hash( fd_gossip_socket_t const * key,
     297           0 :                             ulong                      seed ) {
     298           0 :   if( FD_LIKELY( !key->is_ipv6 ) ) return fd_ulong_hash( seed ^ ((ulong)key->ip4<<16) ^ (ulong)key->port );
     299           0 :   else                             return fd_ulong_hash( fd_hash( seed, key->ip6, 16UL ) ^ (ulong)key->port );
     300           0 : }
     301             : 
     302             : #define MAP_NAME  fd_gui_peers_node_sock_map
     303           0 : #define MAP_ELE_T fd_gui_peers_node_t
     304             : #define MAP_KEY_T fd_gossip_socket_t
     305           0 : #define MAP_KEY   row.contact_info.sockets[ FD_GOSSIP_CONTACT_INFO_SOCKET_GOSSIP ]
     306           0 : #define MAP_IDX_T ulong
     307           0 : #define MAP_NEXT  sock_map.next
     308           0 : #define MAP_PREV  sock_map.prev
     309           0 : #define MAP_KEY_HASH(k,s) (fd_gui_peers_sock_key_hash( (k), (s) ))
     310           0 : #define MAP_KEY_EQ(k0,k1) ((k0)->is_ipv6==(k1)->is_ipv6 && (k0)->port==(k1)->port && (!((k0)->is_ipv6) ? (k0)->ip4==(k1)->ip4 : !memcmp((k0)->ip6,(k1)->ip6,16UL)) )
     311             : #define MAP_OPTIMIZE_RANDOM_ACCESS_REMOVAL 1
     312             : #define MAP_MULTI 1
     313             : #include "../../util/tmpl/fd_map_chain.c"
     314             : 
     315           0 : static int live_table_col_pubkey_lt( void const * a, void const * b ) { return memcmp( ((fd_pubkey_t *)a)->uc, ((fd_pubkey_t *)b)->uc, 32UL ) < 0;   }
     316             : 
     317           0 : static int live_table_col_double_lt( void const * a, void const * b ) { return *(double *)a < *(double *)b;                                          }
     318           0 : static int live_table_col_uchar_lt ( void const * a, void const * b ) { return *(uchar *)a < *(uchar *)b;                                            }
     319           0 : static int live_table_col_ipv4_lt  ( void const * a, void const * b ) { return fd_uint_bswap(*(uint *)a) < fd_uint_bswap(*(uint *)b);                }
     320           0 : static int live_table_col_name_lt  ( void const * a, void const * b ) { return memcmp( (char *)a, (char *)b, FD_GUI_CONFIG_PARSE_VALIDATOR_INFO_NAME_SZ + 1UL ) < 0; }
     321           0 : static int live_table_col_stake_lt ( void const * a, void const * b ) { return fd_long_if( *(ulong *)a>LONG_MAX, -1L, (long)*(ulong *)a ) < fd_long_if( *(ulong *)b>LONG_MAX, -1L, (long)*(ulong *)b ); }
     322             : 
     323             : #define LIVE_TABLE_NAME fd_gui_peers_live_table
     324           0 : #define LIVE_TABLE_TREAP treaps_live_table
     325           0 : #define LIVE_TABLE_SORT_KEYS sort_keys_live_table
     326           0 : #define LIVE_TABLE_DLIST dlist_live_table
     327           0 : #define LIVE_TABLE_COLUMN_CNT (9UL)
     328           0 : #define LIVE_TABLE_IDX_T uint
     329           0 : #define LIVE_TABLE_MAX_SORT_KEY_CNT FD_GUI_PEERS_CI_TABLE_SORT_KEY_CNT
     330             : #define LIVE_TABLE_ROW_T fd_gui_peers_node_t
     331           0 : #define LIVE_TABLE_COLUMNS LIVE_TABLE_COL_ARRAY( \
     332           0 :   LIVE_TABLE_COL_ENTRY( "Stake",        row.stake,                                                                    live_table_col_stake_lt  ), \
     333           0 :   LIVE_TABLE_COL_ENTRY( "Pubkey",       row.pubkey,                                                                   live_table_col_pubkey_lt ), \
     334           0 :   LIVE_TABLE_COL_ENTRY( "Name",         row.name,                                                                     live_table_col_name_lt   ), \
     335           0 :   LIVE_TABLE_COL_ENTRY( "Country",      row.country_code_idx,                                                         live_table_col_uchar_lt  ), \
     336           0 :   LIVE_TABLE_COL_ENTRY( "IP Addr",      row.contact_info.sockets[ FD_GOSSIP_CONTACT_INFO_SOCKET_GOSSIP ].ip4,         live_table_col_ipv4_lt   ), \
     337           0 :   LIVE_TABLE_COL_ENTRY( "Ingress Push", row.gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_TYPE_V_PUSH_IDX ].rate_ema.value,          live_table_col_double_lt ), \
     338           0 :   LIVE_TABLE_COL_ENTRY( "Ingress Pull", row.gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_TYPE_V_PULL_RESPONSE_IDX ].rate_ema.value, live_table_col_double_lt ), \
     339           0 :   LIVE_TABLE_COL_ENTRY( "Egress Push",  row.gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_TYPE_V_PUSH_IDX ].rate_ema.value,          live_table_col_double_lt ), \
     340           0 :   LIVE_TABLE_COL_ENTRY( "Egress Pull",  row.gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_TYPE_V_PULL_RESPONSE_IDX ].rate_ema.value, live_table_col_double_lt ), )
     341             : #include "fd_gui_live_table_tmpl.c"
     342             : 
     343           0 : #define FD_GUI_PEERS_LIVE_TABLE_DEFAULT_SORT_KEY ((fd_gui_peers_live_table_sort_key_t){ .col = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, .dir = { -1, -1, -1, -1, -1, -1, -1, -1, -1 } })
     344             : 
     345             : struct fd_gui_peers_ws_conn {
     346             :   int connected;
     347             :   long connected_time;
     348             : 
     349             :   ulong start_row;
     350             :   ulong row_cnt;
     351             :   fd_gui_peers_row_t viewport[ FD_GUI_PEERS_WS_VIEWPORT_MAX_SZ ];
     352             :   fd_gui_peers_live_table_sort_key_t sort_key;
     353             : };
     354             : 
     355             : typedef struct fd_gui_peers_ws_conn fd_gui_peers_ws_conn_t;
     356             : 
     357             : struct fd_gui_ip_db {
     358             :   /* Columnar disjoint-segment table, pointing into the decompressed
     359             :      database image (see format comment above). */
     360             :   ulong         seg_cnt;
     361             :   uint const *  seg_start;   /* [seg_cnt] sorted, host byte order */
     362             :   uchar const * seg_country; /* [seg_cnt] index into country_code, 255=unknown */
     363             :   uint const *  seg_city;    /* [seg_cnt] index into city_name, UINT_MAX=unknown */
     364             :   char country_code[ FD_GUI_GEOIP_MAX_COUNTRY_CNT ][ 3 ]; /* ISO 3166-1 alpha-2 country codes as cstrings */
     365             :   char city_name[ FD_GUI_GEOIP_MAX_CITY_CNT ][ FD_GUI_GEOIP_MAX_CITY_NAME_SZ ]; /* city_names as cstrings */
     366             : };
     367             : 
     368             : typedef struct fd_gui_ip_db fd_gui_ip_db_t;
     369             : 
     370             : struct fd_gui_peers_ctx {
     371             :   long next_client_nanos; /* ns timestamp when we'll service the next ws client */
     372             :   long next_metric_rate_update_nanos; /* ns timestamp when we'll next update rate-of-change metrics */
     373             :   long next_gossip_stats_update_nanos; /* ns timestamp when we'll next broadcast out gossip stats message */
     374             : 
     375             :   fd_gui_config_parse_info_t * node_info_pool;
     376             :   fd_gui_peers_node_info_map_t * node_info_map;
     377             :   fd_gui_peers_node_pubkey_map_t * node_pubkey_map;
     378             :   fd_gui_peers_node_sock_map_t  * node_sock_map;
     379             :   fd_gui_peers_live_table_t * live_table;
     380             :   fd_gui_peers_bw_dirty_dlist_t bw_dirty_dlist[ 1 ];
     381             : 
     382             :   fd_http_server_t * http;
     383             :   fd_topo_t const * topo;
     384             : 
     385             :   ulong max_ws_conn_cnt;
     386             :   ulong open_ws_conn_cnt;
     387             :   ulong active_ws_conn_id;
     388             :   fd_gui_peers_ws_conn_t * client_viewports; /* points to 2D array with max_ws_conn_cnt rows and FD_GUI_PEERS_WS_VIEWPORT_MAX_SZ columns */
     389             : 
     390             :   fd_gui_peers_gossip_stats_t gossip_stats  [ 1 ];
     391             :   fd_gui_peers_node_t contact_info_table[ FD_CONTACT_INFO_TABLE_SIZE ];
     392             : 
     393             :   ulong slot_voted; /* last vote slot for this validator */
     394             : 
     395             :   /* stakes is sorted descending by identity pubkey.  vote_idx is sorted
     396             :      descending by vote account pubkey, each entry pointing back into
     397             :      the stakes array. */
     398             :   struct {
     399             :     ulong epoch;
     400             : 
     401             :     ulong                    stakes_cnt;
     402             :     fd_gui_peers_voter_t     stakes  [ MAX_STAKE_WEIGHTS ];
     403             :     fd_gui_peers_voter_idx_t vote_idx[ MAX_STAKE_WEIGHTS ];
     404             :   } epochs[ 2 ];
     405             : 
     406             :   union {
     407             :     struct {
     408             :       int   actions[ FD_CONTACT_INFO_TABLE_SIZE ];
     409             :       ulong idxs   [ FD_CONTACT_INFO_TABLE_SIZE ];
     410             :     };
     411             :     struct {
     412             :       ulong wfs_peers[ FD_RUNTIME_MAX_SNAPSHOT_VOTE_ACCOUNTS ];
     413             :     };
     414             :     struct {
     415             :       fd_stake_weight_t      manifest_id_weights  [ FD_RUNTIME_MAX_SNAPSHOT_VOTE_ACCOUNTS ];
     416             :       fd_vote_stake_weight_t manifest_vote_weights[ FD_RUNTIME_MAX_SNAPSHOT_VOTE_ACCOUNTS ];
     417             :     };
     418             :     fd_gui_peers_voter_t voters_scratch[ MAX_STAKE_WEIGHTS ];
     419             :     struct {
     420             :       fd_gui_peers_row_t viewport    [ FD_GUI_PEERS_WS_VIEWPORT_MAX_SZ ]; /* new rows snapshotted from live_table */
     421             :       fd_gui_peers_row_t viewport_ref[ FD_GUI_PEERS_WS_VIEWPORT_MAX_SZ ]; /* old baseline, diff reference */
     422             :       ulong viewport_cnt;
     423             :     };
     424             :   } scratch;
     425             : 
     426             :   uchar * dbip_image;
     427             :   fd_gui_ip_db_t dbip;
     428             : 
     429             :   int               wfs_enabled;
     430             :   fd_gui_wfs_peer_t wfs_peers[ FD_RUNTIME_MAX_SNAPSHOT_VOTE_ACCOUNTS ];
     431             :   ulong             wfs_peers_cnt;
     432             :   int               wfs_peers_valid;
     433             :   int               wfs_stakes_sent;
     434             :   wfs_fresh_dlist_t wfs_fresh_dlist[ 1 ];
     435             : };
     436             : 
     437             : typedef struct fd_gui_peers_ctx fd_gui_peers_ctx_t;
     438             : 
     439             : /* FIXME: see src/discof/restore/utils/fd_ssmsg.h */
     440             : FD_STATIC_ASSERT( sizeof(((fd_gui_peers_ctx_t *)NULL)->wfs_peers)/sizeof(((fd_gui_peers_ctx_t *)NULL)->wfs_peers[0])==
     441             :                   sizeof(((struct fd_snapshot_manifest *)NULL)->vote_accounts)/sizeof(((struct fd_snapshot_manifest *)NULL)->vote_accounts[0]),
     442             :                   wfs_peers_vote_accounts );
     443             : 
     444             : FD_PROTOTYPES_BEGIN
     445             : 
     446             : FD_FN_CONST ulong
     447             : fd_gui_peers_align( void );
     448             : 
     449             : FD_FN_CONST ulong
     450             : fd_gui_peers_footprint( ulong max_ws_conn_cnt );
     451             : 
     452             : void *
     453             : fd_gui_peers_new( void *             shmem,
     454             :                   fd_http_server_t * http,
     455             :                   fd_topo_t const *  topo,
     456             :                   ulong              max_ws_conn_cnt,
     457             :                   char const *       wfs_expected_bank_hash_cstr,
     458             :                   ulong              seed,
     459             :                   long               now );
     460             : 
     461             : fd_gui_peers_ctx_t *
     462             : fd_gui_peers_join( void * shmem );
     463             : 
     464             : /* fd_gui_peers_handle_gossip_bw adds rec_cnt per-socket gossip byte
     465             :    counts to the peers owning those gossip sockets.  is_rx is true for
     466             :    ingress records from the gossvf tiles and false for egress records
     467             :    from the gossip tile.  Records for sockets with no known peer are
     468             :    ignored. */
     469             : 
     470             : void
     471             : fd_gui_peers_handle_gossip_bw( fd_gui_peers_ctx_t *           peers,
     472             :                                fd_gui_gossip_bw_rec_t const * rec,
     473             :                                ulong                          rec_cnt,
     474             :                                int                            is_rx );
     475             : 
     476             : /* fd_gui_peers_handle_gossip_update parses frags on the gossip_ciseen
     477             :    link and uses the contact info update to build up the peer table. */
     478             : 
     479             : void
     480             : fd_gui_peers_handle_gossip_update( fd_gui_peers_ctx_t *               peers,
     481             :                                    fd_gossip_update_message_t const * update,
     482             :                                    long                               now );
     483             : 
     484             : void
     485             : fd_gui_peers_handle_vote( fd_gui_peers_ctx_t * peers,
     486             :                           fd_pubkey_t const *  vote_account,
     487             :                           ulong                vote_slot,
     488             :                           int                  is_us );
     489             : 
     490             : /* fd_gui_peers_handle_identity_change invalidates/resets state from the
     491             :    previous identity.  Namely, it resets the vote slot. */
     492             : void
     493             : fd_gui_peers_handle_identity_change( fd_gui_peers_ctx_t * peers );
     494             : 
     495             : /* fd_gui_peers_update_delinquency is called infrequently (currently,
     496             :    once per slot) and scans the cluster for any nodes that are
     497             :    delinquent, publishing delinquency updates to the frontend. */
     498             : void
     499             : fd_gui_peers_update_delinquency( fd_gui_peers_ctx_t * peers,
     500             :                                  long                 now );
     501             : 
     502             : /* fd_gui_peers_handle_epoch_info is called at the epoch boundary and
     503             :    publishes updates for peer stake information. */
     504             : void
     505             : fd_gui_peers_handle_epoch_info( fd_gui_peers_ctx_t *        peers,
     506             :                                 fd_epoch_info_msg_t const * epoch_info,
     507             :                                 long                        now );
     508             : 
     509             : void
     510             : fd_gui_peers_handle_config_account( fd_gui_peers_ctx_t *  peers,
     511             :                                     uchar const *         data,
     512             :                                     ulong                 sz,
     513             :                                     ulong                 slot );
     514             : 
     515             : void
     516             : fd_gui_peers_stage_snapshot_manifest( fd_gui_peers_ctx_t *           peers,
     517             :                                       fd_snapshot_manifest_t const * manifest,
     518             :                                       long                           now );
     519             : 
     520             : void
     521             : fd_gui_peers_commit_snapshot_manifest( fd_gui_peers_ctx_t * peers );
     522             : 
     523             : /* fd_gui_peers_ws_message handles incoming websocket request payloads
     524             :    requesting peer-related responses.  ws_conn_id is the connection id
     525             :    of the requester.  data is a pointer to the start of the
     526             :    json-formatted request payload.  data_len is the length of the
     527             :    request payload. */
     528             : int
     529             : fd_gui_peers_ws_message( fd_gui_peers_ctx_t * peers,
     530             :                          ulong                ws_conn_id,
     531             :                          uchar const *        data,
     532             :                          ulong                data_len );
     533             : 
     534             : /* fd_gui_peers_ws_open is a callback which should be triggered when a
     535             :    new client opens a WebSocket connection.  ws_conn_id is the
     536             :    connection id of the new client.  now is a UNIX nanosecond timestamp
     537             :    for the current time. */
     538             : void
     539             : fd_gui_peers_ws_open( fd_gui_peers_ctx_t *  peers,
     540             :                       ulong                 ws_conn_id,
     541             :                       long                  now );
     542             : 
     543             : /* fd_gui_peers_ws_close is a callback which should be triggered when an
     544             :    existing client closes their WebSocket connection.  ws_conn_id is the
     545             :    connection id of the client.*/
     546             : void
     547             : fd_gui_peers_ws_close( fd_gui_peers_ctx_t * peers,
     548             :                        ulong                ws_conn_id );
     549             : 
     550             : /* fd_gui_peers_poll should be called in a the tile's main spin loop to
     551             :    periodically update peers internal state as well as publish new
     552             :    Websocket messages to clients. now is a UNIX nanosecond timestamp for
     553             :    the current time. */
     554             : int
     555             : fd_gui_peers_poll( fd_gui_peers_ctx_t * peers,
     556             :                    long                 now  );
     557             : 
     558             : /* fd_gui_peers_next_deadline returns the wallclock nanos at which the
     559             :    earliest of the periodic timers run by fd_gui_peers_poll (client
     560             :    viewport tick, rate update, gossip stats) is next due. */
     561             : 
     562             : long
     563             : fd_gui_peers_next_deadline( fd_gui_peers_ctx_t const * peers );
     564             : 
     565             : /* fd_gui_peers_rate_update advances the per-peer gossip bandwidth
     566             :    rate filters to now and re-keys the peers whose rates changed in the
     567             :    live table.  Called by fd_gui_peers_poll once per
     568             :    FD_GUI_PEERS_METRIC_RATE_UPDATE_INTERVAL_MILLIS; exposed for tests. */
     569             : void
     570             : fd_gui_peers_rate_update( fd_gui_peers_ctx_t * peers,
     571             :                           long                 now );
     572             : 
     573             : FD_PROTOTYPES_END
     574             : 
     575             : #endif /* HEADER_fd_src_disco_gui_fd_gui_peers_h */

Generated by: LCOV version 1.14