LCOV - code coverage report
Current view: top level - disco/gui - fd_gui_peers.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 49 0.0 %
Date: 2025-10-13 04:42:14 Functions: 0 12 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 "../../util/net/fd_net_headers.h"
      18             : #include "../../disco/metrics/fd_metrics.h"
      19             : #include "../../flamenco/gossip/fd_gossip_types.h"
      20             : #include "../../waltz/http/fd_http_server.h"
      21             : #include "../topo/fd_topo.h"
      22             : 
      23             : #define FD_GUI_PEERS_VALIDATOR_INFO_NAME_SZ     ( 64UL)
      24             : #define FD_GUI_PEERS_VALIDATOR_INFO_WEBSITE_SZ  (128UL)
      25             : #define FD_GUI_PEERS_VALIDATOR_INFO_DETAILS_SZ  (256UL)
      26             : #define FD_GUI_PEERS_VALIDATOR_INFO_ICON_URI_SZ (128UL)
      27             : 
      28           0 : #define FD_GUI_PEERS_NODE_NOP    (0)
      29           0 : #define FD_GUI_PEERS_NODE_ADD    (1)
      30           0 : #define FD_GUI_PEERS_NODE_UPDATE (2)
      31             : #define FD_GUI_PEERS_NODE_DELETE (3)
      32             : 
      33           0 : #define FD_GUI_PEERS_CI_TABLE_SORT_KEY_CNT                 (256UL) /* maximum number of maintained active sort keys */
      34           0 : #define FD_GUI_PEERS_WS_VIEWPORT_MAX_SZ                    (200UL) /* the maximum number of rows a client can request for a table viewport */
      35           0 : #define FD_GUI_PEERS_WS_VIEWPORT_UPDATE_INTERVAL_MILLIS    ( 100L)
      36           0 : #define FD_GUI_PEERS_METRIC_RATE_UPDATE_INTERVAL_MILLIS    ( 100L)
      37           0 : #define FD_GUI_PEERS_GOSSIP_STATS_UPDATE_INTERVAL_MILLIS   ( 100L)
      38             : 
      39           0 : #define FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT (64UL)
      40             : 
      41             : /* Some table columns are rates of change, which require keeping a
      42             :    historical value / timestamp. */
      43             : struct fd_gui_peers_metric_rate {
      44             :   ulong cur;
      45             :   ulong ref;
      46             :   long rate; /* units per sec. live_table treaps use this field to sort table entries */
      47             : };
      48             : typedef struct fd_gui_peers_metric_rate fd_gui_peers_metric_rate_t;
      49             : 
      50             : struct fd_gui_peers_node {
      51             :   int valid;
      52             :   long update_time_nanos;
      53             :   fd_contact_info_t contact_info;
      54             : 
      55             :   fd_gui_peers_metric_rate_t gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT ];
      56             :   fd_gui_peers_metric_rate_t gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT ];
      57             :   fd_gui_peers_metric_rate_t gossvf_rx_sum; /* sum of gossvf_rx */
      58             :   fd_gui_peers_metric_rate_t gossip_tx_sum; /* sum of gossip_tx */
      59             : 
      60             :   int         has_node_info;
      61             :   char name    [ FD_GUI_PEERS_VALIDATOR_INFO_NAME_SZ     ];
      62             :   char website [ FD_GUI_PEERS_VALIDATOR_INFO_WEBSITE_SZ  ];
      63             :   char details [ FD_GUI_PEERS_VALIDATOR_INFO_DETAILS_SZ  ];
      64             :   char icon_uri[ FD_GUI_PEERS_VALIDATOR_INFO_ICON_URI_SZ ];
      65             : 
      66             :   struct {
      67             :     ulong next;
      68             :     ulong prev;
      69             :   } pubkey_map;
      70             : 
      71             :   struct {
      72             :     ulong next;
      73             :     ulong prev;
      74             :   } sock_map;
      75             : 
      76             :   struct {
      77             :     ulong parent;
      78             :     ulong left;
      79             :     ulong right;
      80             :     ulong prio;
      81             :     ulong next;
      82             :     ulong prev;
      83             :   } treaps_live_table[ FD_GUI_PEERS_CI_TABLE_SORT_KEY_CNT ];
      84             :   struct {
      85             :     ulong next;
      86             :     ulong prev;
      87             :   } dlist_live_table;
      88             :   ulong sort_keys_live_table;
      89             : 
      90             :   struct {
      91             :     ulong parent;
      92             :     ulong left;
      93             :     ulong right;
      94             :     ulong prio;
      95             :     ulong next;
      96             :     ulong prev;
      97             :   } treaps_bandwidth_tracking[ 2UL ];
      98             :     struct {
      99             :     ulong next;
     100             :     ulong prev;
     101             :   } dlist_bandwidth_tracking;
     102             :   ulong sort_keys_bandwidth_tracking;
     103             : };
     104             : typedef struct fd_gui_peers_node fd_gui_peers_node_t;
     105             : 
     106             : struct fd_gui_peers_gossip_stats {
     107             :   long  sample_time;
     108             :   ulong network_health_pull_response_msg_rx_success;
     109             :   ulong network_health_pull_response_msg_rx_failure;
     110             :   ulong network_health_push_msg_rx_success;
     111             :   ulong network_health_push_msg_rx_failure;
     112             :   ulong network_health_push_crds_rx_duplicate;
     113             :   ulong network_health_pull_response_crds_rx_duplicate;
     114             :   ulong network_health_push_crds_rx_success;
     115             :   ulong network_health_push_crds_rx_failure;
     116             :   ulong network_health_pull_response_crds_rx_success;
     117             :   ulong network_health_pull_response_crds_rx_failure;
     118             :   ulong network_health_push_msg_tx;
     119             :   ulong network_health_pull_response_msg_tx;
     120             :   ulong network_health_total_stake; /* lamports */
     121             :   ulong network_health_total_peers;
     122             :   ulong network_health_connected_stake; /* lamports */
     123             :   ulong network_health_connected_staked_peers;
     124             :   ulong network_health_connected_unstaked_peers;
     125             :   ulong network_ingress_total_bytes;
     126             :   ulong network_ingress_peer_sz;
     127             :   long  network_ingress_peer_bytes_per_sec   [ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ];
     128             :   char  network_ingress_peer_names           [ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ][ FD_GUI_PEERS_VALIDATOR_INFO_NAME_SZ ];
     129             :   fd_pubkey_t network_ingress_peer_identities[ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ];
     130             :   long  network_ingress_total_bytes_per_sec;
     131             :   ulong network_egress_total_bytes;
     132             :   ulong network_egress_peer_sz;
     133             :   long  network_egress_peer_bytes_per_sec   [ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ];
     134             :   char  network_egress_peer_names           [ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ][ FD_GUI_PEERS_VALIDATOR_INFO_NAME_SZ ];
     135             :   fd_pubkey_t network_egress_peer_identities[ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ];
     136             :   long  network_egress_total_bytes_per_sec;
     137             :   ulong storage_capacity;
     138             :   ulong storage_expired_cnt;
     139             :   ulong storage_evicted_cnt;
     140             :   ulong storage_active_cnt[ FD_METRICS_ENUM_CRDS_VALUE_CNT ];
     141             :   ulong storage_cnt_tx    [ FD_METRICS_ENUM_CRDS_VALUE_CNT ];
     142             :   ulong storage_bytes_tx  [ FD_METRICS_ENUM_CRDS_VALUE_CNT ];
     143             :   ulong messages_push_rx_cnt;
     144             :   ulong messages_push_tx_cnt;
     145             :   ulong messages_pull_response_rx_cnt;
     146             :   ulong messages_pull_response_tx_cnt;
     147             :   ulong messages_bytes_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT ];
     148             :   ulong messages_count_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT ];
     149             :   ulong messages_bytes_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT ];
     150             :   ulong messages_count_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT ];
     151             : };
     152             : typedef struct fd_gui_peers_gossip_stats fd_gui_peers_gossip_stats_t;
     153             : 
     154             : #define MAP_NAME  fd_gui_peers_node_pubkey_map
     155           0 : #define MAP_ELE_T fd_gui_peers_node_t
     156             : #define MAP_KEY_T fd_pubkey_t
     157           0 : #define MAP_KEY   contact_info.pubkey
     158           0 : #define MAP_IDX_T ulong
     159           0 : #define MAP_NEXT  pubkey_map.next
     160           0 : #define MAP_PREV  pubkey_map.prev
     161           0 : #define MAP_KEY_HASH(k,s) ((s) ^ fd_ulong_hash( (k)->ul[ 0 ] ))
     162           0 : #define MAP_KEY_EQ(k0,k1) (!memcmp((k0)->uc, (k1)->uc, 32UL))
     163             : #define MAP_OPTIMIZE_RANDOM_ACCESS_REMOVAL 1
     164             : #include "../../util/tmpl/fd_map_chain.c"
     165             : 
     166             : #define MAP_NAME  fd_gui_peers_node_sock_map
     167           0 : #define MAP_ELE_T fd_gui_peers_node_t
     168             : #define MAP_KEY_T fd_ip4_port_t
     169           0 : #define MAP_KEY   contact_info.sockets[ FD_CONTACT_INFO_SOCKET_GOSSIP ]
     170           0 : #define MAP_IDX_T ulong
     171           0 : #define MAP_NEXT  sock_map.next
     172           0 : #define MAP_PREV  sock_map.prev
     173           0 : #define MAP_KEY_HASH(k,s) ( fd_hash( (s), (k), sizeof(uint) + sizeof(ushort) ) )
     174           0 : #define MAP_KEY_EQ(k0,k1) ((k0)->l==(k1)->l )
     175             : #define MAP_OPTIMIZE_RANDOM_ACCESS_REMOVAL 1
     176             : #define MAP_MULTI 1
     177             : #include "../../util/tmpl/fd_map_chain.c"
     178             : 
     179           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; }
     180           0 : static int live_table_col_long_lt  ( void const * a, void const * b ) { return *(long *)a < *(long *)b;                                            }
     181           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);              }
     182             : 
     183             : #define LIVE_TABLE_NAME fd_gui_peers_live_table
     184           0 : #define LIVE_TABLE_TREAP treaps_live_table
     185           0 : #define LIVE_TABLE_SORT_KEYS sort_keys_live_table
     186           0 : #define LIVE_TABLE_DLIST dlist_live_table
     187           0 : #define LIVE_TABLE_COLUMN_CNT (6UL)
     188           0 : #define LIVE_TABLE_MAX_SORT_KEY_CNT FD_GUI_PEERS_CI_TABLE_SORT_KEY_CNT
     189             : #define LIVE_TABLE_ROW_T fd_gui_peers_node_t
     190           0 : #define LIVE_TABLE_COLUMNS LIVE_TABLE_COL_ARRAY( \
     191           0 :   LIVE_TABLE_COL_ENTRY( "Ingress Push", gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate,          live_table_col_long_lt   ), \
     192           0 :   LIVE_TABLE_COL_ENTRY( "Ingress Pull", gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate, live_table_col_long_lt   ), \
     193           0 :   LIVE_TABLE_COL_ENTRY( "Egress Push",  gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate,          live_table_col_long_lt   ), \
     194           0 :   LIVE_TABLE_COL_ENTRY( "Egress Pull",  gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate, live_table_col_long_lt   ), \
     195           0 :   LIVE_TABLE_COL_ENTRY( "Pubkey",       contact_info.pubkey,                                                  live_table_col_pubkey_lt ), \
     196           0 :   LIVE_TABLE_COL_ENTRY( "IP Addr",      contact_info.sockets[ FD_CONTACT_INFO_SOCKET_GOSSIP ].addr,           live_table_col_ipv4_lt   )  )
     197             : #include "fd_gui_live_table_tmpl.c"
     198             : 
     199           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 }, .dir = { -1, -1, -1, -1, -1, -1 } })
     200             : 
     201             : #define LIVE_TABLE_NAME fd_gui_peers_bandwidth_tracking
     202           0 : #define LIVE_TABLE_TREAP treaps_bandwidth_tracking
     203           0 : #define LIVE_TABLE_SORT_KEYS sort_keys_bandwidth_tracking
     204           0 : #define LIVE_TABLE_DLIST dlist_bandwidth_tracking
     205           0 : #define LIVE_TABLE_COLUMN_CNT (2UL)
     206           0 : #define LIVE_TABLE_MAX_SORT_KEY_CNT (2UL)
     207             : #define LIVE_TABLE_ROW_T fd_gui_peers_node_t
     208           0 : #define LIVE_TABLE_COLUMNS LIVE_TABLE_COL_ARRAY( \
     209           0 :   LIVE_TABLE_COL_ENTRY( "Ingress Total", gossvf_rx_sum.rate, live_table_col_long_lt ), \
     210           0 :   LIVE_TABLE_COL_ENTRY( "Egress Total",  gossip_tx_sum.rate, live_table_col_long_lt )  )
     211             : #include "fd_gui_live_table_tmpl.c"
     212             : 
     213           0 : #define FD_GUI_PEERS_BW_TRACKING_INGRESS_SORT_KEY ((fd_gui_peers_bandwidth_tracking_sort_key_t){ .col = { 0, 1 }, .dir = { -1, 0 } })
     214           0 : #define FD_GUI_PEERS_BW_TRACKING_EGRESS_SORT_KEY  ((fd_gui_peers_bandwidth_tracking_sort_key_t){ .col = { 0, 1 }, .dir = { 0, -1 } })
     215             : 
     216             : struct fd_gui_peers_ws_conn {
     217             :   int connected;
     218             :   long connected_time;
     219             : 
     220             :   ulong start_row;
     221             :   ulong row_cnt;
     222             :   fd_gui_peers_node_t viewport[ FD_GUI_PEERS_WS_VIEWPORT_MAX_SZ ];
     223             :   fd_gui_peers_live_table_sort_key_t sort_key[ 1 ];
     224             : };
     225             : typedef struct fd_gui_peers_ws_conn fd_gui_peers_ws_conn_t;
     226             : struct fd_gui_peers_ctx {
     227             :   long next_client_nanos; /* ns timestamp when we'll service the next ws client */
     228             :   long next_metric_rate_update_nanos; /* ns timestamp when we'll next update rate-of-change metrics */
     229             :   long next_gossip_stats_update_nanos; /* ns timestamp when we'll next broadcast out gossip stats message */
     230             : 
     231             :   fd_gui_peers_node_pubkey_map_t * node_pubkey_map;
     232             :   fd_gui_peers_node_sock_map_t  * node_sock_map;
     233             :   fd_gui_peers_live_table_t * live_table;
     234             :   fd_gui_peers_bandwidth_tracking_t * bw_tracking;
     235             : 
     236             :   fd_http_server_t * http;
     237             :   fd_topo_t * topo;
     238             : 
     239             :   ulong max_ws_conn_cnt;
     240             :   ulong open_ws_conn_cnt;
     241             :   ulong active_ws_conn_id;
     242             :   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 */
     243             : 
     244             :   fd_gui_peers_gossip_stats_t gossip_stats  [ 1 ];
     245             :   fd_gui_peers_node_t contact_info_table[ FD_CONTACT_INFO_TABLE_SIZE ];
     246             : };
     247             : typedef struct fd_gui_peers_ctx fd_gui_peers_ctx_t;
     248             : 
     249             : FD_PROTOTYPES_BEGIN
     250             : 
     251             : FD_FN_CONST ulong
     252             : fd_gui_peers_align( void );
     253             : 
     254             : FD_FN_CONST ulong
     255             : fd_gui_peers_footprint( ulong max_ws_conn_cnt );
     256             : 
     257             : void *
     258             : fd_gui_peers_new( void *             shmem,
     259             :                   fd_http_server_t * http,
     260             :                   fd_topo_t *        topo,
     261             :                   ulong              max_ws_conn_cnt,
     262             :                   long               now );
     263             : 
     264             : fd_gui_peers_ctx_t *
     265             : fd_gui_peers_join( void * shmem );
     266             : 
     267             : /* fd_gui_peers_handle_gossip_message_rx parses gossip messages from the
     268             :    net_gossvf link for ingress messages and the gossip_net link for
     269             :    egress messages and tracks per-peer, per-message bytes.  payload and
     270             :    payload_sz corresponds to the frag data after the network headers
     271             :    have been stripped. is_rx is true if the frag is an incoming message
     272             :    from the net_gossvf link. Otherwise, the frag is assumed to be an
     273             :    outgoing message from the gossip_net link. peer_sock is the ipv4
     274             :    address and port from the stripped net headers, which identifies the
     275             :    peers that sent or will receive the message.
     276             : 
     277             :    Note that gossip_net frags are unverified gossip messages from the
     278             :    network.  Messages that cannot be parsed are ignored. */
     279             : void
     280             : fd_gui_peers_handle_gossip_message( fd_gui_peers_ctx_t *  peers,
     281             :                                     uchar const *         payload,
     282             :                                     ulong                 payload_sz,
     283             :                                     fd_ip4_port_t const * peer_sock,
     284             :                                     int                   is_rx );
     285             : 
     286             : /* fd_gui_peers_handle_gossip_message_tx parses frags on the gossip_out
     287             :    link and uses the contact info update to build up the peer table.
     288             :    */
     289             : int
     290             : fd_gui_peers_handle_gossip_update( fd_gui_peers_ctx_t *               peers,
     291             :                                    fd_gossip_update_message_t const * update,
     292             :                                    long                               now );
     293             : 
     294             : /* fd_gui_peers_ws_message handles incoming websocket request payloads
     295             :    requesting peer-related responses.  ws_conn_id is the connection id
     296             :    of the requester.  data is a pointer to the start of the
     297             :    json-formatted request payload.  data_len is the length of the
     298             :    request payload. */
     299             : int
     300             : fd_gui_peers_ws_message( fd_gui_peers_ctx_t * peers,
     301             :                          ulong                ws_conn_id,
     302             :                          uchar const *        data,
     303             :                          ulong                data_len );
     304             : 
     305             : /* fd_gui_peers_ws_open is a callback which should be triggered when a
     306             :    new client opens a WebSocket connection.  ws_conn_id is the
     307             :    connection id of the new client.  now is a UNIX nanosecond timestamp
     308             :    for the current time. */
     309             : void
     310             : fd_gui_peers_ws_open( fd_gui_peers_ctx_t * peers, ulong ws_conn_id, long now );
     311             : 
     312             : /* fd_gui_peers_ws_close is a callback which should be triggered when an
     313             :    existing client closes their WebSocket connection.  ws_conn_id is the
     314             :    connection id of the client.*/
     315             : void
     316             : fd_gui_peers_ws_close( fd_gui_peers_ctx_t * peers, ulong ws_conn_id );
     317             : 
     318             : /* fd_gui_peers_poll should be called in a the tile's main spin loop to
     319             :    periodically update peers internal state as well as publish new
     320             :    Websocket messages to clients. now is a UNIX nanosecond timestamp for
     321             :    the current time. */
     322             : int
     323             : fd_gui_peers_poll( fd_gui_peers_ctx_t * peers, long now  );
     324             : 
     325             : FD_PROTOTYPES_END
     326             : 
     327             : #endif /* HEADER_fd_src_disco_gui_fd_gui_peers_h */

Generated by: LCOV version 1.14