diff --git a/src/app/firedancer/topology.c b/src/app/firedancer/topology.c index 05725d2f68..83c1e3a9a7 100644 --- a/src/app/firedancer/topology.c +++ b/src/app/firedancer/topology.c @@ -928,8 +928,9 @@ fd_topo_initialize( config_t * config ) { FOR(exec_tile_cnt) fd_topob_tile_in( topo, "gui", 0UL, "metric_in", "exec_replay", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED ); if( FD_LIKELY( snapshots_enabled ) ) { - /**/ fd_topob_tile_in ( topo, "gui", 0UL, "metric_in", "snapct_gui", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED ); - /**/ fd_topob_tile_in ( topo, "gui", 0UL, "metric_in", "snapin_gui", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED ); + /**/ fd_topob_tile_in( topo, "gui", 0UL, "metric_in", "snapct_gui", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED ); + /**/ fd_topob_tile_in( topo, "gui", 0UL, "metric_in", "snapin_gui", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED ); + fd_topob_tile_in( topo, "gui", 0UL, "metric_in", "snapin_manif", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED ); } } diff --git a/src/disco/gui/fd_gui_config_parse.h b/src/disco/gui/fd_gui_config_parse.h index a08cdc93fe..3826905d17 100644 --- a/src/disco/gui/fd_gui_config_parse.h +++ b/src/disco/gui/fd_gui_config_parse.h @@ -26,7 +26,7 @@ struct fd_gui_config_parse_info { char icon_uri[ FD_GUI_CONFIG_PARSE_VALIDATOR_INFO_ICON_URI_SZ + 1UL ]; char keybase_username[ FD_GUI_CONFIG_PARSE_VALIDATOR_INFO_KEYBASE_USERNAME_SZ + 1UL ]; - struct { ulong prev, next; } map; + struct { ulong next; } map; struct { ulong next; } pool; }; diff --git a/src/disco/gui/fd_gui_peers.c b/src/disco/gui/fd_gui_peers.c index 7c2d547556..9eb0b19e3a 100644 --- a/src/disco/gui/fd_gui_peers.c +++ b/src/disco/gui/fd_gui_peers.c @@ -18,7 +18,9 @@ fd_gui_peers_align( void ) { a = fd_ulong_max( a, fd_gui_peers_live_table_align() ); a = fd_ulong_max( a, fd_gui_peers_bandwidth_tracking_align() ); a = fd_ulong_max( a, fd_gui_peers_node_info_pool_align() ); + a = fd_ulong_max( a, fd_gui_peers_node_vote_pool_align() ); a = fd_ulong_max( a, fd_gui_peers_node_info_map_align() ); + a = fd_ulong_max( a, fd_gui_peers_node_vote_map_align() ); a = fd_ulong_max( a, fd_gui_peers_node_pubkey_map_align() ); a = fd_ulong_max( a, fd_gui_peers_node_sock_map_align() ); a = fd_ulong_max( a, alignof(fd_gui_peers_ws_conn_t) ); @@ -30,6 +32,7 @@ fd_gui_peers_align( void ) { FD_FN_CONST ulong fd_gui_peers_footprint( ulong max_ws_conn_cnt ) { ulong info_chain_cnt = fd_gui_peers_node_info_map_chain_cnt_est ( FD_CONTACT_INFO_TABLE_SIZE ); + ulong vote_chain_cnt = fd_gui_peers_node_vote_map_chain_cnt_est ( FD_RUNTIME_MAX_VOTE_ACCOUNTS ); ulong pubkey_chain_cnt = fd_gui_peers_node_pubkey_map_chain_cnt_est( FD_CONTACT_INFO_TABLE_SIZE ); ulong sock_chain_cnt = fd_gui_peers_node_sock_map_chain_cnt_est ( FD_CONTACT_INFO_TABLE_SIZE ); @@ -38,11 +41,13 @@ fd_gui_peers_footprint( ulong max_ws_conn_cnt ) { l = FD_LAYOUT_APPEND( l, fd_gui_peers_live_table_align(), fd_gui_peers_live_table_footprint ( FD_CONTACT_INFO_TABLE_SIZE ) ); l = FD_LAYOUT_APPEND( l, fd_gui_peers_bandwidth_tracking_align(), fd_gui_peers_bandwidth_tracking_footprint( FD_CONTACT_INFO_TABLE_SIZE ) ); l = FD_LAYOUT_APPEND( l, fd_gui_peers_node_info_pool_align(), fd_gui_peers_node_info_pool_footprint ( FD_CONTACT_INFO_TABLE_SIZE ) ); + l = FD_LAYOUT_APPEND( l, fd_gui_peers_node_vote_pool_align(), fd_gui_peers_node_vote_pool_footprint ( FD_RUNTIME_MAX_VOTE_ACCOUNTS ) ); l = FD_LAYOUT_APPEND( l, fd_gui_peers_node_info_map_align(), fd_gui_peers_node_info_map_footprint ( info_chain_cnt ) ); + l = FD_LAYOUT_APPEND( l, fd_gui_peers_node_vote_map_align(), fd_gui_peers_node_vote_map_footprint ( vote_chain_cnt ) ); l = FD_LAYOUT_APPEND( l, fd_gui_peers_node_pubkey_map_align(), fd_gui_peers_node_pubkey_map_footprint ( pubkey_chain_cnt ) ); l = FD_LAYOUT_APPEND( l, fd_gui_peers_node_sock_map_align(), fd_gui_peers_node_sock_map_footprint ( sock_chain_cnt ) ); l = FD_LAYOUT_APPEND( l, alignof(fd_gui_peers_ws_conn_t), max_ws_conn_cnt*sizeof(fd_gui_peers_ws_conn_t) ); - l = FD_LAYOUT_APPEND( l, alignof(fd_gui_ipinfo_node_t), sizeof(fd_gui_ipinfo_node_t)*IPINFO_MAX_NODES ); + l = FD_LAYOUT_APPEND( l, alignof(fd_gui_ipinfo_node_t), sizeof(fd_gui_ipinfo_node_t)*IPINFO_MAX_NODES ); return FD_LAYOUT_FINI( l, fd_gui_peers_align() ); } @@ -139,6 +144,7 @@ fd_gui_peers_new( void * shmem, } ulong info_chain_cnt = fd_gui_peers_node_info_map_chain_cnt_est ( FD_CONTACT_INFO_TABLE_SIZE ); + ulong vote_chain_cnt = fd_gui_peers_node_vote_map_chain_cnt_est ( FD_RUNTIME_MAX_VOTE_ACCOUNTS ); ulong pubkey_chain_cnt = fd_gui_peers_node_pubkey_map_chain_cnt_est( FD_CONTACT_INFO_TABLE_SIZE ); ulong sock_chain_cnt = fd_gui_peers_node_sock_map_chain_cnt_est ( FD_CONTACT_INFO_TABLE_SIZE ); @@ -147,7 +153,9 @@ fd_gui_peers_new( void * shmem, void * _live_table = FD_SCRATCH_ALLOC_APPEND( l, fd_gui_peers_live_table_align(), fd_gui_peers_live_table_footprint ( FD_CONTACT_INFO_TABLE_SIZE ) ); void * _bw_tracking = FD_SCRATCH_ALLOC_APPEND( l, fd_gui_peers_bandwidth_tracking_align(), fd_gui_peers_bandwidth_tracking_footprint( FD_CONTACT_INFO_TABLE_SIZE ) ); void * _info_pool = FD_SCRATCH_ALLOC_APPEND( l, fd_gui_peers_node_info_pool_align(), fd_gui_peers_node_info_pool_footprint ( FD_CONTACT_INFO_TABLE_SIZE ) ); + void * _vote_pool = FD_SCRATCH_ALLOC_APPEND( l, fd_gui_peers_node_vote_pool_align(), fd_gui_peers_node_vote_pool_footprint ( FD_RUNTIME_MAX_VOTE_ACCOUNTS ) ); void * _info_map = FD_SCRATCH_ALLOC_APPEND( l, fd_gui_peers_node_info_map_align(), fd_gui_peers_node_info_map_footprint ( info_chain_cnt ) ); + void * _vote_map = FD_SCRATCH_ALLOC_APPEND( l, fd_gui_peers_node_vote_map_align(), fd_gui_peers_node_vote_map_footprint ( vote_chain_cnt ) ); void * _pubkey_map = FD_SCRATCH_ALLOC_APPEND( l, fd_gui_peers_node_pubkey_map_align(), fd_gui_peers_node_pubkey_map_footprint ( pubkey_chain_cnt ) ); void * _sock_map = FD_SCRATCH_ALLOC_APPEND( l, fd_gui_peers_node_sock_map_align(), fd_gui_peers_node_sock_map_footprint ( sock_chain_cnt ) ); ctx->client_viewports = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_gui_peers_ws_conn_t), max_ws_conn_cnt*sizeof(fd_gui_peers_ws_conn_t) ); @@ -178,7 +186,9 @@ fd_gui_peers_new( void * shmem, fd_gui_peers_bandwidth_tracking_seed( ctx->contact_info_table, FD_CONTACT_INFO_TABLE_SIZE, 42UL ); ctx->node_info_pool = fd_gui_peers_node_info_pool_join ( fd_gui_peers_node_info_pool_new ( _info_pool, FD_CONTACT_INFO_TABLE_SIZE ) ); + ctx->node_vote_pool = fd_gui_peers_node_vote_pool_join ( fd_gui_peers_node_vote_pool_new ( _vote_pool, FD_RUNTIME_MAX_VOTE_ACCOUNTS ) ); ctx->node_info_map = fd_gui_peers_node_info_map_join ( fd_gui_peers_node_info_map_new ( _info_map, info_chain_cnt, 42UL ) ); + ctx->node_vote_map = fd_gui_peers_node_vote_map_join ( fd_gui_peers_node_vote_map_new ( _vote_map, vote_chain_cnt, 42UL ) ); ctx->node_pubkey_map = fd_gui_peers_node_pubkey_map_join( fd_gui_peers_node_pubkey_map_new( _pubkey_map, pubkey_chain_cnt, 42UL ) ); ctx->node_sock_map = fd_gui_peers_node_sock_map_join ( fd_gui_peers_node_sock_map_new ( _sock_map, sock_chain_cnt, 42UL ) ); @@ -626,8 +636,9 @@ fd_gui_peers_handle_gossip_update( fd_gui_peers_ctx_t * peers, memset( &peer->gossip_tx, 0, sizeof(peer->gossip_tx) ); memset( &peer->gossvf_rx_sum, 0, sizeof(peer->gossvf_rx_sum) ); memset( &peer->gossip_tx_sum, 0, sizeof(peer->gossip_tx_sum) ); - peer->has_vote_info = 0; - peer->stake = ULONG_MAX; + + fd_gui_peers_vote_t * vote = fd_gui_peers_node_vote_map_ele_query( peers->node_vote_map, &update->contact_info.contact_info->pubkey, NULL, peers->node_vote_pool ); + peer->stake = FD_LIKELY( vote ) ? vote->stake : ULONG_MAX; fd_gui_config_parse_info_t * info = fd_gui_peers_node_info_map_ele_query( peers->node_info_map, &update->contact_info.contact_info->pubkey, NULL, peers->node_info_pool ); if( FD_LIKELY( info ) ) fd_memcpy( peer->name, info->name, sizeof(info->name) ); @@ -722,9 +733,17 @@ void fd_gui_peers_handle_vote_update( fd_gui_peers_ctx_t * peers, fd_gui_peers_vote_t * votes, ulong vote_cnt, - long now, fd_pubkey_t * identity ) { - (void)now; + if( FD_UNLIKELY( !fd_gui_peers_node_vote_pool_free( peers->node_vote_pool ) ) ) { + FD_LOG_WARNING(( "pool mem exhausted" )); + return; + } + + if( FD_UNLIKELY( vote_cnt>FD_RUNTIME_MAX_VOTE_ACCOUNTS ) ) { + FD_LOG_WARNING(( "max vote accounts exceeded" )); + return; + } + fd_gui_peers_vote_t * votes_sorted = votes; fd_gui_peers_vote_t * votes_scratch = peers->votes_scratch; fd_memcpy( votes_sorted, votes, vote_cnt*sizeof(fd_gui_peers_vote_t) ); @@ -785,37 +804,47 @@ fd_gui_peers_handle_vote_update( fd_gui_peers_ctx_t * peers, fd_http_server_ws_broadcast( peers->http ); } - ulong peer_idx = fd_gui_peers_node_pubkey_map_idx_query( peers->node_pubkey_map, &votes_sorted[ i ].node_account, ULONG_MAX, peers->contact_info_table ); - if( FD_UNLIKELY( peer_idx==ULONG_MAX ) ) continue; /* peer not on gossip */ - - fd_gui_peers_node_t * peer = peers->contact_info_table + peer_idx; - /* TODO: we only publish updates when stake changes, otherwise we'd have to republish for every peer every slot, which ends up being too much bandwidth because we republish all the peer info. Ideally, we decouple the vote updates from the reset of the peer info which would let us make updates quickly. */ - int is_delinquent = ((long)last_vote_slot_p67 - (long)votes_sorted[ i ].last_vote_slot) > 150L; - int vote_eq = peer->has_vote_info - && !memcmp( peer->vote_account.uc, votes_sorted[ i ].vote_account.uc, sizeof(fd_pubkey_t) ) - && peer->stake ==votes_sorted[ i ].stake - // && peer->last_vote_slot ==votes_sorted[ i ].last_vote_slot - // && peer->last_vote_timestamp ==votes_sorted[ i ].last_vote_timestamp - // && peer->epoch_credits ==votes_sorted[ i ].epoch_credits - && peer->commission ==votes_sorted[ i ].commission - && peer->epoch ==votes_sorted[ i ].epoch - && peer->delinquent ==is_delinquent; + votes_sorted[ i ].delinquent = ((long)last_vote_slot_p67 - (long)votes_sorted[ i ].last_vote_slot) > 150L; + + fd_gui_peers_vote_t * vote = fd_gui_peers_node_vote_map_ele_query( peers->node_vote_map, &votes_sorted[ i ].node_account, NULL, peers->node_vote_pool ); + + int vote_eq = !!vote + && !memcmp( vote->vote_account.uc, votes_sorted[ i ].vote_account.uc, sizeof(fd_pubkey_t) ) + && vote->stake ==votes_sorted[ i ].stake + // && vote->last_vote_slot ==votes_sorted[ i ].last_vote_slot + // && vote->last_vote_timestamp ==votes_sorted[ i ].last_vote_timestamp + // && vote->epoch_credits ==votes_sorted[ i ].epoch_credits + // && vote->commission ==votes_sorted[ i ].commission + && vote->epoch ==votes_sorted[ i ].epoch + && vote->delinquent ==votes_sorted[ i ].delinquent; if( FD_LIKELY( vote_eq ) ) continue; /* nop */ - peer->has_vote_info = 1; - peer->vote_account = votes_sorted[ i ].vote_account; - peer->last_vote_slot = votes_sorted[ i ].last_vote_slot; - peer->last_vote_timestamp = votes_sorted[ i ].last_vote_timestamp; - peer->epoch_credits = votes_sorted[ i ].epoch_credits; - peer->commission = votes_sorted[ i ].commission; - peer->epoch = votes_sorted[ i ].epoch; - peer->delinquent = is_delinquent; + if ( FD_UNLIKELY( !vote ) ) { + vote = fd_gui_peers_node_vote_pool_ele_acquire( peers->node_vote_pool ); + fd_memcpy( &vote->node_account, &votes_sorted[ i ].node_account, sizeof(fd_pubkey_t) ); + fd_gui_peers_node_vote_map_ele_insert( peers->node_vote_map, vote, peers->node_vote_pool ); + } + + /* update map entry */ + fd_memcpy( vote->vote_account.uc, votes_sorted[ i ].vote_account.uc, sizeof(fd_pubkey_t) ); + vote->stake = votes_sorted[ i ].stake; + vote->last_vote_slot = votes_sorted[ i ].last_vote_slot; + vote->last_vote_timestamp = votes_sorted[ i ].last_vote_timestamp; + vote->epoch_credits = votes_sorted[ i ].epoch_credits; + vote->commission = votes_sorted[ i ].commission; + vote->epoch = votes_sorted[ i ].epoch; + vote->delinquent = votes_sorted[ i ].delinquent; + + ulong peer_idx = fd_gui_peers_node_pubkey_map_idx_query( peers->node_pubkey_map, &votes_sorted[ i ].node_account, ULONG_MAX, peers->contact_info_table ); + if( FD_UNLIKELY( peer_idx==ULONG_MAX ) ) continue; /* peer not on gossip */ + + fd_gui_peers_node_t * peer = peers->contact_info_table + peer_idx; if( FD_UNLIKELY( peer->stake!=votes_sorted[ i ].stake ) ) { fd_gui_peers_live_table_idx_remove( peers->live_table, peer_idx, peers->contact_info_table ); diff --git a/src/disco/gui/fd_gui_peers.h b/src/disco/gui/fd_gui_peers.h index 5f1d6f5325..4440c1135e 100644 --- a/src/disco/gui/fd_gui_peers.h +++ b/src/disco/gui/fd_gui_peers.h @@ -114,6 +114,10 @@ struct fd_gui_peers_vote { uchar commission; ulong epoch; ulong epoch_credits; + int delinquent; + + struct { ulong next; } map; + struct { ulong next; } pool; }; typedef struct fd_gui_peers_vote fd_gui_peers_vote_t; @@ -129,17 +133,8 @@ struct fd_gui_peers_node { fd_gui_peers_metric_rate_t gossvf_rx_sum; /* sum of gossvf_rx */ fd_gui_peers_metric_rate_t gossip_tx_sum; /* sum of gossip_tx */ - int has_vote_info; - fd_pubkey_t vote_account; - ulong stake; /* if has_vote_info==0 then stake==ULONG_MAX */ - ulong last_vote_slot; - long last_vote_timestamp; - uchar commission; - ulong epoch; - ulong epoch_credits; - uchar country_code_idx; - int delinquent; - + ulong stake; /* default ULONG_MAX */ + uchar country_code_idx; struct { ulong next; ulong prev; @@ -233,16 +228,29 @@ typedef struct fd_gui_peers_gossip_stats fd_gui_peers_gossip_stats_t; #define POOL_NEXT pool.next #include "../../util/tmpl/fd_pool.c" +#define POOL_NAME fd_gui_peers_node_vote_pool +#define POOL_T fd_gui_peers_vote_t +#define POOL_NEXT pool.next +#include "../../util/tmpl/fd_pool.c" + #define MAP_NAME fd_gui_peers_node_info_map #define MAP_ELE_T fd_gui_config_parse_info_t #define MAP_KEY_T fd_pubkey_t #define MAP_KEY pubkey #define MAP_IDX_T ulong #define MAP_NEXT map.next -#define MAP_PREV map.prev #define MAP_KEY_HASH(k,s) (fd_hash( (s), (k)->uc, sizeof(fd_pubkey_t) )) #define MAP_KEY_EQ(k0,k1) (!memcmp((k0)->uc, (k1)->uc, 32UL)) -#define MAP_OPTIMIZE_RANDOM_ACCESS_REMOVAL 1 +#include "../../util/tmpl/fd_map_chain.c" + +#define MAP_NAME fd_gui_peers_node_vote_map +#define MAP_ELE_T fd_gui_peers_vote_t +#define MAP_KEY_T fd_pubkey_t +#define MAP_KEY node_account +#define MAP_IDX_T ulong +#define MAP_NEXT map.next +#define MAP_KEY_HASH(k,s) (fd_hash( (s), (k)->uc, sizeof(fd_pubkey_t) )) +#define MAP_KEY_EQ(k0,k1) (!memcmp((k0)->uc, (k1)->uc, 32UL)) #include "../../util/tmpl/fd_map_chain.c" #define MAP_NAME fd_gui_peers_node_pubkey_map @@ -331,7 +339,9 @@ struct fd_gui_peers_ctx { long next_gossip_stats_update_nanos; /* ns timestamp when we'll next broadcast out gossip stats message */ fd_gui_config_parse_info_t * node_info_pool; + fd_gui_peers_vote_t * node_vote_pool; fd_gui_peers_node_info_map_t * node_info_map; + fd_gui_peers_node_vote_map_t * node_vote_map; fd_gui_peers_node_pubkey_map_t * node_pubkey_map; fd_gui_peers_node_sock_map_t * node_sock_map; fd_gui_peers_live_table_t * live_table; @@ -410,7 +420,6 @@ void fd_gui_peers_handle_vote_update( fd_gui_peers_ctx_t * peers, fd_gui_peers_vote_t * votes, ulong vote_cnt, - long now, fd_pubkey_t * identity ); void diff --git a/src/disco/gui/fd_gui_printf.c b/src/disco/gui/fd_gui_printf.c index 79c33383e0..1ca0d567e9 100644 --- a/src/disco/gui/fd_gui_printf.c +++ b/src/disco/gui/fd_gui_printf.c @@ -1162,21 +1162,22 @@ peers_printf_node( fd_gui_peers_ctx_t * peers, jsonp_close_object( peers->http ); - if( FD_LIKELY( !peer->has_vote_info ) ) { + fd_gui_peers_vote_t * vote = fd_gui_peers_node_vote_map_ele_query( peers->node_vote_map, &peer->contact_info.pubkey, NULL, peers->node_vote_pool ); + if( FD_LIKELY( !vote ) ) { jsonp_open_array( peers->http, "vote" ); jsonp_close_array( peers->http ); } else { jsonp_open_array( peers->http, "vote" ); jsonp_open_object( peers->http, NULL ); char vote_account_base58[ FD_BASE58_ENCODED_32_SZ ]; - fd_base58_encode_32( peer->vote_account.uc, NULL, vote_account_base58 ); + fd_base58_encode_32( vote->vote_account.uc, NULL, vote_account_base58 ); jsonp_string( peers->http, "vote_account", vote_account_base58 ); - jsonp_ulong_as_str( peers->http, "activated_stake", peer->stake ); - jsonp_ulong( peers->http, "last_vote", peer->last_vote_slot ); - jsonp_ulong( peers->http, "epoch_credits", peer->epoch_credits ); - jsonp_ulong( peers->http, "commission", peer->commission ); + jsonp_ulong_as_str( peers->http, "activated_stake", vote->stake ); + jsonp_ulong( peers->http, "last_vote", vote->last_vote_slot ); + jsonp_ulong( peers->http, "epoch_credits", vote->epoch_credits ); + jsonp_ulong( peers->http, "commission", vote->commission ); jsonp_ulong( peers->http, "root_slot", 0UL ); - jsonp_bool( peers->http, "delinquent", peer->delinquent ); + jsonp_bool( peers->http, "delinquent", vote->delinquent ); jsonp_close_object( peers->http ); jsonp_close_array( peers->http ); } diff --git a/src/disco/gui/fd_gui_tile.c b/src/disco/gui/fd_gui_tile.c index d5618aa225..05e2dc9152 100644 --- a/src/disco/gui/fd_gui_tile.c +++ b/src/disco/gui/fd_gui_tile.c @@ -31,6 +31,7 @@ static fd_http_static_file_t * STATIC_FILES; #include "../../waltz/http/fd_http_server_private.h" #include "../../ballet/json/cJSON_alloc.h" #include "../../util/clock/fd_clock.h" +#include "../../discof/restore/utils/fd_ssmsg.h" #include "../../discof/repair/fd_repair.h" #include "../../discof/replay/fd_replay_tile.h" #include "../../util/pod/fd_pod_format.h" @@ -55,6 +56,7 @@ static fd_http_static_file_t * STATIC_FILES; #define IN_KIND_GENESI_OUT (14UL) /* firedancer only */ #define IN_KIND_SNAPIN (15UL) /* firedancer only */ #define IN_KIND_EXEC_REPLAY (16UL) /* firedancer only */ +#define IN_KIND_SNAPIN_MANIF (17UL) /* firedancer only */ FD_IMPORT_BINARY( firedancer_svg, "book/public/fire.svg" ); @@ -233,6 +235,11 @@ before_frag( fd_gui_ctx_t * ctx, /* Ignore "done draining banks" signal from pack->poh */ if( FD_LIKELY( ctx->in_kind[ in_idx ]==IN_KIND_PACK_POH && sig==ULONG_MAX ) ) return 1; + + if( FD_LIKELY( ctx->in_kind[ in_idx ]==IN_KIND_SNAPIN_MANIF ) ) { + ulong msg = fd_ssmsg_sig_message( sig ); + if( FD_UNLIKELY( msg!=FD_SSMSG_MANIFEST_FULL && msg!=FD_SSMSG_MANIFEST_INCREMENTAL ) ) return 1; + } return 0; } @@ -415,7 +422,7 @@ after_frag( fd_gui_ctx_t * ctx, fd_stem_publish( stem, ctx->replay_out->idx, replay->bank_idx, 0UL, 0UL, 0UL, 0UL, 0UL ); /* update vote info */ - fd_gui_peers_handle_vote_update( ctx->peers, ctx->peers->votes, vote_count, fd_clock_now( ctx->clock ), ctx->gui->summary.identity_key ); + fd_gui_peers_handle_vote_update( ctx->peers, ctx->peers->votes, vote_count, ctx->gui->summary.identity_key ); /* update slot data */ fd_gui_handle_replay_update( ctx->gui, &slot_completed, &replay->block_hash, ctx->peers->slot_voted, replay->storage_slot, replay->identity_balance, fd_clock_now( ctx->clock ) ); @@ -435,6 +442,25 @@ after_frag( fd_gui_ctx_t * ctx, fd_gui_handle_leader_schedule( ctx->gui, leader_schedule, fd_clock_now( ctx->clock ) ); break; } + case IN_KIND_SNAPIN_MANIF: { + fd_snapshot_manifest_t * manifest = (fd_snapshot_manifest_t *)src; + + ulong vote_count = fd_ulong_min( FD_RUNTIME_MAX_VOTE_ACCOUNTS, manifest->vote_accounts_len ); + for( ulong i=0UL; ipeers->votes[ i ].vote_account.uc, manifest->vote_accounts[ i ].vote_account_pubkey, sizeof(fd_pubkey_t) ); + fd_memcpy( ctx->peers->votes[ i ].node_account.uc, manifest->vote_accounts[ i ].node_account_pubkey, sizeof(fd_pubkey_t) ); + ctx->peers->votes[ i ].stake = manifest->vote_accounts[ i ].stake; + ctx->peers->votes[ i ].last_vote_slot = manifest->vote_accounts[ i ].last_slot; + ctx->peers->votes[ i ].last_vote_timestamp = manifest->vote_accounts[ i ].last_timestamp; + ctx->peers->votes[ i ].commission = manifest->vote_accounts[ i ].commission; + ctx->peers->votes[ i ].epoch = fd_ulong_if( !manifest->vote_accounts[ i ].epoch_credits_history_len, ULONG_MAX, manifest->vote_accounts[ i ].epoch_credits[ 0 ].epoch ); + ctx->peers->votes[ i ].epoch_credits = fd_ulong_if( !manifest->vote_accounts[ i ].epoch_credits_history_len, ULONG_MAX, manifest->vote_accounts[ i ].epoch_credits[ 0 ].credits ); + } + + fd_gui_peers_handle_vote_update( ctx->peers, ctx->peers->votes, vote_count, ctx->gui->summary.identity_key ); + + break; + } case IN_KIND_SNAPIN: { FD_TEST( ctx->is_full_client ); fd_gui_peers_handle_config_account( ctx->peers, src, sz ); @@ -751,11 +777,11 @@ unprivileged_init( fd_topo_t * topo, fd_http_server_params_t http_param = derive_http_params( tile ); FD_SCRATCH_ALLOC_INIT( l, scratch ); - fd_gui_ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_gui_ctx_t ), sizeof( fd_gui_ctx_t ) ); - FD_SCRATCH_ALLOC_APPEND( l, fd_http_server_align(), fd_http_server_footprint( http_param ) ); - void * _peers = FD_SCRATCH_ALLOC_APPEND( l, fd_gui_peers_align(), fd_gui_peers_footprint( http_param.max_ws_connection_cnt) ); - void * _gui = FD_SCRATCH_ALLOC_APPEND( l, fd_gui_align(), fd_gui_footprint() ); - void * _alloc = FD_SCRATCH_ALLOC_APPEND( l, fd_alloc_align(), fd_alloc_footprint() ); + fd_gui_ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_gui_ctx_t ), sizeof( fd_gui_ctx_t ) ); + FD_SCRATCH_ALLOC_APPEND( l, fd_http_server_align(), fd_http_server_footprint( http_param ) ); + void * _peers = FD_SCRATCH_ALLOC_APPEND( l, fd_gui_peers_align(), fd_gui_peers_footprint( http_param.max_ws_connection_cnt ) ); + void * _gui = FD_SCRATCH_ALLOC_APPEND( l, fd_gui_align(), fd_gui_footprint() ); + void * _alloc = FD_SCRATCH_ALLOC_APPEND( l, fd_alloc_align(), fd_alloc_footprint() ); ctx->is_full_client = ULONG_MAX!=fd_topo_find_tile( topo, "repair", 0UL ); ctx->snapshots_enabled = ULONG_MAX!=fd_topo_find_tile( topo, "snapct", 0UL ); @@ -813,6 +839,7 @@ unprivileged_init( fd_topo_t * topo, else if( FD_LIKELY( !strcmp( link->name, "replay_stake" ) ) ) ctx->in_kind[ i ] = IN_KIND_REPLAY_STAKE; /* full client only */ else if( FD_LIKELY( !strcmp( link->name, "genesi_out" ) ) ) ctx->in_kind[ i ] = IN_KIND_GENESI_OUT; /* full client only */ else if( FD_LIKELY( !strcmp( link->name, "snapin_gui" ) ) ) ctx->in_kind[ i ] = IN_KIND_SNAPIN; /* full client only */ + else if( FD_LIKELY( !strcmp( link->name, "snapin_manif" ) ) ) ctx->in_kind[ i ] = IN_KIND_SNAPIN_MANIF; /* full client only */ else if( FD_LIKELY( !strcmp( link->name, "exec_replay" ) ) ) ctx->in_kind[ i ] = IN_KIND_EXEC_REPLAY; /* full client only */ else FD_LOG_ERR(( "gui tile has unexpected input link %lu %s", i, link->name ));