LCOV - code coverage report
Current view: top level - disco/gui - fd_gui_peers.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 75 0.0 %
Date: 2026-06-19 09:21:35 Functions: 0 28 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             : 
      19             : #include "../../disco/metrics/generated/fd_metrics_enums.h"
      20             : #include "../../flamenco/gossip/fd_gossip_message.h"
      21             : #include "../../flamenco/leaders/fd_leaders_base.h"
      22             : 
      23             : #include "../../waltz/http/fd_http_server.h"
      24             : #include "../../discof/restore/utils/fd_ssmsg.h"
      25             : #include "../topo/fd_topo.h"
      26             : 
      27             : #if FD_HAS_ZSTD
      28             : #define FD_GUI_GEOIP_ZSTD_COMPRESSION_LEVEL 19
      29           0 : #define FD_GUI_GEOIP_ZSTD_WINDOW_LOG 23
      30             : #define ZSTD_STATIC_LINKING_ONLY
      31             : #include <zstd.h>
      32             : #endif
      33             : 
      34             : #include <math.h>
      35             : 
      36             : /* Node in an IP geolocation binary trie.  The trie is built from a
      37             :    compressed binary file with the following format:
      38             : 
      39             :    GeoIp Binary layout
      40             :   | country_code_cnt (8 bytes) |
      41             :   | country_codes (2*country_code_cnt bytes) |
      42             :   | city_names_cnt (8 bytes) |
      43             :   | city_names (see below) |
      44             :   | record_cnt (8 bytes) |
      45             :   | records (record_cnt*10UL) |
      46             : 
      47             :   Record binary layout
      48             :   | ip (4 bytes) |
      49             :   | prefix_sz (1 byte) |
      50             :   | country_code_idx (1 byte) |
      51             :   | city_name_idx (4 bytes) |
      52             : 
      53             :   country_code_cnt: ulong count of country codes (little-endian)
      54             :   country_codes: Array of 2-byte ASCII country codes, not null-terminated.
      55             :   city_names_cnt: ulong count of city names (little-endian).
      56             :   city_names: Concatenation of variable-length, null-terminated city names
      57             :   record_cnt: ulong count of CIDR IP ranges in records
      58             :   records: Series of 10-byte records containing:
      59             :   ip: network ipv4 address (big-endian)
      60             :   prefix_sz: uchar count of 1 bits (up to 32) in the netmask of the CIDR address
      61             :   country_code_idx: uchar country code index, into country_codes
      62             :   city_name_idx: uint city name index, into city_names.
      63             : 
      64             :   In the trie, each node represents one bit position in an IP address.
      65             :   Paths follow 0 (left child) and 1 (right child) bits from the IP's MSB
      66             :   to LSB.  Nodes with has_prefix=1 indicate a match at that prefix
      67             :   length country_code_idx references the 2-letter country code in the
      68             :   table.  Maximum depth is 32 levels (for IPv4).
      69             : 
      70             :   FD_GUI_GEOIP_*_MAX_NODES should be larger than 2*num_records (since
      71             :   records are stored in the leaves of a binary tree). */
      72             : 
      73           0 : #define FD_GUI_GEOIP_DBIP_MAX_NODES   (1UL<<24UL) /* 16M nodes */
      74           0 : #define FD_GUI_GEOIP_MAX_CITY_NAME_SZ (80UL)
      75             : #define FD_GUI_GEOIP_MAX_CITY_CNT     (160000UL)
      76             : #define FD_GUI_GEOIP_MAX_COUNTRY_CNT  (254UL)
      77             : 
      78             : struct fd_gui_geoip_node {
      79             :   uchar has_prefix;
      80             :   uchar country_code_idx;
      81             :   uint  city_name_idx;
      82             : 
      83             :   struct fd_gui_geoip_node * left;
      84             :   struct fd_gui_geoip_node * right;
      85             : };
      86             : 
      87             : typedef struct fd_gui_geoip_node fd_gui_geoip_node_t;
      88             : 
      89             : struct fd_gui_wfs_peer {
      90             :   fd_pubkey_t identity_key;
      91             :   ulong       stake;
      92             :   int         is_online;
      93             :   long        update_time_nanos;
      94             : 
      95             :   ulong       fresh_prev;
      96             :   ulong       fresh_next;
      97             : };
      98             : typedef struct fd_gui_wfs_peer fd_gui_wfs_peer_t;
      99             : 
     100             : #define DLIST_NAME  wfs_fresh_dlist
     101             : #define DLIST_ELE_T fd_gui_wfs_peer_t
     102           0 : #define DLIST_PREV  fresh_prev
     103           0 : #define DLIST_NEXT  fresh_next
     104             : #include "../../util/tmpl/fd_dlist.c"
     105             : 
     106             : #define FD_GUI_PEERS_NODE_NOP    (0)
     107           0 : #define FD_GUI_PEERS_NODE_ADD    (1)
     108           0 : #define FD_GUI_PEERS_NODE_UPDATE (2)
     109           0 : #define FD_GUI_PEERS_NODE_DELETE (3)
     110             : 
     111           0 : #define FD_GUI_PEERS_CI_TABLE_SORT_KEY_CNT                 (256UL) /* maximum number of maintained active sort keys */
     112             : #define FD_GUI_PEERS_WS_VIEWPORT_MAX_SZ                    (200UL) /* the maximum number of rows a client can request for a table viewport */
     113           0 : #define FD_GUI_PEERS_WS_VIEWPORT_UPDATE_INTERVAL_MILLIS    ( 150L)
     114           0 : #define FD_GUI_PEERS_METRIC_RATE_UPDATE_INTERVAL_MILLIS    ( 150L)
     115           0 : #define FD_GUI_PEERS_GOSSIP_STATS_UPDATE_INTERVAL_MILLIS   ( 300L)
     116             : 
     117           0 : #define FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT (64UL)
     118             : 
     119             : /* Some table columns are rates of change, which require keeping a
     120             :    historical value / timestamp. */
     121             : struct fd_gui_peers_metric_rate {
     122             :   ulong cur;
     123             :   ulong ref;
     124             :   long rate_ema; /* units per sec. live_table treaps use this field to sort table entries */
     125             :   long update_timestamp_ns; /* time when cur was last copied over to ref */
     126             : };
     127             : typedef struct fd_gui_peers_metric_rate fd_gui_peers_metric_rate_t;
     128             : 
     129           0 : #define FD_GUI_PEERS_EMA_HALF_LIFE_NS (3000000000L)
     130             : 
     131             : /* fd_gui_ema computes an adaptive exponential moving average tick.
     132             :    Given the previous EMA value, a new sample, timestamps, and a
     133             :    half-life (all in nanoseconds), returns the updated EMA.  On the
     134             :    first call (last_update_nanos==0) the new sample is returned as-is
     135             :    to seed the series. */
     136             : 
     137             : static inline double
     138             : fd_gui_ema( long   last_update_nanos,
     139             :             long   now_nanos,
     140             :             double new_sample,
     141             :             double prev_ema,
     142           0 :             long   half_life_ns ) {
     143           0 :   if( FD_UNLIKELY( last_update_nanos==0L ) ) return new_sample;
     144             : 
     145           0 :   long dt = now_nanos - last_update_nanos;
     146           0 :   if( FD_UNLIKELY( dt<=0L ) ) return prev_ema;
     147             : 
     148           0 :   double alpha = 1.0 - exp( -0.69314718055994 * (double)dt / (double)half_life_ns );
     149           0 :   return alpha * new_sample + (1.0 - alpha) * prev_ema;
     150           0 : }
     151             : 
     152             : struct fd_gui_peers_voter {
     153             :   fd_vote_stake_weight_t weight;
     154             :   ulong vote_slot;
     155             : };
     156             : typedef struct fd_gui_peers_voter fd_gui_peers_voter_t;
     157             : 
     158             : struct fd_gui_peers_voter_idx {
     159             :   fd_pubkey_t key;
     160             :   ulong       idx;
     161             : };
     162             : typedef struct fd_gui_peers_voter_idx fd_gui_peers_voter_idx_t;
     163             : 
     164             : /* fd_gui_peers_row_t holds all of the per-peer state that is read when
     165             :    formatting websocket viewport messages snapshotted into a client's
     166             :    viewport. */
     167             : struct fd_gui_peers_row {
     168             :   int valid;
     169             :   long update_time_nanos;
     170             :   fd_pubkey_t pubkey;
     171             :   long wallclock_nanos;
     172             :   fd_gossip_contact_info_t contact_info;
     173             :   char name[ FD_GUI_CONFIG_PARSE_VALIDATOR_INFO_NAME_SZ + 1UL ];
     174             : 
     175             :   fd_gui_peers_metric_rate_t gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT ];
     176             :   fd_gui_peers_metric_rate_t gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT ];
     177             :   fd_gui_peers_metric_rate_t gossvf_rx_sum; /* sum of gossvf_rx */
     178             :   fd_gui_peers_metric_rate_t gossip_tx_sum; /* sum of gossip_tx */
     179             : 
     180             :   int         has_vote_info;
     181             :   fd_pubkey_t vote_account;
     182             :   int         delinquent;
     183             :   ulong       stake;
     184             : 
     185             :   uchar       country_code_idx;
     186             :   uint        city_name_idx;
     187             : };
     188             : typedef struct fd_gui_peers_row fd_gui_peers_row_t;
     189             : 
     190             : struct fd_gui_peers_node {
     191             :   fd_gui_peers_row_t row;
     192             : 
     193             :   struct {
     194             :     ulong next;
     195             :     ulong prev;
     196             :   } pubkey_map;
     197             : 
     198             :   struct {
     199             :     ulong next;
     200             :     ulong prev;
     201             :   } sock_map;
     202             : 
     203             :   struct {
     204             :     ulong parent;
     205             :     ulong left;
     206             :     ulong right;
     207             :     ulong prio;
     208             :     ulong next;
     209             :     ulong prev;
     210             :   } treaps_live_table[ FD_GUI_PEERS_CI_TABLE_SORT_KEY_CNT ];
     211             :   struct {
     212             :     ulong next;
     213             :     ulong prev;
     214             :   } dlist_live_table;
     215             :   ulong sort_keys_live_table;
     216             : 
     217             :   struct {
     218             :     ulong parent;
     219             :     ulong left;
     220             :     ulong right;
     221             :     ulong prio;
     222             :     ulong next;
     223             :     ulong prev;
     224             :   } treaps_bandwidth_tracking[ 2UL ];
     225             :     struct {
     226             :     ulong next;
     227             :     ulong prev;
     228             :   } dlist_bandwidth_tracking;
     229             :   ulong sort_keys_bandwidth_tracking;
     230             : };
     231             : typedef struct fd_gui_peers_node fd_gui_peers_node_t;
     232             : 
     233             : struct fd_gui_peers_gossip_stats {
     234             :   long  sample_time;
     235             :   ulong network_health_pull_response_msg_rx_success;
     236             :   ulong network_health_pull_response_msg_rx_failure;
     237             :   ulong network_health_push_msg_rx_success;
     238             :   ulong network_health_push_msg_rx_failure;
     239             :   ulong network_health_push_crds_rx_duplicate;
     240             :   ulong network_health_pull_response_crds_rx_duplicate;
     241             :   ulong network_health_push_crds_rx_success;
     242             :   ulong network_health_push_crds_rx_failure;
     243             :   ulong network_health_pull_response_crds_rx_success;
     244             :   ulong network_health_pull_response_crds_rx_failure;
     245             :   ulong network_health_push_msg_tx;
     246             :   ulong network_health_pull_response_msg_tx;
     247             :   ulong network_health_total_stake; /* lamports */
     248             :   ulong network_health_total_peers;
     249             :   ulong network_health_connected_stake; /* lamports */
     250             :   ulong network_health_connected_staked_peers;
     251             :   ulong network_health_connected_unstaked_peers;
     252             :   ulong network_ingress_total_bytes;
     253             :   ulong network_ingress_peer_sz;
     254             :   long  network_ingress_peer_bytes_per_sec   [ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ];
     255             :   char  network_ingress_peer_names           [ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ][ FD_GUI_CONFIG_PARSE_VALIDATOR_INFO_NAME_SZ + 1UL ];
     256             :   fd_pubkey_t network_ingress_peer_identities[ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ];
     257             :   long  network_ingress_total_bytes_per_sec;
     258             :   ulong network_egress_total_bytes;
     259             :   ulong network_egress_peer_sz;
     260             :   long  network_egress_peer_bytes_per_sec   [ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ];
     261             :   char  network_egress_peer_names           [ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ][ FD_GUI_CONFIG_PARSE_VALIDATOR_INFO_NAME_SZ + 1UL ];
     262             :   fd_pubkey_t network_egress_peer_identities[ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ];
     263             :   long  network_egress_total_bytes_per_sec;
     264             :   ulong storage_capacity;
     265             :   ulong storage_expired_cnt;
     266             :   ulong storage_evicted_cnt;
     267             :   ulong storage_active_cnt[ FD_METRICS_ENUM_CRDS_VALUE_CNT ];
     268             :   ulong storage_cnt_tx    [ FD_METRICS_ENUM_CRDS_VALUE_CNT ];
     269             :   ulong storage_bytes_tx  [ FD_METRICS_ENUM_CRDS_VALUE_CNT ];
     270             :   ulong messages_push_rx_cnt;
     271             :   ulong messages_push_tx_cnt;
     272             :   ulong messages_pull_response_rx_cnt;
     273             :   ulong messages_pull_response_tx_cnt;
     274             :   ulong messages_bytes_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT ];
     275             :   ulong messages_count_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT ];
     276             :   ulong messages_bytes_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT ];
     277             :   ulong messages_count_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT ];
     278             : };
     279             : typedef struct fd_gui_peers_gossip_stats fd_gui_peers_gossip_stats_t;
     280             : 
     281             : #define POOL_NAME fd_gui_peers_node_info_pool
     282           0 : #define POOL_T    fd_gui_config_parse_info_t
     283           0 : #define POOL_NEXT pool.next
     284             : #include "../../util/tmpl/fd_pool.c"
     285             : 
     286             : #define MAP_NAME  fd_gui_peers_node_info_map
     287             : #define MAP_ELE_T fd_gui_config_parse_info_t
     288             : #define MAP_KEY_T fd_pubkey_t
     289           0 : #define MAP_KEY   pubkey
     290           0 : #define MAP_IDX_T ulong
     291           0 : #define MAP_NEXT  map.next
     292           0 : #define MAP_PREV  map.prev
     293           0 : #define MAP_KEY_HASH(k,s) (fd_hash( (s), (k)->uc, sizeof(fd_pubkey_t) ))
     294           0 : #define MAP_KEY_EQ(k0,k1) (!memcmp((k0)->uc, (k1)->uc, 32UL))
     295             : #define MAP_OPTIMIZE_RANDOM_ACCESS_REMOVAL 1
     296             : #include "../../util/tmpl/fd_map_chain.c"
     297             : 
     298             : #define MAP_NAME  fd_gui_peers_node_pubkey_map
     299           0 : #define MAP_ELE_T fd_gui_peers_node_t
     300             : #define MAP_KEY_T fd_pubkey_t
     301           0 : #define MAP_KEY   row.pubkey
     302           0 : #define MAP_IDX_T ulong
     303           0 : #define MAP_NEXT  pubkey_map.next
     304           0 : #define MAP_PREV  pubkey_map.prev
     305           0 : #define MAP_KEY_HASH(k,s) (fd_hash( (s), (k)->uc, sizeof(fd_pubkey_t) ))
     306           0 : #define MAP_KEY_EQ(k0,k1) (!memcmp((k0)->uc, (k1)->uc, 32UL))
     307             : #define MAP_OPTIMIZE_RANDOM_ACCESS_REMOVAL 1
     308             : #include "../../util/tmpl/fd_map_chain.c"
     309             : 
     310             : #define MAP_NAME  fd_gui_peers_node_sock_map
     311           0 : #define MAP_ELE_T fd_gui_peers_node_t
     312             : #define MAP_KEY_T fd_gossip_socket_t
     313           0 : #define MAP_KEY   row.contact_info.sockets[ FD_GOSSIP_CONTACT_INFO_SOCKET_GOSSIP ]
     314           0 : #define MAP_IDX_T ulong
     315           0 : #define MAP_NEXT  sock_map.next
     316           0 : #define MAP_PREV  sock_map.prev
     317           0 : #define MAP_KEY_HASH(k,s) ( fd_hash( (s), (k), sizeof(uint) + sizeof(ushort) ) )
     318           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)) )
     319             : #define MAP_OPTIMIZE_RANDOM_ACCESS_REMOVAL 1
     320             : #define MAP_MULTI 1
     321             : #include "../../util/tmpl/fd_map_chain.c"
     322             : 
     323           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;   }
     324           0 : static int live_table_col_long_lt  ( void const * a, void const * b ) { return *(long *)a < *(long *)b;                                              }
     325           0 : static int live_table_col_uchar_lt ( void const * a, void const * b ) { return *(uchar *)a < *(uchar *)b;                                            }
     326           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);                }
     327           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; }
     328           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 ); }
     329             : 
     330             : #define LIVE_TABLE_NAME fd_gui_peers_live_table
     331           0 : #define LIVE_TABLE_TREAP treaps_live_table
     332           0 : #define LIVE_TABLE_SORT_KEYS sort_keys_live_table
     333           0 : #define LIVE_TABLE_DLIST dlist_live_table
     334           0 : #define LIVE_TABLE_COLUMN_CNT (9UL)
     335           0 : #define LIVE_TABLE_MAX_SORT_KEY_CNT FD_GUI_PEERS_CI_TABLE_SORT_KEY_CNT
     336             : #define LIVE_TABLE_ROW_T fd_gui_peers_node_t
     337           0 : #define LIVE_TABLE_COLUMNS LIVE_TABLE_COL_ARRAY( \
     338           0 :   LIVE_TABLE_COL_ENTRY( "Stake",        row.stake,                                                                    live_table_col_stake_lt  ), \
     339           0 :   LIVE_TABLE_COL_ENTRY( "Pubkey",       row.pubkey,                                                                   live_table_col_pubkey_lt ), \
     340           0 :   LIVE_TABLE_COL_ENTRY( "Name",         row.name,                                                                     live_table_col_name_lt   ), \
     341           0 :   LIVE_TABLE_COL_ENTRY( "Country",      row.country_code_idx,                                                         live_table_col_uchar_lt  ), \
     342           0 :   LIVE_TABLE_COL_ENTRY( "IP Addr",      row.contact_info.sockets[ FD_GOSSIP_CONTACT_INFO_SOCKET_GOSSIP ].ip4,         live_table_col_ipv4_lt   ), \
     343           0 :   LIVE_TABLE_COL_ENTRY( "Ingress Push", row.gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate_ema,          live_table_col_long_lt   ), \
     344           0 :   LIVE_TABLE_COL_ENTRY( "Ingress Pull", row.gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate_ema, live_table_col_long_lt   ), \
     345           0 :   LIVE_TABLE_COL_ENTRY( "Egress Push",  row.gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate_ema,          live_table_col_long_lt   ), \
     346           0 :   LIVE_TABLE_COL_ENTRY( "Egress Pull",  row.gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate_ema, live_table_col_long_lt   ), )
     347             : #include "fd_gui_live_table_tmpl.c"
     348             : 
     349           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 } })
     350             : 
     351             : #define LIVE_TABLE_NAME fd_gui_peers_bandwidth_tracking
     352           0 : #define LIVE_TABLE_TREAP treaps_bandwidth_tracking
     353           0 : #define LIVE_TABLE_SORT_KEYS sort_keys_bandwidth_tracking
     354           0 : #define LIVE_TABLE_DLIST dlist_bandwidth_tracking
     355           0 : #define LIVE_TABLE_COLUMN_CNT (2UL)
     356           0 : #define LIVE_TABLE_MAX_SORT_KEY_CNT (2UL)
     357             : #define LIVE_TABLE_ROW_T fd_gui_peers_node_t
     358           0 : #define LIVE_TABLE_COLUMNS LIVE_TABLE_COL_ARRAY( \
     359           0 :   LIVE_TABLE_COL_ENTRY( "Ingress Total", row.gossvf_rx_sum.rate_ema, live_table_col_long_lt ), \
     360           0 :   LIVE_TABLE_COL_ENTRY( "Egress Total",  row.gossip_tx_sum.rate_ema, live_table_col_long_lt )  )
     361             : #include "fd_gui_live_table_tmpl.c"
     362             : 
     363           0 : #define FD_GUI_PEERS_BW_TRACKING_INGRESS_SORT_KEY ((fd_gui_peers_bandwidth_tracking_sort_key_t){ .col = { 0, 1 }, .dir = { -1, 0 } })
     364           0 : #define FD_GUI_PEERS_BW_TRACKING_EGRESS_SORT_KEY  ((fd_gui_peers_bandwidth_tracking_sort_key_t){ .col = { 0, 1 }, .dir = { 0, -1 } })
     365             : 
     366             : struct fd_gui_peers_ws_conn {
     367             :   int connected;
     368             :   long connected_time;
     369             : 
     370             :   ulong start_row;
     371             :   ulong row_cnt;
     372             :   fd_gui_peers_row_t viewport[ FD_GUI_PEERS_WS_VIEWPORT_MAX_SZ ];
     373             :   fd_gui_peers_live_table_sort_key_t sort_key;
     374             : };
     375             : 
     376             : typedef struct fd_gui_peers_ws_conn fd_gui_peers_ws_conn_t;
     377             : 
     378             : struct fd_gui_ip_db {
     379             :   fd_gui_geoip_node_t * nodes;
     380             :   char country_code[ FD_GUI_GEOIP_MAX_COUNTRY_CNT ][ 3 ]; /* ISO 3166-1 alpha-2 country codes as cstrings */
     381             :   char city_name[ FD_GUI_GEOIP_MAX_CITY_CNT ][ FD_GUI_GEOIP_MAX_CITY_NAME_SZ ]; /* city_names as cstrings */
     382             : };
     383             : 
     384             : typedef struct fd_gui_ip_db fd_gui_ip_db_t;
     385             : 
     386             : struct fd_gui_peers_ctx {
     387             :   long next_client_nanos; /* ns timestamp when we'll service the next ws client */
     388             :   long next_metric_rate_update_nanos; /* ns timestamp when we'll next update rate-of-change metrics */
     389             :   long next_gossip_stats_update_nanos; /* ns timestamp when we'll next broadcast out gossip stats message */
     390             : 
     391             :   fd_gui_config_parse_info_t * node_info_pool;
     392             :   fd_gui_peers_node_info_map_t * node_info_map;
     393             :   fd_gui_peers_node_pubkey_map_t * node_pubkey_map;
     394             :   fd_gui_peers_node_sock_map_t  * node_sock_map;
     395             :   fd_gui_peers_live_table_t * live_table;
     396             :   fd_gui_peers_bandwidth_tracking_t * bw_tracking;
     397             : 
     398             :   fd_http_server_t * http;
     399             :   fd_topo_t const * topo;
     400             : 
     401             :   ulong max_ws_conn_cnt;
     402             :   ulong open_ws_conn_cnt;
     403             :   ulong active_ws_conn_id;
     404             :   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 */
     405             : 
     406             :   fd_gui_peers_gossip_stats_t gossip_stats  [ 1 ];
     407             :   fd_gui_peers_node_t contact_info_table[ FD_CONTACT_INFO_TABLE_SIZE ];
     408             : 
     409             :   ulong slot_voted; /* last vote slot for this validator */
     410             : 
     411             :   /* stakes is sorted descending by identity pubkey.  vote_idx is sorted
     412             :      descending by vote account pubkey, each entry pointing back into
     413             :      the stakes array. */
     414             :   struct {
     415             :     ulong epoch;
     416             : 
     417             :     ulong                    stakes_cnt;
     418             :     fd_gui_peers_voter_t     stakes  [ MAX_COMPRESSED_STAKE_WEIGHTS ];
     419             :     fd_gui_peers_voter_idx_t vote_idx[ MAX_COMPRESSED_STAKE_WEIGHTS ];
     420             :   } epochs[ 2 ];
     421             : 
     422             :   union {
     423             :     struct {
     424             :       int   actions[ FD_CONTACT_INFO_TABLE_SIZE ];
     425             :       ulong idxs   [ FD_CONTACT_INFO_TABLE_SIZE ];
     426             :     };
     427             :     struct {
     428             :       ulong wfs_peers[ FD_VOTE_ACCOUNTS_MAX ];
     429             :     };
     430             :     struct {
     431             :       fd_stake_weight_t      manifest_id_weights  [ FD_VOTE_ACCOUNTS_MAX ];
     432             :       fd_vote_stake_weight_t manifest_vote_weights[ FD_VOTE_ACCOUNTS_MAX ];
     433             :     };
     434             :     fd_gui_peers_voter_t voters_scratch[ MAX_COMPRESSED_STAKE_WEIGHTS ];
     435             :     struct {
     436             :       fd_gui_peers_row_t viewport    [ FD_GUI_PEERS_WS_VIEWPORT_MAX_SZ ]; /* new rows snapshotted from live_table */
     437             :       fd_gui_peers_row_t viewport_ref[ FD_GUI_PEERS_WS_VIEWPORT_MAX_SZ ]; /* old baseline, diff reference */
     438             :       ulong viewport_cnt;
     439             :     };
     440             :   } scratch;
     441             : 
     442             : #if FD_HAS_ZSTD
     443             :   ZSTD_DCtx * zstd_dctx;
     444             : #endif
     445             : 
     446             :   fd_gui_ip_db_t dbip;
     447             : 
     448             :   int                       wfs_enabled;
     449             :   fd_gui_wfs_peer_t         wfs_peers[ FD_VOTE_ACCOUNTS_MAX ];
     450             :   ulong                     wfs_peers_cnt;
     451             :   int                       wfs_peers_valid;
     452             :   int                       wfs_stakes_sent;
     453             :   wfs_fresh_dlist_t         wfs_fresh_dlist[ 1 ];
     454             : };
     455             : 
     456             : typedef struct fd_gui_peers_ctx fd_gui_peers_ctx_t;
     457             : 
     458             : /* FIXME: see src/discof/restore/utils/fd_ssmsg.h */
     459             : FD_STATIC_ASSERT( sizeof(((fd_gui_peers_ctx_t *)NULL)->wfs_peers)/sizeof(((fd_gui_peers_ctx_t *)NULL)->wfs_peers[0])==
     460             :                   sizeof(((struct fd_snapshot_manifest *)NULL)->vote_accounts)/sizeof(((struct fd_snapshot_manifest *)NULL)->vote_accounts[0]),
     461             :                   wfs_peers_vote_accounts );
     462             : 
     463             : FD_PROTOTYPES_BEGIN
     464             : 
     465             : FD_FN_CONST ulong
     466             : fd_gui_peers_align( void );
     467             : 
     468             : FD_FN_CONST ulong
     469             : fd_gui_peers_footprint( ulong max_ws_conn_cnt );
     470             : 
     471             : void *
     472             : fd_gui_peers_new( void *             shmem,
     473             :                   fd_http_server_t * http,
     474             :                   fd_topo_t const *  topo,
     475             :                   ulong              max_ws_conn_cnt,
     476             :                   char const *       wfs_expected_bank_hash_cstr,
     477             :                   long               now );
     478             : 
     479             : fd_gui_peers_ctx_t *
     480             : fd_gui_peers_join( void * shmem );
     481             : 
     482             : /* fd_gui_peers_handle_gossip_message_rx parses gossip messages from the
     483             :    net_gossvf link for ingress messages and the gossip_net link for
     484             :    egress messages and tracks per-peer, per-message bytes.  payload and
     485             :    payload_sz corresponds to the frag data after the network headers
     486             :    have been stripped. is_rx is true if the frag is an incoming message
     487             :    from the net_gossvf link. Otherwise, the frag is assumed to be an
     488             :    outgoing message from the gossip_net link. peer_sock is the ipv4
     489             :    address and port from the stripped net headers, which identifies the
     490             :    peers that sent or will receive the message.
     491             : 
     492             :    Note that gossip_net frags are unverified gossip messages from the
     493             :    network.  Messages that cannot be parsed are ignored. */
     494             : void
     495             : fd_gui_peers_handle_gossip_message( fd_gui_peers_ctx_t *       peers,
     496             :                                     uchar const *              payload,
     497             :                                     ulong                      payload_sz,
     498             :                                     fd_gossip_socket_t const * peer_sock,
     499             :                                     int                        is_rx );
     500             : 
     501             : /* fd_gui_peers_handle_gossip_message_tx parses frags on the gossip_out
     502             :    link and uses the contact info update to build up the peer table. */
     503             : 
     504             : void
     505             : fd_gui_peers_handle_gossip_update( fd_gui_peers_ctx_t *               peers,
     506             :                                    fd_gossip_update_message_t const * update,
     507             :                                    long                               now );
     508             : 
     509             : void
     510             : fd_gui_peers_handle_vote( fd_gui_peers_ctx_t * peers,
     511             :                           fd_pubkey_t const *  vote_account,
     512             :                           ulong                vote_slot,
     513             :                           int                  is_us );
     514             : 
     515             : /* fd_gui_peers_update_delinquency is called infrequently (currently,
     516             :    once per slot) and scans the cluster for any nodes that are
     517             :    delinquent, publishing delinquency updates to the frontend. */
     518             : void
     519             : fd_gui_peers_update_delinquency( fd_gui_peers_ctx_t * peers,
     520             :                                  long                 now );
     521             : 
     522             : /* fd_gui_peers_handle_epoch_info is called at the epoch boundary and
     523             :    publishes updates for peer stake information. */
     524             : void
     525             : fd_gui_peers_handle_epoch_info( fd_gui_peers_ctx_t *        peers,
     526             :                                 fd_epoch_info_msg_t const * epoch_info,
     527             :                                 long                        now );
     528             : 
     529             : void
     530             : fd_gui_peers_handle_config_account( fd_gui_peers_ctx_t *  peers,
     531             :                                     uchar const *         data,
     532             :                                     ulong                 sz );
     533             : 
     534             : void
     535             : fd_gui_peers_stage_snapshot_manifest( fd_gui_peers_ctx_t *           peers,
     536             :                                       fd_snapshot_manifest_t const * manifest,
     537             :                                       long                           now );
     538             : 
     539             : void
     540             : fd_gui_peers_commit_snapshot_manifest( fd_gui_peers_ctx_t * peers );
     541             : 
     542             : /* fd_gui_peers_ws_message handles incoming websocket request payloads
     543             :    requesting peer-related responses.  ws_conn_id is the connection id
     544             :    of the requester.  data is a pointer to the start of the
     545             :    json-formatted request payload.  data_len is the length of the
     546             :    request payload. */
     547             : int
     548             : fd_gui_peers_ws_message( fd_gui_peers_ctx_t * peers,
     549             :                          ulong                ws_conn_id,
     550             :                          uchar const *        data,
     551             :                          ulong                data_len );
     552             : 
     553             : /* fd_gui_peers_ws_open is a callback which should be triggered when a
     554             :    new client opens a WebSocket connection.  ws_conn_id is the
     555             :    connection id of the new client.  now is a UNIX nanosecond timestamp
     556             :    for the current time. */
     557             : void
     558             : fd_gui_peers_ws_open( fd_gui_peers_ctx_t *  peers,
     559             :                       ulong                 ws_conn_id,
     560             :                       long                  now );
     561             : 
     562             : /* fd_gui_peers_ws_close is a callback which should be triggered when an
     563             :    existing client closes their WebSocket connection.  ws_conn_id is the
     564             :    connection id of the client.*/
     565             : void
     566             : fd_gui_peers_ws_close( fd_gui_peers_ctx_t * peers,
     567             :                        ulong                ws_conn_id );
     568             : 
     569             : /* fd_gui_peers_poll should be called in a the tile's main spin loop to
     570             :    periodically update peers internal state as well as publish new
     571             :    Websocket messages to clients. now is a UNIX nanosecond timestamp for
     572             :    the current time. */
     573             : int
     574             : fd_gui_peers_poll( fd_gui_peers_ctx_t * peers,
     575             :                    long                 now  );
     576             : 
     577             : FD_PROTOTYPES_END
     578             : 
     579             : #endif /* HEADER_fd_src_disco_gui_fd_gui_peers_h */

Generated by: LCOV version 1.14