From 8e1d702a4a39c66815a9fddaa80776a05b3b8248 Mon Sep 17 00:00:00 2001 From: Yunhao Zhang Date: Fri, 6 Sep 2024 16:58:39 +0000 Subject: [PATCH] Add some code for wen-restart --- src/app/fdctl/config.h | 1 + src/app/fdctl/config_parse.c | 1 + src/app/fdctl/run/tiles/fd_gossip.c | 171 +++-- src/app/fdctl/run/tiles/fd_replay.c | 160 ++++- src/app/fdctl/run/tiles/fd_store_int.c | 8 +- src/app/fdctl/run/topos/fd_firedancer.c | 15 +- src/disco/restart/Local.mk | 4 + src/disco/restart/fd_restart.c | 147 +++++ src/disco/restart/fd_restart.h | 100 +++ src/disco/topo/fd_topo.h | 1 + src/flamenco/gossip/fd_gossip.c | 18 +- src/flamenco/runtime/fd_blockstore.h | 1 + src/flamenco/types/fd_type_names.c | 10 +- src/flamenco/types/fd_types.c | 825 ++++++++++++++++++++++++ src/flamenco/types/fd_types.h | 252 ++++++++ src/flamenco/types/fd_types.json | 72 ++- 16 files changed, 1739 insertions(+), 47 deletions(-) create mode 100644 src/disco/restart/Local.mk create mode 100644 src/disco/restart/fd_restart.c create mode 100644 src/disco/restart/fd_restart.h diff --git a/src/app/fdctl/config.h b/src/app/fdctl/config.h index 2e8b6d9ca7..0300ac71ff 100644 --- a/src/app/fdctl/config.h +++ b/src/app/fdctl/config.h @@ -273,6 +273,7 @@ typedef struct { char status_cache[ PATH_MAX ]; ulong tpool_thread_count; char cluster_version[ 32 ]; + int in_wen_restart; } replay; struct { diff --git a/src/app/fdctl/config_parse.c b/src/app/fdctl/config_parse.c index c7cc16116a..7b32be53d3 100644 --- a/src/app/fdctl/config_parse.c +++ b/src/app/fdctl/config_parse.c @@ -367,6 +367,7 @@ fdctl_pod_to_cfg( config_t * config, CFG_POP ( cstr, tiles.replay.status_cache ); CFG_POP ( ulong, tiles.replay.tpool_thread_count ); CFG_POP ( cstr, tiles.replay.cluster_version ); + CFG_POP ( bool, tiles.replay.in_wen_restart ); CFG_POP ( cstr, tiles.store_int.blockstore_restore ); CFG_POP ( cstr, tiles.store_int.slots_pending ); diff --git a/src/app/fdctl/run/tiles/fd_gossip.c b/src/app/fdctl/run/tiles/fd_gossip.c index d137fdad24..dc46992505 100644 --- a/src/app/fdctl/run/tiles/fd_gossip.c +++ b/src/app/fdctl/run/tiles/fd_gossip.c @@ -17,6 +17,7 @@ #include "../../../../disco/store/util.h" #include "../../../../flamenco/gossip/fd_gossip.h" #include "../../../../flamenco/runtime/fd_system_ids.h" +#include "../../../../disco/restart/fd_restart.h" #include "../../../../util/fd_util.h" #include "../../../../util/net/fd_eth.h" #include "../../../../util/net/fd_ip4.h" @@ -28,7 +29,8 @@ #define NET_IN_IDX 0 #define VOTER_IN_IDX 1 -#define SIGN_IN_IDX 2 +#define REPLAY_IN_IDX 2 +#define SIGN_IN_IDX 3 #define NET_OUT_IDX 0 #define SHRED_OUT_IDX 1 @@ -36,7 +38,8 @@ #define DEDUP_OUT_IDX 3 #define SIGN_OUT_IDX 4 #define VOTER_OUT_IDX 5 -#define EQVOC_OUT_IDX 6 +#define REPLAY_OUT_IDX 6 +#define EQVOC_OUT_IDX 7 #define CONTACT_INFO_PUBLISH_TIME_NS ((long)5e9) @@ -49,21 +52,6 @@ static volatile ulong * fd_shred_version; -static int -fd_pubkey_eq( fd_pubkey_t const * key1, fd_pubkey_t const * key2 ) { - return memcmp( key1->key, key2->key, sizeof(fd_pubkey_t) ) == 0; -} - -static ulong -fd_pubkey_hash( fd_pubkey_t const * key, ulong seed ) { - return fd_hash( seed, key->key, sizeof(fd_pubkey_t) ); -} - -static void -fd_pubkey_copy( fd_pubkey_t * keyd, fd_pubkey_t const * keys ) { - memcpy( keyd->key, keys->key, sizeof(fd_pubkey_t) ); -} - /* Contact info table */ #define MAP_NAME fd_contact_info_table #define MAP_KEY_T fd_pubkey_t @@ -132,10 +120,24 @@ struct fd_gossip_tile_ctx { ulong duplicate_shred_out_wmark; ulong duplicate_shred_out_chunk; + fd_wksp_t * voter_in_mem; + ulong voter_in_chunk0; + ulong voter_in_wmark; + fd_wksp_t * replay_in_mem; ulong replay_in_chunk0; ulong replay_in_wmark; + fd_frag_meta_t * replay_out_mcache; + ulong * replay_out_sync; + ulong replay_out_depth; + ulong replay_out_seq; + + fd_wksp_t * replay_out_mem; + ulong replay_out_chunk0; + ulong replay_out_wmark; + ulong replay_out_chunk; + fd_wksp_t * wksp; fd_gossip_peer_addr_t gossip_my_addr; fd_gossip_peer_addr_t tvu_my_addr; @@ -176,6 +178,10 @@ struct fd_gossip_tile_ctx { ulong replay_vote_txn_sz; uchar replay_vote_txn [ FD_TXN_MTU ]; + + ulong restart_msg_sz; + long restart_last_voted_fork_push_time; + uchar restart_msg [ LAST_VOTED_FORK_MAX_MSG_BYTES ]; }; typedef struct fd_gossip_tile_ctx fd_gossip_tile_ctx_t; @@ -287,7 +293,43 @@ static void gossip_deliver_fun( fd_crds_data_t * data, void * arg ) { fd_gossip_tile_ctx_t * ctx = (fd_gossip_tile_ctx_t *)arg; - if( fd_crds_data_is_vote( data ) ) { + if( fd_crds_data_is_restart_last_voted_fork_slots( data ) ) { + if( data->inner.restart_last_voted_fork_slots.offsets.discriminant!=fd_restart_slots_offsets_enum_raw_offsets ) { + FD_LOG_WARNING(( "Decoding RunLengthEncoding offsets is not implemented yet" )); + } + + ulong struct_len = sizeof( fd_gossip_restart_last_voted_fork_slots_t ); + ulong bitmap_len = data->inner.restart_last_voted_fork_slots.offsets.inner.raw_offsets.offsets.bits.bits_len; + if( FD_UNLIKELY( bitmap_len>LAST_VOTED_FORK_MAX_BITMAP_BYTES ) ) { + FD_LOG_WARNING(( "Ignore an invalid gossip message with bitmap length %lu, greater than %lu", bitmap_len, LAST_VOTED_FORK_MAX_BITMAP_BYTES )); + return; + } + + uchar * last_vote_msg_ = fd_chunk_to_laddr( ctx->replay_out_mem, ctx->replay_out_chunk ); + FD_STORE( uint, last_vote_msg_, fd_crds_data_enum_restart_last_voted_fork_slots ); + last_vote_msg_ += sizeof(uint); + + fd_memcpy( last_vote_msg_, &data->inner.restart_last_voted_fork_slots, struct_len ); + fd_memcpy( last_vote_msg_ + struct_len, + data->inner.restart_last_voted_fork_slots.offsets.inner.raw_offsets.offsets.bits.bits, + bitmap_len ); + fd_mcache_publish( ctx->replay_out_mcache, ctx->replay_out_depth, ctx->replay_out_seq, 1UL, ctx->replay_out_chunk, + sizeof(uint) + struct_len + bitmap_len, 0UL, 0, 0 ); + ctx->replay_out_seq = fd_seq_inc( ctx->replay_out_seq, 1UL ); + ctx->replay_out_chunk = fd_dcache_compact_next( ctx->replay_out_chunk, struct_len + bitmap_len, ctx->replay_out_chunk0, ctx->replay_out_wmark ); + } else if( fd_crds_data_is_restart_heaviest_fork( data ) ) { + uchar * heaviest_fork_msg_ = fd_chunk_to_laddr( ctx->replay_out_mem, ctx->replay_out_chunk ); + FD_STORE( uint, heaviest_fork_msg_, fd_crds_data_enum_restart_heaviest_fork ); + heaviest_fork_msg_ += sizeof(uint); + + fd_memcpy( heaviest_fork_msg_, + &data->inner.restart_heaviest_fork, + sizeof(fd_gossip_restart_heaviest_fork_t) ); + fd_mcache_publish( ctx->replay_out_mcache, ctx->replay_out_depth, ctx->replay_out_seq, 1UL, ctx->replay_out_chunk, + sizeof(uint) + sizeof(fd_gossip_restart_heaviest_fork_t), 0UL, 0, 0 ); + ctx->replay_out_seq = fd_seq_inc( ctx->replay_out_seq, 1UL ); + ctx->replay_out_chunk = fd_dcache_compact_next( ctx->replay_out_chunk, sizeof(uint) + sizeof(fd_gossip_restart_heaviest_fork_t), ctx->replay_out_chunk0, ctx->replay_out_wmark ); + } else if( fd_crds_data_is_vote( data ) ) { fd_gossip_vote_t const * gossip_vote = &data->inner.vote; if( verify_vote_txn( gossip_vote ) != 0 ) { return; @@ -369,7 +411,7 @@ before_frag( fd_gossip_tile_ctx_t * ctx, (void)ctx; (void)seq; - return in_idx != VOTER_IN_IDX && fd_disco_netmux_sig_proto( sig ) != DST_PROTO_GOSSIP; + return in_idx != VOTER_IN_IDX && in_idx != REPLAY_IN_IDX && fd_disco_netmux_sig_proto( sig ) != DST_PROTO_GOSSIP; } static inline void @@ -382,13 +424,22 @@ during_frag( fd_gossip_tile_ctx_t * ctx, (void)seq; (void)sig; - if ( in_idx == VOTER_IN_IDX ) { - if( FD_UNLIKELY( chunkreplay_in_chunk0 || chunk>ctx->replay_in_wmark || sz>USHORT_MAX ) ) { + if( in_idx == REPLAY_IN_IDX ) { + if( FD_UNLIKELY( chunkreplay_in_chunk0 || chunk>ctx->replay_in_wmark || sz>LAST_VOTED_FORK_MAX_MSG_BYTES ) ) { FD_LOG_ERR(( "chunk %lu %lu corrupt, not in range [%lu,%lu]", chunk, sz, ctx->replay_in_chunk0, ctx->replay_in_wmark )); } + fd_memcpy( ctx->restart_msg, fd_chunk_to_laddr( ctx->replay_in_mem, chunk ), sz ); + ctx->restart_msg_sz = sz; + return; + } + + if ( in_idx == VOTER_IN_IDX ) { + if( FD_UNLIKELY( chunkvoter_in_chunk0 || chunk>ctx->voter_in_wmark || sz>USHORT_MAX ) ) { + FD_LOG_ERR(( "chunk %lu %lu corrupt, not in range [%lu,%lu]", chunk, sz, ctx->voter_in_chunk0, ctx->voter_in_wmark )); + } ctx->replay_vote_txn_sz = sz; - memcpy( ctx->replay_vote_txn, fd_chunk_to_laddr( ctx->replay_in_mem, chunk ), sz ); + memcpy( ctx->replay_vote_txn, fd_chunk_to_laddr( ctx->voter_in_mem, chunk ), sz ); return; } @@ -421,6 +472,11 @@ after_frag( fd_gossip_tile_ctx_t * ctx, /* TODO: This doesn't seem right... */ if( in_idx!=NET_IN_IDX ) return; + if( in_idx == REPLAY_IN_IDX ) { + /* Messages from the replay tile for wen-restart are handled by after_credit periodically */ + return; + } + if ( in_idx == VOTER_IN_IDX ) { fd_crds_data_t vote_txn_crds; vote_txn_crds.discriminant = fd_crds_data_enum_vote; @@ -571,6 +627,25 @@ after_credit( fd_gossip_tile_ctx_t * ctx, } } + if( FD_UNLIKELY (( ctx->restart_msg_sz != 0 )&&( ctx->restart_last_voted_fork_push_time + LAST_VOTED_FORK_PUBLISH_PERIOD_NS < now )) ) { + ctx->restart_last_voted_fork_push_time = now; + fd_crds_data_t restart_msg; + restart_msg.discriminant = fd_crds_data_enum_restart_last_voted_fork_slots; + fd_memcpy( &restart_msg.inner.restart_last_voted_fork_slots, ctx->restart_msg, sizeof(fd_gossip_restart_last_voted_fork_slots_t) ); + + restart_msg.inner.restart_last_voted_fork_slots.shred_version = fd_gossip_get_shred_version( ctx->gossip ); + restart_msg.inner.restart_last_voted_fork_slots.offsets.inner.raw_offsets.offsets.bits.bits = ctx->restart_msg + sizeof(fd_gossip_restart_last_voted_fork_slots_t); + + FD_TEST( fd_gossip_push_value( ctx->gossip, &restart_msg, NULL ) == 0 ); + + FD_LOG_NOTICE(( "gossip sends the wen-restart message: struct=%luB, bitmap=%luB, shred_version=%u, vote_hash=%s", + sizeof(fd_gossip_restart_last_voted_fork_slots_t), + ctx->restart_msg_sz - sizeof(fd_gossip_restart_last_voted_fork_slots_t), + restart_msg.inner.restart_last_voted_fork_slots.shred_version, + FD_BASE58_ENC_32_ALLOCA( &restart_msg.inner.restart_last_voted_fork_slots.last_voted_hash ) )); + return; + } + ushort shred_version = fd_gossip_get_shred_version( ctx->gossip ); if( shred_version!=0U ) { *fd_shred_version = shred_version; @@ -597,21 +672,23 @@ unprivileged_init( fd_topo_t * topo, fd_topo_tile_t * tile ) { void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id ); - if( FD_UNLIKELY( tile->in_cnt != 3UL || - strcmp( topo->links[ tile->in_link_id[ NET_IN_IDX ] ].name, "net_gossip" ) || - strcmp( topo->links[ tile->in_link_id[ VOTER_IN_IDX ] ].name, "voter_gossip" ) || - strcmp( topo->links[ tile->in_link_id[ SIGN_IN_IDX ] ].name, "sign_gossip" ) ) ) { + if( FD_UNLIKELY( tile->in_cnt != 4UL || + strcmp( topo->links[ tile->in_link_id[ NET_IN_IDX ] ].name, "net_gossip" ) || + strcmp( topo->links[ tile->in_link_id[ VOTER_IN_IDX ] ].name, "voter_gossip" ) || + strcmp( topo->links[ tile->in_link_id[ REPLAY_IN_IDX ] ].name, "replay_gossi" ) || + strcmp( topo->links[ tile->in_link_id[ SIGN_IN_IDX ] ].name, "sign_gossip" ) ) ) { FD_LOG_ERR(( "gossip tile has none or unexpected input links %lu %s %s", tile->in_cnt, topo->links[ tile->in_link_id[ 0 ] ].name, topo->links[ tile->in_link_id[ 1 ] ].name )); } - if( FD_UNLIKELY( tile->out_cnt != 6 || - strcmp( topo->links[ tile->out_link_id[ NET_OUT_IDX ] ].name, "gossip_net" ) || - strcmp( topo->links[ tile->out_link_id[ SHRED_OUT_IDX ] ].name, "crds_shred" ) || - strcmp( topo->links[ tile->out_link_id[ REPAIR_OUT_IDX ] ].name, "gossip_repai" ) || - strcmp( topo->links[ tile->out_link_id[ DEDUP_OUT_IDX ] ].name, "gossip_dedup" ) || - strcmp( topo->links[ tile->out_link_id[ SIGN_OUT_IDX ] ].name, "gossip_sign" ) || - strcmp( topo->links[ tile->out_link_id[ VOTER_OUT_IDX ] ].name, "gossip_voter" ) ) ) { + if( FD_UNLIKELY( tile->out_cnt != 7UL || + strcmp( topo->links[ tile->out_link_id[ NET_OUT_IDX ] ].name, "gossip_net" ) || + strcmp( topo->links[ tile->out_link_id[ SHRED_OUT_IDX ] ].name, "crds_shred" ) || + strcmp( topo->links[ tile->out_link_id[ REPAIR_OUT_IDX ] ].name, "gossip_repai" ) || + strcmp( topo->links[ tile->out_link_id[ DEDUP_OUT_IDX ] ].name, "gossip_dedup" ) || + strcmp( topo->links[ tile->out_link_id[ SIGN_OUT_IDX ] ].name, "gossip_sign" ) || + strcmp( topo->links[ tile->out_link_id[ VOTER_OUT_IDX ] ].name, "gossip_voter" ) || + strcmp( topo->links[ tile->out_link_id[ REPLAY_OUT_IDX ] ].name, "gossip_repla" ) ) ) { FD_LOG_ERR(( "gossip tile has none or unexpected output links %lu %s %s", tile->out_cnt, topo->links[ tile->out_link_id[ 0 ] ].name, topo->links[ tile->out_link_id[ 1 ] ].name )); } @@ -655,7 +732,9 @@ unprivileged_init( fd_topo_t * topo, fd_net_create_packet_header_template( ctx->hdr, FD_NET_MTU, ctx->gossip_my_addr.addr, ctx->src_mac_addr, ctx->gossip_listen_port ); - ctx->last_shred_dest_push_time = 0; + ctx->last_shred_dest_push_time = 0; + ctx->restart_msg_sz = 0; + ctx->restart_last_voted_fork_push_time = 0; fd_topo_link_t * sign_in = &topo->links[ tile->in_link_id[ SIGN_IN_IDX ] ]; fd_topo_link_t * sign_out = &topo->links[ tile->out_link_id[ SIGN_OUT_IDX ] ]; @@ -726,10 +805,10 @@ unprivileged_init( fd_topo_t * topo, ctx->net_in_chunk = fd_disco_compact_chunk0( ctx->net_in_mem ); ctx->net_in_wmark = fd_disco_compact_wmark( ctx->net_in_mem, netmux_link->mtu ); - fd_topo_link_t * replay_in = &topo->links[ tile->in_link_id[ VOTER_IN_IDX ] ]; - ctx->replay_in_mem = topo->workspaces[ topo->objs[ replay_in->dcache_obj_id ].wksp_id ].wksp; - ctx->replay_in_chunk0 = fd_dcache_compact_chunk0( ctx->replay_in_mem, replay_in->dcache ); - ctx->replay_in_wmark = fd_dcache_compact_wmark( ctx->replay_in_mem, replay_in->dcache, replay_in->mtu ); + fd_topo_link_t * voter_in = &topo->links[ tile->in_link_id[ VOTER_IN_IDX ] ]; + ctx->voter_in_mem = topo->workspaces[ topo->objs[ voter_in->dcache_obj_id ].wksp_id ].wksp; + ctx->voter_in_chunk0 = fd_dcache_compact_chunk0( ctx->voter_in_mem, voter_in->dcache ); + ctx->voter_in_wmark = fd_dcache_compact_wmark( ctx->voter_in_mem, voter_in->dcache, voter_in->mtu ); /* Set up shred contact info tile output */ fd_topo_link_t * shred_contact_out = &topo->links[ tile->out_link_id[ SHRED_OUT_IDX ] ]; @@ -775,6 +854,22 @@ unprivileged_init( fd_topo_t * topo, ctx->voter_contact_out_wmark = fd_dcache_compact_wmark ( ctx->voter_contact_out_mem, voter_out->dcache, voter_out->mtu ); ctx->voter_contact_out_chunk = ctx->voter_contact_out_chunk0; + /* Set up crds restart messages input/output with the replay tile */ + fd_topo_link_t * replay_in = &topo->links[ tile->in_link_id[ REPLAY_IN_IDX ] ]; + ctx->replay_in_mem = topo->workspaces[ topo->objs[ replay_in->dcache_obj_id ].wksp_id ].wksp; + ctx->replay_in_chunk0 = fd_dcache_compact_chunk0( ctx->replay_in_mem, replay_in->dcache ); + ctx->replay_in_wmark = fd_dcache_compact_wmark( ctx->replay_in_mem, replay_in->dcache, replay_in->mtu ); + + fd_topo_link_t * replay_out = &topo->links[ tile->out_link_id[ REPLAY_OUT_IDX ] ]; + ctx->replay_out_mcache = replay_out->mcache; + ctx->replay_out_sync = fd_mcache_seq_laddr( ctx->replay_out_mcache ); + ctx->replay_out_depth = fd_mcache_depth( ctx->replay_out_mcache ); + ctx->replay_out_seq = fd_mcache_seq_query( ctx->replay_out_sync ); + ctx->replay_out_mem = topo->workspaces[ topo->objs[ replay_out->dcache_obj_id ].wksp_id ].wksp; + ctx->replay_out_chunk0 = fd_dcache_compact_chunk0( ctx->replay_out_mem, replay_out->dcache ); + ctx->replay_out_wmark = fd_dcache_compact_wmark ( ctx->replay_out_mem, replay_out->dcache, replay_out->mtu ); + ctx->replay_out_chunk = ctx->replay_out_chunk0; + ulong scratch_top = FD_SCRATCH_ALLOC_FINI( l, 1UL ); if( FD_UNLIKELY( scratch_top>( (ulong)scratch + scratch_footprint( tile ) ) ) ) FD_LOG_ERR(( "scratch overflow %lu %lu %lu", scratch_top - (ulong)scratch - scratch_footprint( tile ), scratch_top, (ulong)scratch + scratch_footprint( tile ) )); diff --git a/src/app/fdctl/run/tiles/fd_replay.c b/src/app/fdctl/run/tiles/fd_replay.c index 0960b7d4eb..b0aaecf67f 100644 --- a/src/app/fdctl/run/tiles/fd_replay.c +++ b/src/app/fdctl/run/tiles/fd_replay.c @@ -27,6 +27,7 @@ #include "../../../../util/net/fd_net_headers.h" #include "fd_replay_notif.h" #include "generated/replay_seccomp.h" +#include "../../../../disco/restart/fd_restart.h" #include "../../../../disco/metrics/fd_metrics.h" #include "../../../../disco/metrics/generated/fd_metrics_replay.h" #include "../../../../choreo/fd_choreo.h" @@ -54,11 +55,13 @@ #define STORE_IN_IDX (0UL) #define PACK_IN_IDX (1UL) +#define GOSSIP_IN_IDX (2UL) #define STAKE_OUT_IDX (0UL) #define NOTIF_OUT_IDX (1UL) #define SENDER_OUT_IDX (2UL) -#define POH_OUT_IDX (3UL) +#define GOSSIP_OUT_IDX (3UL) +#define POH_OUT_IDX (4UL) /* Scratch space estimates. TODO: Update constants and add explanation @@ -101,6 +104,11 @@ struct fd_replay_tile_ctx { ulong pack_in_chunk0; ulong pack_in_wmark; + // Gossip tile input for wen-restart + fd_wksp_t * gossip_in_mem; + ulong gossip_in_chunk0; + ulong gossip_in_wmark; + // Notification output defs fd_frag_meta_t * notif_out_mcache; ulong * notif_out_sync; @@ -123,6 +131,17 @@ struct fd_replay_tile_ctx { ulong sender_out_wmark; ulong sender_out_chunk; + // Gossip tile output defs for wen-restart + fd_frag_meta_t * gossip_out_mcache; + ulong * gossip_out_sync; + ulong gossip_out_depth; + ulong gossip_out_seq; + + fd_wksp_t * gossip_out_mem; + ulong gossip_out_chunk0; + ulong gossip_out_wmark; + ulong gossip_out_chunk; + // Stake weights output link defs fd_frag_meta_t * stake_weights_out_mcache; ulong * stake_weights_out_sync; @@ -199,6 +218,9 @@ struct fd_replay_tile_ctx { uint poh_init_done; int snapshot_init_done; + int in_wen_restart; + fd_restart_state_t * restart_state; + int vote; fd_pubkey_t validator_identity_pubkey[ 1 ]; fd_pubkey_t vote_acct_addr[ 1 ]; @@ -245,6 +267,7 @@ scratch_footprint( fd_topo_tile_t const * tile FD_PARAM_UNUSED ) { l = FD_LAYOUT_APPEND( l, FD_SCRATCH_ALIGN_DEFAULT, tile->replay.tpool_thread_count * TPOOL_WORKER_MEM_SZ ); l = FD_LAYOUT_APPEND( l, fd_scratch_smem_align(), fd_scratch_smem_footprint( SCRATCH_MAX ) ); l = FD_LAYOUT_APPEND( l, fd_scratch_fmem_align(), fd_scratch_fmem_footprint( SCRATCH_DEPTH ) ); + l = FD_LAYOUT_APPEND( l, fd_restart_state_align(), fd_restart_state_footprint() ); l = FD_LAYOUT_FINI ( l, scratch_align() ); return l; } @@ -427,6 +450,52 @@ during_frag( fd_replay_tile_ctx_t * ctx, } FD_LOG_DEBUG(( "packed microblock - slot: %lu, parent_slot: %lu, txn_cnt: %lu", ctx->curr_slot, ctx->parent_slot, ctx->txn_cnt )); + } else if( in_idx == GOSSIP_IN_IDX ) { + if( FD_UNLIKELY( chunkgossip_in_chunk0 || chunk>ctx->gossip_in_wmark || sz>LAST_VOTED_FORK_MAX_MSG_BYTES ) ) { + FD_LOG_ERR(( "chunk %lu %lu corrupt, not in range [%lu,%lu]", chunk, sz, ctx->pack_in_chunk0, ctx->pack_in_wmark )); + } + uchar * src = (uchar *) fd_type_pun( fd_chunk_to_laddr( ctx->gossip_in_mem, chunk) ); + uint discriminant = FD_LOAD( uint, src ); + src += sizeof(uint); + + if( discriminant==fd_crds_data_enum_restart_heaviest_fork ) { + /* Incoming packet from gossip tile. Format: + Wen-restart gossip message for heaviest_fork (fd_gossip_restart_heaviest_fork_t) + */ + fd_gossip_restart_heaviest_fork_t * msg = (fd_gossip_restart_heaviest_fork_t * ) fd_type_pun( src ); + FD_LOG_WARNING(( "Received a restart_heaviest_fork message: slot=%lu, hash=%s", + msg->last_slot, FD_BASE58_ENC_32_ALLOCA( &msg->last_slot_hash ) )); + ctx->restart_state->coordinator_heaviest_fork_slot = msg->last_slot; + fd_memcpy( &ctx->restart_state->coordinator_heaviest_fork_bank_hash, + &msg->last_slot_hash, + sizeof(fd_hash_t) ); + ctx->restart_state->coordinator_heaviest_fork_ready = 1; + } else if( discriminant==fd_crds_data_enum_restart_last_voted_fork_slots ) { + /* Incoming packet from gossip tile. Format: + Wen-restart gossip message for last voted fork slots (fd_gossip_restart_last_voted_fork_slots_t) + Bitmap in raw format (uchar* - bitmap size is specified in the gossip message) + */ + fd_gossip_restart_last_voted_fork_slots_t * msg = (fd_gossip_restart_last_voted_fork_slots_t * ) fd_type_pun( src ); + msg->offsets.inner.raw_offsets.offsets.bits.bits = src + sizeof(fd_gossip_restart_last_voted_fork_slots_t); + fd_restart_recv_last_voted_fork_slots( ctx->restart_state, msg ); + + if( ctx->restart_state->heaviest_fork_slot!=ULONG_MAX ) { + /* Notify the store tile for repairing/replaying the chosen heaviest fork */ + fd_blockstore_start_write( ctx->blockstore ); + fd_block_map_t * block_map = fd_blockstore_block_map( ctx->blockstore ); + for( ulong slot=ctx->blockstore->smr+1; slot<=ctx->restart_state->heaviest_fork_slot; slot++ ){ + fd_block_map_t * block_map_entry = fd_block_map_query( block_map, &slot, NULL ); + if( block_map_entry != NULL ){ + fd_blockstore_slot_remove( ctx->blockstore, slot); + FD_LOG_NOTICE(( "Cleaning up slot%lu from blockstore for wen-restart repair", slot )); + } + } + ctx->blockstore->restart_heaviest_fork_slot = ctx->restart_state->heaviest_fork_slot; + fd_blockstore_end_write( ctx->blockstore ); + } + } + + return; } // if( ctx->flags & REPLAY_FLAG_PACKED_MICROBLOCK ) { @@ -1103,6 +1172,13 @@ after_frag( fd_replay_tile_ctx_t * ctx, fd_solcap_writer_flush( ctx->capture_ctx->capture ); } + /* Wen-restart checks whether repair&replay has finished */ + + if( ctx->in_wen_restart && curr_slot==ctx->restart_state->heaviest_fork_slot ) { + fd_hash_t const * bank_hash = &child->slot_ctx.slot_bank.banks_hash; + fd_memcpy( &ctx->restart_state->heaviest_fork_bank_hash, bank_hash, sizeof(fd_hash_t) ); + ctx->restart_state->heaviest_fork_ready = 1; + } /* Bank hash cmp */ @@ -1383,6 +1459,60 @@ after_credit( fd_replay_tile_ctx_t * ctx, init_snapshot( ctx, stem ); ctx->snapshot_init_done = 1; *charge_busy = 1; + if( FD_UNLIKELY( ctx->in_wen_restart ) ) { + if( FD_UNLIKELY( strncmp( ctx->snapshot, "wksp:", 5 )!=0 ) ) { + FD_LOG_WARNING(( "Snapshot should be a funk checkpoint file for wen-restart.\n \ + Specifically, there are 2 steps for wen-restart:\n \ + 1) Terminate the normal execution of FD which creates checkpoint files;\n \ + 2) Restart FD in wen-restart mode and use the funk checkpoint as snapshot." )); + fd_memset( ctx->restart_state, 0, fd_restart_state_footprint() ); + } else { + FD_SCRATCH_SCOPE_BEGIN { + ulong buf_len; + uchar * buf = fd_chunk_to_laddr( ctx->gossip_out_mem, ctx->gossip_out_chunk ); + fd_sysvar_slot_history_read( ctx->slot_ctx, fd_scratch_virtual(), ctx->slot_ctx->slot_history ); + fd_restart_init( ctx->restart_state, + &ctx->slot_ctx->slot_bank.epoch_stakes, + ctx->tower, + ctx->slot_ctx->slot_history, + ctx->slot_ctx->blockstore, + buf, + &buf_len ); + fd_mcache_publish( ctx->gossip_out_mcache, ctx->gossip_out_depth, ctx->gossip_out_seq, 1UL, ctx->gossip_out_chunk, + buf_len, 0UL, 0, 0 ); + ctx->gossip_out_seq = fd_seq_inc( ctx->gossip_out_seq, 1UL ); + ctx->gossip_out_chunk = fd_dcache_compact_next( ctx->gossip_out_chunk, buf_len, ctx->gossip_out_chunk0, ctx->gossip_out_wmark ); + + /* FIXME: Restoring funk checkpoint does not give the correct epoch number, + * i.e., the epoch number when the funk checkpoint file is produced. + * For now, we need to redo stakes->epoch in order to avoid a BHM in + * a local setup when repairing blocks. */ + fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( ctx->slot_ctx->epoch_ctx ); + fd_stakes_t * stakes = &epoch_bank->stakes; + stakes->epoch = ctx->blockstore->smr / epoch_bank->epoch_schedule.slots_per_epoch; + FD_LOG_NOTICE(( "slots_per_epoch=%lu, blockstore root=%lu", epoch_bank->epoch_schedule.slots_per_epoch, ctx->blockstore->smr )); + FD_LOG_WARNING(( "Reset stakes->epoch=%lu (blockstore root / slots per epoch)", stakes->epoch )); + } FD_SCRATCH_SCOPE_END; + } + } + } + + /* Verify the heaviest fork for the output of wen-restart */ + if( FD_UNLIKELY(( ctx->restart_state->heaviest_fork_ready==1 && ctx->restart_state->coordinator_heaviest_fork_ready==1 )) ) { + if( ctx->restart_state->heaviest_fork_slot!=ctx->restart_state->coordinator_heaviest_fork_slot ) { + FD_LOG_ERR(( "Heaviest fork mismatch: my slot=%lu, coordinator slot=%lu", + ctx->restart_state->heaviest_fork_slot, ctx->restart_state->coordinator_heaviest_fork_slot )); + } + if( memcmp( ctx->restart_state->heaviest_fork_bank_hash.hash, + ctx->restart_state->coordinator_heaviest_fork_bank_hash.hash, + sizeof(fd_hash_t) )!=0 ) { + FD_LOG_ERR(( "Heaviest fork mismatch for slot%lu: my hash=%s, coordinator hash=%s", + ctx->restart_state->heaviest_fork_slot, + FD_BASE58_ENC_32_ALLOCA( &ctx->restart_state->heaviest_fork_bank_hash ), + FD_BASE58_ENC_32_ALLOCA( &ctx->restart_state->coordinator_heaviest_fork_bank_hash ) )); + } + FD_LOG_ERR(( "Wen-restart succeeds with slot=%lu, bank hash=%s", + ctx->restart_state->heaviest_fork_slot, FD_BASE58_ENC_32_ALLOCA( &ctx->restart_state->heaviest_fork_bank_hash ) )); } } @@ -1417,6 +1547,11 @@ during_housekeeping( void * _ctx ) { fd_ghost_publish( ctx->ghost, smr ); } + /* FIXME: Decide how to tell FD to checkpoint funk and then halt before restarting FD in wen-restart mode */ + if( ctx->in_wen_restart && ctx->curr_slot>ctx->snapshot_slot+200 ) { + checkpt( ctx ); + FD_LOG_ERR(( "Halt and wait for restarting in wen-restart mode" )); + } // fd_mcache_seq_update( ctx->store_out_sync, ctx->store_out_seq ); } @@ -1461,6 +1596,7 @@ unprivileged_init( fd_topo_t * topo, void * tpool_worker_mem = FD_SCRATCH_ALLOC_APPEND( l, FD_SCRATCH_ALIGN_DEFAULT, tile->replay.tpool_thread_count * TPOOL_WORKER_MEM_SZ ); void * scratch_smem = FD_SCRATCH_ALLOC_APPEND( l, fd_scratch_smem_align(), fd_scratch_smem_footprint( SCRATCH_MAX ) ); void * scratch_fmem = FD_SCRATCH_ALLOC_APPEND( l, fd_scratch_fmem_align(), fd_scratch_fmem_footprint( SCRATCH_DEPTH ) ); + void * restart_state_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_restart_state_align(), fd_restart_state_footprint() ); ulong scratch_alloc_mem = FD_SCRATCH_ALLOC_FINI ( l, scratch_align() ); if( FD_UNLIKELY( scratch_alloc_mem != ( (ulong)scratch + scratch_footprint( tile ) ) ) ) { @@ -1750,6 +1886,12 @@ unprivileged_init( fd_topo_t * topo, ctx->validator_identity_pubkey[ 0 ] = *(fd_pubkey_t const *)fd_type_pun_const( fd_keyload_load( tile->replay.identity_key_path, 1 ) ); ctx->vote_acct_addr[ 0 ] = *(fd_pubkey_t const *)fd_type_pun_const( fd_keyload_load( tile->replay.vote_account_path, 1 ) ); + /**********************************************************************/ + /* wen-restart */ + /**********************************************************************/ + ctx->in_wen_restart = tile->replay.in_wen_restart; + ctx->restart_state = restart_state_mem; + /**********************************************************************/ /* links */ /**********************************************************************/ @@ -1766,6 +1908,12 @@ unprivileged_init( fd_topo_t * topo, ctx->pack_in_chunk0 = fd_dcache_compact_chunk0( ctx->pack_in_mem, pack_in_link->dcache ); ctx->pack_in_wmark = fd_dcache_compact_wmark( ctx->pack_in_mem, pack_in_link->dcache, pack_in_link->mtu ); + /* Set up gossip tile input for wen-restart */ + fd_topo_link_t * gossip_in_link = &topo->links[ tile->in_link_id[ GOSSIP_IN_IDX ] ]; + ctx->gossip_in_mem = topo->workspaces[ topo->objs[ gossip_in_link->dcache_obj_id ].wksp_id ].wksp; + ctx->gossip_in_chunk0 = fd_dcache_compact_chunk0( ctx->gossip_in_mem, gossip_in_link->dcache ); + ctx->gossip_in_wmark = fd_dcache_compact_wmark( ctx->gossip_in_mem, gossip_in_link->dcache, gossip_in_link->mtu ); + fd_topo_link_t * notif_out = &topo->links[ tile->out_link_id[ NOTIF_OUT_IDX ] ]; ctx->notif_out_mcache = notif_out->mcache; ctx->notif_out_sync = fd_mcache_seq_laddr( ctx->notif_out_mcache ); @@ -1786,6 +1934,16 @@ unprivileged_init( fd_topo_t * topo, ctx->sender_out_wmark = fd_dcache_compact_wmark ( ctx->sender_out_mem, sender_out->dcache, sender_out->mtu ); ctx->sender_out_chunk = ctx->sender_out_chunk0; + fd_topo_link_t * gossip_out = &topo->links[ tile->out_link_id[ GOSSIP_OUT_IDX ] ]; + ctx->gossip_out_mcache = gossip_out->mcache; + ctx->gossip_out_sync = fd_mcache_seq_laddr( ctx->gossip_out_mcache ); + ctx->gossip_out_depth = fd_mcache_depth( ctx->gossip_out_mcache ); + ctx->gossip_out_seq = fd_mcache_seq_query( ctx->gossip_out_sync ); + ctx->gossip_out_chunk0 = fd_dcache_compact_chunk0( fd_wksp_containing( gossip_out->dcache ), gossip_out->dcache ); + ctx->gossip_out_mem = topo->workspaces[ topo->objs[ gossip_out->dcache_obj_id ].wksp_id ].wksp; + ctx->gossip_out_wmark = fd_dcache_compact_wmark( ctx->gossip_out_mem, gossip_out->dcache, gossip_out->mtu ); + ctx->gossip_out_chunk = ctx->gossip_out_chunk0; + /* Set up stake weights tile output */ fd_topo_link_t * stake_weights_out = &topo->links[ tile->out_link_id[ STAKE_OUT_IDX] ]; ctx->stake_weights_out_mcache = stake_weights_out->mcache; diff --git a/src/app/fdctl/run/tiles/fd_store_int.c b/src/app/fdctl/run/tiles/fd_store_int.c index abc5ba9e9f..8fa9a1bf48 100644 --- a/src/app/fdctl/run/tiles/fd_store_int.c +++ b/src/app/fdctl/run/tiles/fd_store_int.c @@ -496,6 +496,11 @@ after_credit( fd_store_tile_ctx_t * ctx, FD_LOG_DEBUG(( "store slot - mode: %d, slot: %lu, repair_slot: %lu", store_slot_prepare_mode, i, repair_slot )); fd_store_tile_slot_prepare( ctx, stem, store_slot_prepare_mode, slot ); } + + if( ctx->blockstore->restart_heaviest_fork_slot!=0 ) { + /* In wen-restart, keep adding the restart_heaviest_fork_slot to the pending queue until it has been repaired and replayed */ + fd_store_add_pending( ctx->store, ctx->blockstore->restart_heaviest_fork_slot, (long)5e6, 0, 0 ); + } } static void @@ -588,7 +593,7 @@ unprivileged_init( fd_topo_t * topo, } FD_LOG_NOTICE(( "finished blockstore_wksp restore %s", tile->store_int.blockstore_restore )); fd_wksp_tag_query_info_t info; - ulong tag = FD_BLOCKSTORE_MAGIC; + ulong tag = 1; if (fd_wksp_tag_query(ctx->blockstore_wksp, &tag, 1, &info, 1) > 0) { void * blockstore_mem = fd_wksp_laddr_fast( ctx->blockstore_wksp, info.gaddr_lo ); ctx->blockstore = fd_blockstore_join( blockstore_mem ); @@ -693,6 +698,7 @@ unprivileged_init( fd_topo_t * topo, fclose( file ); } + ctx->shred_cap_ctx.is_archive = 0; ctx->shred_cap_ctx.stable_slot_end = 0; ctx->shred_cap_ctx.stable_slot_start = 0; if( strlen( tile->store_int.shred_cap_archive ) > 0 ) { diff --git a/src/app/fdctl/run/topos/fd_firedancer.c b/src/app/fdctl/run/topos/fd_firedancer.c index b367a65221..5ecb2d697c 100644 --- a/src/app/fdctl/run/topos/fd_firedancer.c +++ b/src/app/fdctl/run/topos/fd_firedancer.c @@ -113,6 +113,9 @@ fd_topo_initialize( config_t * config ) { fd_topob_wksp( topo, "gossip_sign" ); fd_topob_wksp( topo, "sign_gossip" ); + fd_topob_wksp( topo, "gossip_repla" ); + fd_topob_wksp( topo, "replay_gossi" ); + fd_topob_wksp( topo, "voter_sign" ); fd_topob_wksp( topo, "sign_voter" ); @@ -136,7 +139,6 @@ fd_topo_initialize( config_t * config ) { fd_topob_wksp( topo, "gossip_voter" ); fd_topob_wksp( topo, "voter_gossip" ); fd_topob_wksp( topo, "voter_dedup" ); - fd_topob_wksp( topo, "poh_replay" ); fd_topob_wksp( topo, "net" ); fd_topob_wksp( topo, "quic" ); @@ -184,6 +186,9 @@ fd_topo_initialize( config_t * config ) { /**/ fd_topob_link( topo, "gossip_sign", "gossip_sign", 0, 128UL, 2048UL, 1UL ); /**/ fd_topob_link( topo, "sign_gossip", "sign_gossip", 0, 128UL, 64UL, 1UL ); + /**/ fd_topob_link( topo, "gossip_repla", "gossip_repla", 0, 128UL, 128UL + 8192UL, 1UL ); + /**/ fd_topob_link( topo, "replay_gossi", "replay_gossi", 0, 128UL, 128UL + 8192UL, 1UL ); + /* gossip_dedup could be FD_TPU_MTU, since txns are not parsed, but better to just share one size for all the ins of dedup */ /**/ fd_topob_link( topo, "gossip_dedup", "gossip_dedup", 0, config->tiles.verify.receive_buffer_size, FD_TPU_DCACHE_MTU, 1UL ); @@ -206,7 +211,6 @@ fd_topo_initialize( config_t * config ) { /**/ fd_topob_link( topo, "poh_shred", "poh_shred", 0, 16384UL, USHORT_MAX, 1UL ); /**/ fd_topob_link( topo, "pack_replay", "pack_replay", 0, 65536UL, USHORT_MAX, 1UL ); /**/ fd_topob_link( topo, "poh_pack", "replay_poh", 0, 128UL, sizeof(fd_became_leader_t) , 1UL ); - /**/ fd_topob_link( topo, "poh_replay", "poh_replay", 0, 128UL, USHORT_MAX, 1UL ); /* TODO: not properly sized yet */ /**/ fd_topob_link( topo, "replay_voter", "replay_voter", 0, 128UL, FD_TPU_DCACHE_MTU, 1UL ); /**/ fd_topob_link( topo, "voter_gossip", "voter_gossip", 0, 128UL, FD_TXN_MTU, 1UL ); @@ -399,9 +403,11 @@ fd_topo_initialize( config_t * config ) { /**/ fd_topob_tile_in( topo, "sign", 0UL, "metric_in", "gossip_sign", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /**/ fd_topob_tile_out( topo, "gossip", 0UL, "gossip_sign", 0UL ); /**/ fd_topob_tile_in( topo, "gossip", 0UL, "metric_in", "voter_gossip", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); + /**/ fd_topob_tile_in( topo, "gossip", 0UL, "metric_in", "replay_gossi", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /**/ fd_topob_tile_in( topo, "gossip", 0UL, "metric_in", "sign_gossip", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_UNPOLLED ); /**/ fd_topob_tile_out( topo, "sign", 0UL, "sign_gossip", 0UL ); /**/ fd_topob_tile_out( topo, "gossip", 0UL, "gossip_voter", 0UL ); + /**/ fd_topob_tile_out( topo, "gossip", 0UL, "gossip_repla", 0UL ); FOR(net_tile_cnt) fd_topob_tile_out( topo, "net", i, "net_repair", i ); FOR(net_tile_cnt) fd_topob_tile_in( topo, "repair", 0UL, "metric_in", "net_repair", i, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */ @@ -412,8 +418,9 @@ fd_topo_initialize( config_t * config ) { /**/ fd_topob_tile_out( topo, "replay", 0UL, "stake_out", 0UL ); /**/ fd_topob_tile_out( topo, "replay", 0UL, "replay_notif", 0UL ); /**/ fd_topob_tile_in( topo, "replay", 0UL, "metric_in", "pack_replay", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED ); - /**/ fd_topob_tile_in( topo, "replay", 0UL, "metric_in", "poh_replay", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED ); + /**/ fd_topob_tile_in( topo, "replay", 0UL, "metric_in", "gossip_repla", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /**/ fd_topob_tile_out( topo, "replay", 0UL, "replay_voter", 0UL ); + /**/ fd_topob_tile_out( topo, "replay", 0UL, "replay_gossi", 0UL ); FOR(bank_tile_cnt) fd_topob_tile_out( topo, "replay", 0UL, "replay_poh", i ); /**/ fd_topob_tile_in( topo, "sender", 0UL, "metric_in", "stake_out", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */ @@ -439,7 +446,6 @@ fd_topo_initialize( config_t * config ) { /**/ fd_topob_tile_in( topo, "pohi", 0UL, "metric_in", "pack_replay", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED ); fd_topob_tile_out( topo, "pohi", 0UL, "poh_pack", 0UL ); - fd_topob_tile_out( topo, "pohi", 0UL, "poh_replay", 0UL ); /**/ fd_topob_tile_in( topo, "sign", 0UL, "metric_in", "repair_sign", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /**/ fd_topob_tile_out( topo, "repair", 0UL, "repair_sign", 0UL ); @@ -577,6 +583,7 @@ fd_topo_initialize( config_t * config ) { } strncpy( tile->replay.cluster_version, config->tiles.replay.cluster_version, sizeof(tile->replay.cluster_version) ); tile->replay.bank_tile_count = config->layout.bank_tile_count; + tile->replay.in_wen_restart = config->tiles.replay.in_wen_restart; /* not specified by [tiles.replay] */ diff --git a/src/disco/restart/Local.mk b/src/disco/restart/Local.mk new file mode 100644 index 0000000000..527cdfd8b1 --- /dev/null +++ b/src/disco/restart/Local.mk @@ -0,0 +1,4 @@ +ifdef FD_HAS_INT128 +$(call add-hdrs,fd_restart.h) +$(call add-objs,fd_restart,fd_disco) +endif diff --git a/src/disco/restart/fd_restart.c b/src/disco/restart/fd_restart.c new file mode 100644 index 0000000000..cf8fc5c6b2 --- /dev/null +++ b/src/disco/restart/fd_restart.c @@ -0,0 +1,147 @@ +#include "fd_restart.h" +#include "../../util/fd_util.h" +#include "../../flamenco/stakes/fd_stakes.h" + +#pragma GCC diagnostic ignored "-Wformat" +#pragma GCC diagnostic ignored "-Wformat-extra-args" + +void +fd_restart_init( fd_restart_state_t * restart_state, + fd_vote_accounts_t const * accs, + fd_tower_t const * tower, + fd_slot_history_t const * slot_history, + fd_blockstore_t * blockstore, + uchar * buf_out, + ulong * buf_len_out ) { + restart_state->num_vote_accts = fd_stake_weights_by_node( accs, restart_state->stake_weights ); + restart_state->total_stake = 0; + restart_state->total_active_stake = 0; + restart_state->root = tower->root; + FD_TEST( restart_state->num_vote_accts <= MAX_RESTART_PEERS ); + + for( ulong i=0; inum_vote_accts; i++ ) { + FD_LOG_NOTICE(( "fd_restart_init: %s holds stake amount=%lu", + FD_BASE58_ENC_32_ALLOCA( &restart_state->stake_weights[i].key ), + restart_state->stake_weights[i].stake )); + restart_state->total_stake += restart_state->stake_weights[i].stake; + } + + fd_gossip_restart_last_voted_fork_slots_t * msg = (fd_gossip_restart_last_voted_fork_slots_t *) fd_type_pun( buf_out ); + /* FIXME: Need to check whether this tower loaded from the funk checkpoint is the right one to use; It seems stale. */ + msg->last_voted_slot = fd_tower_votes_peek_tail_const( tower->votes )->slot; + if( FD_UNLIKELY( msg->last_voted_slot>=slot_history->next_slot ) ) { + FD_LOG_ERR(( "Voted slot should not exceed the end of slot history" )); + } + + fd_blockstore_start_read( blockstore ); + fd_hash_t const * vote_block_hash = fd_blockstore_block_hash_query( blockstore, msg->last_voted_slot ); + fd_blockstore_end_read( blockstore ); + if( FD_UNLIKELY( vote_block_hash==NULL ) ) { + FD_LOG_ERR(( "fd_restart_init: cannot query the block hash of last voted slot=%lu from blockstore", msg->last_voted_slot )); + } else { + FD_LOG_NOTICE(( "fd_restart_init: voted for slot%lu with block hash %s", msg->last_voted_slot, FD_BASE58_ENC_32_ALLOCA( vote_block_hash ) )); + fd_memcpy( msg->last_voted_hash.hash, vote_block_hash->hash, sizeof(fd_hash_t) ); + } + + ulong end_slot = msg->last_voted_slot; + ulong start_slot = ( end_slot>LAST_VOTED_FORK_MAX_SLOTS? end_slot-LAST_VOTED_FORK_MAX_SLOTS : 0 ); + ulong num_slots = end_slot-start_slot+1; + msg->offsets.discriminant = fd_restart_slots_offsets_enum_raw_offsets; + msg->offsets.inner.raw_offsets.offsets.has_bits = 1; + msg->offsets.inner.raw_offsets.offsets.len = num_slots; + msg->offsets.inner.raw_offsets.offsets.bits.bits_len = ( num_slots+bits_per_uchar )/bits_per_uchar; + *buf_len_out = sizeof(fd_gossip_restart_last_voted_fork_slots_t) + ( num_slots+bits_per_uchar )/bits_per_uchar; + FD_LOG_NOTICE(( "fd_restart_init: encoding %lu bits in bitmap", num_slots )); + + uchar * bitmap = buf_out + sizeof(fd_gossip_restart_last_voted_fork_slots_t); + for( ulong i=start_slot; i<=end_slot; i++ ) { + ulong in_idx = ( i/bits_per_ulong )%( slot_history->bits.bits->blocks_len ); + ulong in_bit_off = i%bits_per_ulong; + + ulong offset_from_end = end_slot-i; + ulong out_idx = offset_from_end/bits_per_uchar; + int out_bit_off = offset_from_end%bits_per_uchar; + + if( FD_LIKELY( slot_history->bits.bits->blocks[ in_idx ] & (1UL<stage = WR_STATE_FIND_HEAVIEST_FORK; + restart_state->heaviest_fork_slot = ULONG_MAX; + restart_state->heaviest_fork_ready = 0; + restart_state->coordinator_heaviest_fork_ready = 0; + fd_memset( restart_state->slot_to_stake, 0, sizeof(restart_state->slot_to_stake) ); + fd_memset( restart_state->last_voted_fork_slots_received, 0, sizeof(restart_state->last_voted_fork_slots_received) ); +} + +void +fd_restart_recv_last_voted_fork_slots( fd_restart_state_t * restart_state, + fd_gossip_restart_last_voted_fork_slots_t * msg ) { + if( FD_UNLIKELY( restart_state->stage!=WR_STATE_FIND_HEAVIEST_FORK ) ) { + return; + } + + ulong stake = ULONG_MAX; + fd_pubkey_t * pubkey = &msg->from; + for( ulong i=0; inum_vote_accts; i++ ) { + if( FD_UNLIKELY( memcmp( pubkey->key, restart_state->stake_weights[i].key.key, sizeof(fd_pubkey_t) ) == 0 ) ) { + if( FD_UNLIKELY( restart_state->last_voted_fork_slots_received[i] ) ) { + FD_LOG_NOTICE(( "Duplicate last_voted_fork_slots message from %s", FD_BASE58_ENC_32_ALLOCA( pubkey ) )); + return; + } + stake = restart_state->stake_weights[i].stake; + restart_state->last_voted_fork_slots_received[i] = 1; + break; + } + } + if( FD_UNLIKELY( stake==ULONG_MAX ) ) { + FD_LOG_WARNING(( "Get last_voted_fork_slots message from unknown validator: %s", FD_BASE58_ENC_32_ALLOCA( pubkey ) )); + return; + } + + restart_state->total_active_stake += stake; + ulong percentile = restart_state->total_active_stake * 100 / restart_state->total_stake; + FD_LOG_NOTICE(( "Total active stake: %lu/%lu = %lu%\n", + restart_state->total_active_stake, + restart_state->total_stake, + percentile)); + + if( FD_UNLIKELY( msg->offsets.discriminant==fd_restart_slots_offsets_enum_run_length_encoding ) ) { + FD_LOG_ERR(( "Decoding RunLengthEncoding offsets is not implemented yet" )); + } + + for( ulong i=0, last_voted_slot = msg->last_voted_slot; \ + ioffsets.inner.raw_offsets.offsets.len; i++ ) { + if( FD_UNLIKELY( last_voted_slotroot+i ) ) break; + + ulong slot = last_voted_slot-i; + ulong byte_off = i/bits_per_uchar; + ulong bit_off = i%bits_per_uchar; + uchar bit = msg->offsets.inner.raw_offsets.offsets.bits.bits[ byte_off ] & (uchar)(1<root; + restart_state->slot_to_stake[ offset ] += stake; + } + } + + if( FD_UNLIKELY( percentile>=WAIT_FOR_SUPERMAJORITY_THRESHOLD_PERCENT ) ) { + ulong stake_threshold = restart_state->total_active_stake + - restart_state->total_stake * HEAVIEST_FORK_THRESHOLD_DELTA_PERCENT / 100UL; + + FD_LOG_NOTICE(( "Stake threshold: %lu", stake_threshold )); + restart_state->heaviest_fork_slot = restart_state->root; + for( ulong offset=0; offsetslot_to_stake[ offset ]>=stake_threshold ) ) { + restart_state->heaviest_fork_slot = restart_state->root+offset; + } + } + FD_LOG_NOTICE(( "Found heaviest fork slot=%lu", restart_state->heaviest_fork_slot )); + + restart_state->stage = WR_STATE_AGREE_ON_HEAVIEST_FORK; + } +} diff --git a/src/disco/restart/fd_restart.h b/src/disco/restart/fd_restart.h new file mode 100644 index 0000000000..c2e053bef9 --- /dev/null +++ b/src/disco/restart/fd_restart.h @@ -0,0 +1,100 @@ +#ifndef HEADER_fd_src_choreo_restart_fd_restart_h +#define HEADER_fd_src_choreo_restart_fd_restart_h + +/* fd_restart implements Solana's SIMD-0046, Optimistic cluster restart + automation, also known as wen-restart. + Protocol details: + TODO, the protocol may still change and the agave code has not been + finalized yet. + */ + +#include "../../choreo/tower/fd_tower.h" +#include "../../flamenco/types/fd_types.h" + +#define bits_per_uchar 8 +#define bits_per_ulong ( 8 * sizeof(ulong) ) + +/* Protocol parameters of wen-restart */ +#define HEAVIEST_FORK_THRESHOLD_DELTA_PERCENT 38UL +#define REPAIR_THRESHOLD_PERCENT 42UL +#define WAIT_FOR_SUPERMAJORITY_THRESHOLD_PERCENT 80UL +#define LAST_VOTED_FORK_MAX_SLOTS 0xFFFFUL + +/* Implementation-specific parameters */ +#define MAX_RESTART_PEERS 40200UL +#define LAST_VOTED_FORK_PUBLISH_PERIOD_NS 10e9L +#define LAST_VOTED_FORK_MAX_BITMAP_BYTES ( LAST_VOTED_FORK_MAX_SLOTS/bits_per_uchar+1 ) +#define LAST_VOTED_FORK_MAX_MSG_BYTES ( sizeof(fd_gossip_restart_last_voted_fork_slots_t)+LAST_VOTED_FORK_MAX_BITMAP_BYTES ) + +/* Wen-restart has 2 stages: + one for finding the heaviest fork, + another for disseminating the heaviest fork information */ +typedef enum { + WR_STATE_FIND_HEAVIEST_FORK = 0, + WR_STATE_AGREE_ON_HEAVIEST_FORK = 1, + WR_STATE_DONE = 2 +} fd_wen_restart_stage_t; + +/* fd_restart_state_t contains all the states maintained by wen-restart. + It is allocated within the `unprivileged_init` of the replay tile. */ +struct fd_restart_state { + fd_wen_restart_stage_t stage; + + /* States existed before wen-restart */ + ulong root; + ulong total_stake; + ulong num_vote_accts; + fd_stake_weight_t stake_weights[ MAX_RESTART_PEERS ]; + + /* States maintained by the FIND_HEAVIEST_FORK stage of wen-restart */ + ulong total_active_stake; + ulong slot_to_stake[ LAST_VOTED_FORK_MAX_SLOTS ]; + uchar last_voted_fork_slots_received[ MAX_RESTART_PEERS ]; + + /* States maintained by the AGREE_ON_HEAVIEST_FORK stage of wen-restart */ + ulong heaviest_fork_slot; + fd_hash_t heaviest_fork_bank_hash; + ulong heaviest_fork_ready; + + ulong coordinator_heaviest_fork_slot; + fd_hash_t coordinator_heaviest_fork_bank_hash; + ulong coordinator_heaviest_fork_ready; +}; +typedef struct fd_restart_state fd_restart_state_t; + +/* fd_restart_state_{align,footprint} return the required alignment and + footprint of a memory region suitable for use as the wen-restart state. */ +FD_FN_CONST static inline ulong +fd_restart_state_align( void ) { + return alignof(fd_restart_state_t); +} + +FD_FN_CONST static inline ulong +fd_restart_state_footprint( void ) { + return sizeof(fd_restart_state_t); +} + +/* fd_restart_init is called in the replay tile after a snapshot is loaded. + The arguments of this function come from the loaded snapshot and provide + the first few fields in fd_restart_state_t. This function fills buf_out + and buf_len_out with a gossip message -- the first gossip message sent + in the wen-restart protocol (fd_gossip_restart_last_voted_fork_slots_t). */ +void +fd_restart_init( fd_restart_state_t * restart_state, + fd_vote_accounts_t const * accs, + fd_tower_t const * tower, + fd_slot_history_t const * slot_history, + fd_blockstore_t * blockstore, + uchar * buf_out, + ulong * buf_len_out ); + +/* fd_restart_recv_last_voted_fork_slots is called after receiving each + gossip message of type fd_gossip_restart_last_voted_fork_slots_t from + other validators. After receiving such messages from more than 80% + (WAIT_FOR_SUPERMAJORITY_THRESHOLD_PERCENT) stake, this function will + move wen-restart to the next stage, i.e., AGREE_ON_HEAVIEST_FORK. */ +void +fd_restart_recv_last_voted_fork_slots( fd_restart_state_t * restart_state, + fd_gossip_restart_last_voted_fork_slots_t * last_voted_msg ); + +#endif diff --git a/src/disco/topo/fd_topo.h b/src/disco/topo/fd_topo.h index 7931f8bee6..18bb7cfd11 100644 --- a/src/disco/topo/fd_topo.h +++ b/src/disco/topo/fd_topo.h @@ -227,6 +227,7 @@ typedef struct { char status_cache[ PATH_MAX ]; ulong tpool_thread_count; char cluster_version[ 32 ]; + int in_wen_restart; /* not specified by [tiles.replay] */ diff --git a/src/flamenco/gossip/fd_gossip.c b/src/flamenco/gossip/fd_gossip.c index 5506572b09..50ac6d992a 100644 --- a/src/flamenco/gossip/fd_gossip.c +++ b/src/flamenco/gossip/fd_gossip.c @@ -50,7 +50,7 @@ /* Sha256 pre-image size for pings/pongs */ #define FD_PING_PRE_IMAGE_SZ (48UL) /* Number of recognized CRDS enum members */ -#define FD_KNOWN_CRDS_ENUM_MAX (12UL) +#define FD_KNOWN_CRDS_ENUM_MAX (14UL) #define FD_NANOSEC_TO_MILLI(_ts_) ((ulong)(_ts_/1000000)) @@ -792,6 +792,14 @@ fd_gossip_sign_crds_value( fd_gossip_t * glob, fd_crds_value_t * crd ) { pubkey = &crd->data.inner.contact_info_v2.from; wallclock = &crd->data.inner.contact_info_v2.wallclock; break; + case fd_crds_data_enum_restart_last_voted_fork_slots: + pubkey = &crd->data.inner.restart_last_voted_fork_slots.from; + wallclock = &crd->data.inner.restart_last_voted_fork_slots.wallclock; + break; + case fd_crds_data_enum_restart_heaviest_fork: + pubkey = &crd->data.inner.restart_heaviest_fork.from; + wallclock = &crd->data.inner.restart_heaviest_fork.wallclock; + break; default: return; } @@ -1133,6 +1141,14 @@ fd_gossip_recv_crds_value(fd_gossip_t * glob, const fd_gossip_peer_addr_t * from pubkey = &crd->data.inner.contact_info_v2.from; wallclock = crd->data.inner.contact_info_v2.wallclock; break; + case fd_crds_data_enum_restart_last_voted_fork_slots: + pubkey = &crd->data.inner.restart_last_voted_fork_slots.from; + wallclock = crd->data.inner.restart_last_voted_fork_slots.wallclock; + break; + case fd_crds_data_enum_restart_heaviest_fork: + pubkey = &crd->data.inner.restart_heaviest_fork.from; + wallclock = crd->data.inner.restart_heaviest_fork.wallclock; + break; default: wallclock = FD_NANOSEC_TO_MILLI(glob->now); /* In millisecs */ break; diff --git a/src/flamenco/runtime/fd_blockstore.h b/src/flamenco/runtime/fd_blockstore.h index 0950d68d52..dd5fa654fa 100644 --- a/src/flamenco/runtime/fd_blockstore.h +++ b/src/flamenco/runtime/fd_blockstore.h @@ -290,6 +290,7 @@ struct __attribute__((aligned(FD_BLOCKSTORE_ALIGN))) fd_blockstore_private { ulong lps; /* latest processed slot */ ulong hcs; /* highest confirmed slot */ ulong smr; /* supermajority root. DO NOT MODIFY DIRECTLY, instead use fd_blockstore_publish */ + ulong restart_heaviest_fork_slot; /* the slot chosen in wen-restart as the slot to restart from */ /* Internal data structures */ diff --git a/src/flamenco/types/fd_type_names.c b/src/flamenco/types/fd_type_names.c index 92676d832c..d1e16f6f7b 100644 --- a/src/flamenco/types/fd_type_names.c +++ b/src/flamenco/types/fd_type_names.c @@ -1,5 +1,5 @@ // This is an auto-generated file. To add entries, edit fd_types.json -#define FD_TYPE_NAME_COUNT 216 +#define FD_TYPE_NAME_COUNT 224 static char const * fd_type_names[FD_TYPE_NAME_COUNT] = { "fd_hash", "fd_pubkey", @@ -184,6 +184,14 @@ static char const * fd_type_names[FD_TYPE_NAME_COUNT] = { "fd_gossip_incremental_snapshot_hashes", "fd_gossip_socket_entry", "fd_gossip_contact_info_v2", + "fd_restart_run_length_encoding_inner", + "fd_restart_run_length_encoding", + "fd_restart_raw_offsets_bitvec_u8_inner", + "fd_restart_raw_offsets_bitvec", + "fd_restart_raw_offsets", + "fd_restart_slots_offsets", + "fd_gossip_restart_last_voted_fork_slots", + "fd_gossip_restart_heaviest_fork", "fd_crds_data", "fd_crds_bloom", "fd_crds_filter", diff --git a/src/flamenco/types/fd_types.c b/src/flamenco/types/fd_types.c index d8754ba8dc..f0c2cd6892 100644 --- a/src/flamenco/types/fd_types.c +++ b/src/flamenco/types/fd_types.c @@ -25727,6 +25727,763 @@ ulong fd_gossip_contact_info_v2_size( fd_gossip_contact_info_v2_t const * self ) return size; } +int fd_restart_run_length_encoding_inner_decode( fd_restart_run_length_encoding_inner_t * self, fd_bincode_decode_ctx_t * ctx ) { + void const * data = ctx->data; + int err = fd_restart_run_length_encoding_inner_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + ctx->data = data; + if( !fd_is_null_alloc_virtual( ctx->valloc ) ) { + fd_restart_run_length_encoding_inner_new( self ); + } + fd_restart_run_length_encoding_inner_decode_unsafe( self, ctx ); + return FD_BINCODE_SUCCESS; +} +int fd_restart_run_length_encoding_inner_decode_preflight( fd_bincode_decode_ctx_t * ctx ) { + int err; + do { ushort _tmp; err = fd_bincode_compact_u16_decode( &_tmp, ctx ); } while(0); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + return FD_BINCODE_SUCCESS; +} +void fd_restart_run_length_encoding_inner_decode_unsafe( fd_restart_run_length_encoding_inner_t * self, fd_bincode_decode_ctx_t * ctx ) { + fd_bincode_compact_u16_decode_unsafe( &self->bits, ctx ); +} +int fd_restart_run_length_encoding_inner_encode( fd_restart_run_length_encoding_inner_t const * self, fd_bincode_encode_ctx_t * ctx ) { + int err; + err = fd_bincode_compact_u16_encode( &self->bits, ctx ); + if( FD_UNLIKELY( err ) ) return err; + return FD_BINCODE_SUCCESS; +} +int fd_restart_run_length_encoding_inner_decode_offsets( fd_restart_run_length_encoding_inner_off_t * self, fd_bincode_decode_ctx_t * ctx ) { + uchar const * data = ctx->data; + int err; + self->bits_off = (uint)( (ulong)ctx->data - (ulong)data ); + do { ushort _tmp; err = fd_bincode_compact_u16_decode( &_tmp, ctx ); } while(0); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + return FD_BINCODE_SUCCESS; +} +void fd_restart_run_length_encoding_inner_new(fd_restart_run_length_encoding_inner_t * self) { + fd_memset( self, 0, sizeof(fd_restart_run_length_encoding_inner_t) ); +} +void fd_restart_run_length_encoding_inner_destroy( fd_restart_run_length_encoding_inner_t * self, fd_bincode_destroy_ctx_t * ctx ) { +} + +ulong fd_restart_run_length_encoding_inner_footprint( void ){ return FD_RESTART_RUN_LENGTH_ENCODING_INNER_FOOTPRINT; } +ulong fd_restart_run_length_encoding_inner_align( void ){ return FD_RESTART_RUN_LENGTH_ENCODING_INNER_ALIGN; } + +void fd_restart_run_length_encoding_inner_walk( void * w, fd_restart_run_length_encoding_inner_t const * self, fd_types_walk_fn_t fun, const char *name, uint level ) { + fun( w, self, name, FD_FLAMENCO_TYPE_MAP, "fd_restart_run_length_encoding_inner", level++ ); + fun( w, &self->bits, "bits", FD_FLAMENCO_TYPE_USHORT, "ushort", level ); + fun( w, self, name, FD_FLAMENCO_TYPE_MAP_END, "fd_restart_run_length_encoding_inner", level-- ); +} +ulong fd_restart_run_length_encoding_inner_size( fd_restart_run_length_encoding_inner_t const * self ) { + ulong size = 0; + size += fd_bincode_compact_u16_size( &self->bits ); + return size; +} + +int fd_restart_run_length_encoding_decode( fd_restart_run_length_encoding_t * self, fd_bincode_decode_ctx_t * ctx ) { + void const * data = ctx->data; + int err = fd_restart_run_length_encoding_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + ctx->data = data; + if( !fd_is_null_alloc_virtual( ctx->valloc ) ) { + fd_restart_run_length_encoding_new( self ); + } + fd_restart_run_length_encoding_decode_unsafe( self, ctx ); + return FD_BINCODE_SUCCESS; +} +int fd_restart_run_length_encoding_decode_preflight( fd_bincode_decode_ctx_t * ctx ) { + int err; + ulong offsets_len; + err = fd_bincode_uint64_decode( &offsets_len, ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + if( offsets_len ) { + for( ulong i=0; i < offsets_len; i++ ) { + err = fd_restart_run_length_encoding_inner_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + } + } + return FD_BINCODE_SUCCESS; +} +void fd_restart_run_length_encoding_decode_unsafe( fd_restart_run_length_encoding_t * self, fd_bincode_decode_ctx_t * ctx ) { + fd_bincode_uint64_decode_unsafe( &self->offsets_len, ctx ); + if( self->offsets_len ) { + self->offsets = (fd_restart_run_length_encoding_inner_t *)fd_valloc_malloc( ctx->valloc, FD_RESTART_RUN_LENGTH_ENCODING_INNER_ALIGN, FD_RESTART_RUN_LENGTH_ENCODING_INNER_FOOTPRINT*self->offsets_len ); + for( ulong i=0; i < self->offsets_len; i++ ) { + fd_restart_run_length_encoding_inner_new( self->offsets + i ); + fd_restart_run_length_encoding_inner_decode_unsafe( self->offsets + i, ctx ); + } + } else + self->offsets = NULL; +} +int fd_restart_run_length_encoding_encode( fd_restart_run_length_encoding_t const * self, fd_bincode_encode_ctx_t * ctx ) { + int err; + err = fd_bincode_uint64_encode( self->offsets_len, ctx ); + if( FD_UNLIKELY(err) ) return err; + if( self->offsets_len ) { + for( ulong i=0; i < self->offsets_len; i++ ) { + err = fd_restart_run_length_encoding_inner_encode( self->offsets + i, ctx ); + if( FD_UNLIKELY( err ) ) return err; + } + } + return FD_BINCODE_SUCCESS; +} +int fd_restart_run_length_encoding_decode_offsets( fd_restart_run_length_encoding_off_t * self, fd_bincode_decode_ctx_t * ctx ) { + uchar const * data = ctx->data; + int err; + self->offsets_off = (uint)( (ulong)ctx->data - (ulong)data ); + ulong offsets_len; + err = fd_bincode_uint64_decode( &offsets_len, ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + if( offsets_len ) { + for( ulong i=0; i < offsets_len; i++ ) { + err = fd_restart_run_length_encoding_inner_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + } + } + return FD_BINCODE_SUCCESS; +} +void fd_restart_run_length_encoding_new(fd_restart_run_length_encoding_t * self) { + fd_memset( self, 0, sizeof(fd_restart_run_length_encoding_t) ); +} +void fd_restart_run_length_encoding_destroy( fd_restart_run_length_encoding_t * self, fd_bincode_destroy_ctx_t * ctx ) { + if( self->offsets ) { + for( ulong i=0; i < self->offsets_len; i++ ) + fd_restart_run_length_encoding_inner_destroy( self->offsets + i, ctx ); + fd_valloc_free( ctx->valloc, self->offsets ); + self->offsets = NULL; + } +} + +ulong fd_restart_run_length_encoding_footprint( void ){ return FD_RESTART_RUN_LENGTH_ENCODING_FOOTPRINT; } +ulong fd_restart_run_length_encoding_align( void ){ return FD_RESTART_RUN_LENGTH_ENCODING_ALIGN; } + +void fd_restart_run_length_encoding_walk( void * w, fd_restart_run_length_encoding_t const * self, fd_types_walk_fn_t fun, const char *name, uint level ) { + fun( w, self, name, FD_FLAMENCO_TYPE_MAP, "fd_restart_run_length_encoding", level++ ); + if( self->offsets_len ) { + fun( w, NULL, "offsets", FD_FLAMENCO_TYPE_ARR, "array", level++ ); + for( ulong i=0; i < self->offsets_len; i++ ) + fd_restart_run_length_encoding_inner_walk(w, self->offsets + i, fun, "restart_run_length_encoding_inner", level ); + fun( w, NULL, "offsets", FD_FLAMENCO_TYPE_ARR_END, "array", level-- ); + } + fun( w, self, name, FD_FLAMENCO_TYPE_MAP_END, "fd_restart_run_length_encoding", level-- ); +} +ulong fd_restart_run_length_encoding_size( fd_restart_run_length_encoding_t const * self ) { + ulong size = 0; + do { + size += sizeof(ulong); + for( ulong i=0; i < self->offsets_len; i++ ) + size += fd_restart_run_length_encoding_inner_size( self->offsets + i ); + } while(0); + return size; +} + +int fd_restart_raw_offsets_bitvec_u8_inner_decode( fd_restart_raw_offsets_bitvec_u8_inner_t * self, fd_bincode_decode_ctx_t * ctx ) { + void const * data = ctx->data; + int err = fd_restart_raw_offsets_bitvec_u8_inner_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + ctx->data = data; + if( !fd_is_null_alloc_virtual( ctx->valloc ) ) { + fd_restart_raw_offsets_bitvec_u8_inner_new( self ); + } + fd_restart_raw_offsets_bitvec_u8_inner_decode_unsafe( self, ctx ); + return FD_BINCODE_SUCCESS; +} +int fd_restart_raw_offsets_bitvec_u8_inner_decode_preflight( fd_bincode_decode_ctx_t * ctx ) { + int err; + ulong bits_len; + err = fd_bincode_uint64_decode( &bits_len, ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + if( bits_len ) { + err = fd_bincode_bytes_decode_preflight( bits_len, ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + } + return FD_BINCODE_SUCCESS; +} +void fd_restart_raw_offsets_bitvec_u8_inner_decode_unsafe( fd_restart_raw_offsets_bitvec_u8_inner_t * self, fd_bincode_decode_ctx_t * ctx ) { + fd_bincode_uint64_decode_unsafe( &self->bits_len, ctx ); + if( self->bits_len ) { + self->bits = fd_valloc_malloc( ctx->valloc, 8UL, self->bits_len ); + fd_bincode_bytes_decode_unsafe( self->bits, self->bits_len, ctx ); + } else + self->bits = NULL; +} +int fd_restart_raw_offsets_bitvec_u8_inner_encode( fd_restart_raw_offsets_bitvec_u8_inner_t const * self, fd_bincode_encode_ctx_t * ctx ) { + int err; + err = fd_bincode_uint64_encode( self->bits_len, ctx ); + if( FD_UNLIKELY(err) ) return err; + if( self->bits_len ) { + err = fd_bincode_bytes_encode( self->bits, self->bits_len, ctx ); + if( FD_UNLIKELY( err ) ) return err; + } + return FD_BINCODE_SUCCESS; +} +int fd_restart_raw_offsets_bitvec_u8_inner_decode_offsets( fd_restart_raw_offsets_bitvec_u8_inner_off_t * self, fd_bincode_decode_ctx_t * ctx ) { + uchar const * data = ctx->data; + int err; + self->bits_off = (uint)( (ulong)ctx->data - (ulong)data ); + ulong bits_len; + err = fd_bincode_uint64_decode( &bits_len, ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + if( bits_len ) { + err = fd_bincode_bytes_decode_preflight( bits_len, ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + } + return FD_BINCODE_SUCCESS; +} +void fd_restart_raw_offsets_bitvec_u8_inner_new(fd_restart_raw_offsets_bitvec_u8_inner_t * self) { + fd_memset( self, 0, sizeof(fd_restart_raw_offsets_bitvec_u8_inner_t) ); +} +void fd_restart_raw_offsets_bitvec_u8_inner_destroy( fd_restart_raw_offsets_bitvec_u8_inner_t * self, fd_bincode_destroy_ctx_t * ctx ) { + if( self->bits ) { + fd_valloc_free( ctx->valloc, self->bits ); + self->bits = NULL; + } +} + +ulong fd_restart_raw_offsets_bitvec_u8_inner_footprint( void ){ return FD_RESTART_RAW_OFFSETS_BITVEC_U8_INNER_FOOTPRINT; } +ulong fd_restart_raw_offsets_bitvec_u8_inner_align( void ){ return FD_RESTART_RAW_OFFSETS_BITVEC_U8_INNER_ALIGN; } + +void fd_restart_raw_offsets_bitvec_u8_inner_walk( void * w, fd_restart_raw_offsets_bitvec_u8_inner_t const * self, fd_types_walk_fn_t fun, const char *name, uint level ) { + fun( w, self, name, FD_FLAMENCO_TYPE_MAP, "fd_restart_raw_offsets_bitvec_u8_inner", level++ ); + fun(w, self->bits, "bits", FD_FLAMENCO_TYPE_UCHAR, "uchar", level ); + fun( w, self, name, FD_FLAMENCO_TYPE_MAP_END, "fd_restart_raw_offsets_bitvec_u8_inner", level-- ); +} +ulong fd_restart_raw_offsets_bitvec_u8_inner_size( fd_restart_raw_offsets_bitvec_u8_inner_t const * self ) { + ulong size = 0; + do { + size += sizeof(ulong); + size += self->bits_len; + } while(0); + return size; +} + +int fd_restart_raw_offsets_bitvec_decode( fd_restart_raw_offsets_bitvec_t * self, fd_bincode_decode_ctx_t * ctx ) { + void const * data = ctx->data; + int err = fd_restart_raw_offsets_bitvec_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + ctx->data = data; + if( !fd_is_null_alloc_virtual( ctx->valloc ) ) { + fd_restart_raw_offsets_bitvec_new( self ); + } + fd_restart_raw_offsets_bitvec_decode_unsafe( self, ctx ); + return FD_BINCODE_SUCCESS; +} +int fd_restart_raw_offsets_bitvec_decode_preflight( fd_bincode_decode_ctx_t * ctx ) { + int err; + { + uchar o; + err = fd_bincode_bool_decode( &o, ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + if( o ) { + err = fd_restart_raw_offsets_bitvec_u8_inner_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + } + } + err = fd_bincode_uint64_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + return FD_BINCODE_SUCCESS; +} +void fd_restart_raw_offsets_bitvec_decode_unsafe( fd_restart_raw_offsets_bitvec_t * self, fd_bincode_decode_ctx_t * ctx ) { + { + uchar o; + fd_bincode_bool_decode_unsafe( &o, ctx ); + self->has_bits = !!o; + if( o ) { + fd_restart_raw_offsets_bitvec_u8_inner_new( &self->bits ); + fd_restart_raw_offsets_bitvec_u8_inner_decode_unsafe( &self->bits, ctx ); + } + } + fd_bincode_uint64_decode_unsafe( &self->len, ctx ); +} +int fd_restart_raw_offsets_bitvec_encode( fd_restart_raw_offsets_bitvec_t const * self, fd_bincode_encode_ctx_t * ctx ) { + int err; + err = fd_bincode_bool_encode( self->has_bits, ctx ); + if( FD_UNLIKELY( err ) ) return err; + if( self->has_bits ) { + err = fd_restart_raw_offsets_bitvec_u8_inner_encode( &self->bits, ctx ); + if( FD_UNLIKELY( err ) ) return err; + } + err = fd_bincode_uint64_encode( self->len, ctx ); + if( FD_UNLIKELY( err ) ) return err; + return FD_BINCODE_SUCCESS; +} +int fd_restart_raw_offsets_bitvec_decode_offsets( fd_restart_raw_offsets_bitvec_off_t * self, fd_bincode_decode_ctx_t * ctx ) { + uchar const * data = ctx->data; + int err; + self->bits_off = (uint)( (ulong)ctx->data - (ulong)data ); + { + uchar o; + err = fd_bincode_bool_decode( &o, ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + if( o ) { + err = fd_restart_raw_offsets_bitvec_u8_inner_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + } + } + self->len_off = (uint)( (ulong)ctx->data - (ulong)data ); + err = fd_bincode_uint64_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + return FD_BINCODE_SUCCESS; +} +void fd_restart_raw_offsets_bitvec_new(fd_restart_raw_offsets_bitvec_t * self) { + fd_memset( self, 0, sizeof(fd_restart_raw_offsets_bitvec_t) ); +} +void fd_restart_raw_offsets_bitvec_destroy( fd_restart_raw_offsets_bitvec_t * self, fd_bincode_destroy_ctx_t * ctx ) { + if( self->has_bits ) { + fd_restart_raw_offsets_bitvec_u8_inner_destroy( &self->bits, ctx ); + self->has_bits = 0; + } +} + +ulong fd_restart_raw_offsets_bitvec_footprint( void ){ return FD_RESTART_RAW_OFFSETS_BITVEC_FOOTPRINT; } +ulong fd_restart_raw_offsets_bitvec_align( void ){ return FD_RESTART_RAW_OFFSETS_BITVEC_ALIGN; } + +void fd_restart_raw_offsets_bitvec_walk( void * w, fd_restart_raw_offsets_bitvec_t const * self, fd_types_walk_fn_t fun, const char *name, uint level ) { + fun( w, self, name, FD_FLAMENCO_TYPE_MAP, "fd_restart_raw_offsets_bitvec", level++ ); + if( !self->has_bits ) { + fun( w, NULL, "bits", FD_FLAMENCO_TYPE_NULL, "restart_raw_offsets_bitvec_u8_inner", level ); + } else { + fd_restart_raw_offsets_bitvec_u8_inner_walk( w, &self->bits, fun, "bits", level ); + } + fun( w, &self->len, "len", FD_FLAMENCO_TYPE_ULONG, "ulong", level ); + fun( w, self, name, FD_FLAMENCO_TYPE_MAP_END, "fd_restart_raw_offsets_bitvec", level-- ); +} +ulong fd_restart_raw_offsets_bitvec_size( fd_restart_raw_offsets_bitvec_t const * self ) { + ulong size = 0; + size += sizeof(char); + if( self->has_bits ) { + size += fd_restart_raw_offsets_bitvec_u8_inner_size( &self->bits ); + } + size += sizeof(ulong); + return size; +} + +int fd_restart_raw_offsets_decode( fd_restart_raw_offsets_t * self, fd_bincode_decode_ctx_t * ctx ) { + void const * data = ctx->data; + int err = fd_restart_raw_offsets_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + ctx->data = data; + if( !fd_is_null_alloc_virtual( ctx->valloc ) ) { + fd_restart_raw_offsets_new( self ); + } + fd_restart_raw_offsets_decode_unsafe( self, ctx ); + return FD_BINCODE_SUCCESS; +} +int fd_restart_raw_offsets_decode_preflight( fd_bincode_decode_ctx_t * ctx ) { + int err; + err = fd_restart_raw_offsets_bitvec_decode_preflight( ctx ); + if( FD_UNLIKELY( err ) ) return err; + return FD_BINCODE_SUCCESS; +} +void fd_restart_raw_offsets_decode_unsafe( fd_restart_raw_offsets_t * self, fd_bincode_decode_ctx_t * ctx ) { + fd_restart_raw_offsets_bitvec_decode_unsafe( &self->offsets, ctx ); +} +int fd_restart_raw_offsets_encode( fd_restart_raw_offsets_t const * self, fd_bincode_encode_ctx_t * ctx ) { + int err; + err = fd_restart_raw_offsets_bitvec_encode( &self->offsets, ctx ); + if( FD_UNLIKELY( err ) ) return err; + return FD_BINCODE_SUCCESS; +} +int fd_restart_raw_offsets_decode_offsets( fd_restart_raw_offsets_off_t * self, fd_bincode_decode_ctx_t * ctx ) { + uchar const * data = ctx->data; + int err; + self->offsets_off = (uint)( (ulong)ctx->data - (ulong)data ); + err = fd_restart_raw_offsets_bitvec_decode_preflight( ctx ); + if( FD_UNLIKELY( err ) ) return err; + return FD_BINCODE_SUCCESS; +} +void fd_restart_raw_offsets_new(fd_restart_raw_offsets_t * self) { + fd_memset( self, 0, sizeof(fd_restart_raw_offsets_t) ); + fd_restart_raw_offsets_bitvec_new( &self->offsets ); +} +void fd_restart_raw_offsets_destroy( fd_restart_raw_offsets_t * self, fd_bincode_destroy_ctx_t * ctx ) { + fd_restart_raw_offsets_bitvec_destroy( &self->offsets, ctx ); +} + +ulong fd_restart_raw_offsets_footprint( void ){ return FD_RESTART_RAW_OFFSETS_FOOTPRINT; } +ulong fd_restart_raw_offsets_align( void ){ return FD_RESTART_RAW_OFFSETS_ALIGN; } + +void fd_restart_raw_offsets_walk( void * w, fd_restart_raw_offsets_t const * self, fd_types_walk_fn_t fun, const char *name, uint level ) { + fun( w, self, name, FD_FLAMENCO_TYPE_MAP, "fd_restart_raw_offsets", level++ ); + fd_restart_raw_offsets_bitvec_walk( w, &self->offsets, fun, "offsets", level ); + fun( w, self, name, FD_FLAMENCO_TYPE_MAP_END, "fd_restart_raw_offsets", level-- ); +} +ulong fd_restart_raw_offsets_size( fd_restart_raw_offsets_t const * self ) { + ulong size = 0; + size += fd_restart_raw_offsets_bitvec_size( &self->offsets ); + return size; +} + +FD_FN_PURE uchar fd_restart_slots_offsets_is_run_length_encoding(fd_restart_slots_offsets_t const * self) { + return self->discriminant == 0; +} +FD_FN_PURE uchar fd_restart_slots_offsets_is_raw_offsets(fd_restart_slots_offsets_t const * self) { + return self->discriminant == 1; +} +void fd_restart_slots_offsets_inner_new( fd_restart_slots_offsets_inner_t * self, uint discriminant ); +int fd_restart_slots_offsets_inner_decode_preflight( uint discriminant, fd_bincode_decode_ctx_t * ctx ) { + int err; + switch (discriminant) { + case 0: { + err = fd_restart_run_length_encoding_decode_preflight( ctx ); + if( FD_UNLIKELY( err ) ) return err; + return FD_BINCODE_SUCCESS; + } + case 1: { + err = fd_restart_raw_offsets_decode_preflight( ctx ); + if( FD_UNLIKELY( err ) ) return err; + return FD_BINCODE_SUCCESS; + } + default: return FD_BINCODE_ERR_ENCODING; + } +} +void fd_restart_slots_offsets_inner_decode_unsafe( fd_restart_slots_offsets_inner_t * self, uint discriminant, fd_bincode_decode_ctx_t * ctx ) { + switch (discriminant) { + case 0: { + fd_restart_run_length_encoding_decode_unsafe( &self->run_length_encoding, ctx ); + break; + } + case 1: { + fd_restart_raw_offsets_decode_unsafe( &self->raw_offsets, ctx ); + break; + } + } +} +int fd_restart_slots_offsets_decode( fd_restart_slots_offsets_t * self, fd_bincode_decode_ctx_t * ctx ) { + void const * data = ctx->data; + int err = fd_restart_slots_offsets_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + ctx->data = data; + if( !fd_is_null_alloc_virtual( ctx->valloc ) ) { + fd_restart_slots_offsets_new( self ); + } + fd_restart_slots_offsets_decode_unsafe( self, ctx ); + return FD_BINCODE_SUCCESS; +} +int fd_restart_slots_offsets_decode_preflight( fd_bincode_decode_ctx_t * ctx ) { + uint discriminant = 0; + int err = fd_bincode_uint32_decode( &discriminant, ctx ); + if( FD_UNLIKELY( err ) ) return err; + return fd_restart_slots_offsets_inner_decode_preflight( discriminant, ctx ); +} +void fd_restart_slots_offsets_decode_unsafe( fd_restart_slots_offsets_t * self, fd_bincode_decode_ctx_t * ctx ) { + fd_bincode_uint32_decode_unsafe( &self->discriminant, ctx ); + fd_restart_slots_offsets_inner_decode_unsafe( &self->inner, self->discriminant, ctx ); +} +void fd_restart_slots_offsets_inner_new( fd_restart_slots_offsets_inner_t * self, uint discriminant ) { + switch( discriminant ) { + case 0: { + fd_restart_run_length_encoding_new( &self->run_length_encoding ); + break; + } + case 1: { + fd_restart_raw_offsets_new( &self->raw_offsets ); + break; + } + default: break; // FD_LOG_ERR(( "unhandled type")); + } +} +void fd_restart_slots_offsets_new_disc( fd_restart_slots_offsets_t * self, uint discriminant ) { + self->discriminant = discriminant; + fd_restart_slots_offsets_inner_new( &self->inner, self->discriminant ); +} +void fd_restart_slots_offsets_new( fd_restart_slots_offsets_t * self ) { + fd_memset( self, 0, sizeof(fd_restart_slots_offsets_t) ); + fd_restart_slots_offsets_new_disc( self, UINT_MAX ); +} +void fd_restart_slots_offsets_inner_destroy( fd_restart_slots_offsets_inner_t * self, uint discriminant, fd_bincode_destroy_ctx_t * ctx ) { + switch( discriminant ) { + case 0: { + fd_restart_run_length_encoding_destroy( &self->run_length_encoding, ctx ); + break; + } + case 1: { + fd_restart_raw_offsets_destroy( &self->raw_offsets, ctx ); + break; + } + default: break; // FD_LOG_ERR(( "unhandled type" )); + } +} +void fd_restart_slots_offsets_destroy( fd_restart_slots_offsets_t * self, fd_bincode_destroy_ctx_t * ctx ) { + fd_restart_slots_offsets_inner_destroy( &self->inner, self->discriminant, ctx ); +} + +ulong fd_restart_slots_offsets_footprint( void ){ return FD_RESTART_SLOTS_OFFSETS_FOOTPRINT; } +ulong fd_restart_slots_offsets_align( void ){ return FD_RESTART_SLOTS_OFFSETS_ALIGN; } + +void fd_restart_slots_offsets_walk( void * w, fd_restart_slots_offsets_t const * self, fd_types_walk_fn_t fun, const char *name, uint level ) { + fun(w, self, name, FD_FLAMENCO_TYPE_ENUM, "fd_restart_slots_offsets", level++); + switch( self->discriminant ) { + case 0: { + fun( w, self, "run_length_encoding", FD_FLAMENCO_TYPE_ENUM_DISC, "discriminant", level ); + fd_restart_run_length_encoding_walk( w, &self->inner.run_length_encoding, fun, "run_length_encoding", level ); + break; + } + case 1: { + fun( w, self, "raw_offsets", FD_FLAMENCO_TYPE_ENUM_DISC, "discriminant", level ); + fd_restart_raw_offsets_walk( w, &self->inner.raw_offsets, fun, "raw_offsets", level ); + break; + } + } + fun( w, self, name, FD_FLAMENCO_TYPE_ENUM_END, "fd_restart_slots_offsets", level-- ); +} +ulong fd_restart_slots_offsets_size( fd_restart_slots_offsets_t const * self ) { + ulong size = 0; + size += sizeof(uint); + switch (self->discriminant) { + case 0: { + size += fd_restart_run_length_encoding_size( &self->inner.run_length_encoding ); + break; + } + case 1: { + size += fd_restart_raw_offsets_size( &self->inner.raw_offsets ); + break; + } + } + return size; +} + +int fd_restart_slots_offsets_inner_encode( fd_restart_slots_offsets_inner_t const * self, uint discriminant, fd_bincode_encode_ctx_t * ctx ) { + int err; + switch (discriminant) { + case 0: { + err = fd_restart_run_length_encoding_encode( &self->run_length_encoding, ctx ); + if( FD_UNLIKELY( err ) ) return err; + break; + } + case 1: { + err = fd_restart_raw_offsets_encode( &self->raw_offsets, ctx ); + if( FD_UNLIKELY( err ) ) return err; + break; + } + } + return FD_BINCODE_SUCCESS; +} +int fd_restart_slots_offsets_encode( fd_restart_slots_offsets_t const * self, fd_bincode_encode_ctx_t * ctx ) { + int err = fd_bincode_uint32_encode( self->discriminant, ctx ); + if( FD_UNLIKELY( err ) ) return err; + return fd_restart_slots_offsets_inner_encode( &self->inner, self->discriminant, ctx ); +} + +int fd_gossip_restart_last_voted_fork_slots_decode( fd_gossip_restart_last_voted_fork_slots_t * self, fd_bincode_decode_ctx_t * ctx ) { + void const * data = ctx->data; + int err = fd_gossip_restart_last_voted_fork_slots_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + ctx->data = data; + if( !fd_is_null_alloc_virtual( ctx->valloc ) ) { + fd_gossip_restart_last_voted_fork_slots_new( self ); + } + fd_gossip_restart_last_voted_fork_slots_decode_unsafe( self, ctx ); + return FD_BINCODE_SUCCESS; +} +int fd_gossip_restart_last_voted_fork_slots_decode_preflight( fd_bincode_decode_ctx_t * ctx ) { + int err; + err = fd_bincode_bytes_decode_preflight( 32, ctx ); + if( FD_UNLIKELY( err ) ) return err; + err = fd_bincode_uint64_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + err = fd_restart_slots_offsets_decode_preflight( ctx ); + if( FD_UNLIKELY( err ) ) return err; + err = fd_bincode_uint64_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + err = fd_hash_decode_preflight( ctx ); + if( FD_UNLIKELY( err ) ) return err; + err = fd_bincode_uint16_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + return FD_BINCODE_SUCCESS; +} +void fd_gossip_restart_last_voted_fork_slots_decode_unsafe( fd_gossip_restart_last_voted_fork_slots_t * self, fd_bincode_decode_ctx_t * ctx ) { + fd_pubkey_decode_unsafe( &self->from, ctx ); + fd_bincode_uint64_decode_unsafe( &self->wallclock, ctx ); + fd_restart_slots_offsets_decode_unsafe( &self->offsets, ctx ); + fd_bincode_uint64_decode_unsafe( &self->last_voted_slot, ctx ); + fd_hash_decode_unsafe( &self->last_voted_hash, ctx ); + fd_bincode_uint16_decode_unsafe( &self->shred_version, ctx ); +} +int fd_gossip_restart_last_voted_fork_slots_encode( fd_gossip_restart_last_voted_fork_slots_t const * self, fd_bincode_encode_ctx_t * ctx ) { + int err; + err = fd_pubkey_encode( &self->from, ctx ); + if( FD_UNLIKELY( err ) ) return err; + err = fd_bincode_uint64_encode( self->wallclock, ctx ); + if( FD_UNLIKELY( err ) ) return err; + err = fd_restart_slots_offsets_encode( &self->offsets, ctx ); + if( FD_UNLIKELY( err ) ) return err; + err = fd_bincode_uint64_encode( self->last_voted_slot, ctx ); + if( FD_UNLIKELY( err ) ) return err; + err = fd_hash_encode( &self->last_voted_hash, ctx ); + if( FD_UNLIKELY( err ) ) return err; + err = fd_bincode_uint16_encode( self->shred_version, ctx ); + if( FD_UNLIKELY( err ) ) return err; + return FD_BINCODE_SUCCESS; +} +int fd_gossip_restart_last_voted_fork_slots_decode_offsets( fd_gossip_restart_last_voted_fork_slots_off_t * self, fd_bincode_decode_ctx_t * ctx ) { + uchar const * data = ctx->data; + int err; + self->from_off = (uint)( (ulong)ctx->data - (ulong)data ); + err = fd_bincode_bytes_decode_preflight( 32, ctx ); + if( FD_UNLIKELY( err ) ) return err; + self->wallclock_off = (uint)( (ulong)ctx->data - (ulong)data ); + err = fd_bincode_uint64_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + self->offsets_off = (uint)( (ulong)ctx->data - (ulong)data ); + err = fd_restart_slots_offsets_decode_preflight( ctx ); + if( FD_UNLIKELY( err ) ) return err; + self->last_voted_slot_off = (uint)( (ulong)ctx->data - (ulong)data ); + err = fd_bincode_uint64_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + self->last_voted_hash_off = (uint)( (ulong)ctx->data - (ulong)data ); + err = fd_hash_decode_preflight( ctx ); + if( FD_UNLIKELY( err ) ) return err; + self->shred_version_off = (uint)( (ulong)ctx->data - (ulong)data ); + err = fd_bincode_uint16_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + return FD_BINCODE_SUCCESS; +} +void fd_gossip_restart_last_voted_fork_slots_new(fd_gossip_restart_last_voted_fork_slots_t * self) { + fd_memset( self, 0, sizeof(fd_gossip_restart_last_voted_fork_slots_t) ); + fd_pubkey_new( &self->from ); + fd_restart_slots_offsets_new( &self->offsets ); + fd_hash_new( &self->last_voted_hash ); +} +void fd_gossip_restart_last_voted_fork_slots_destroy( fd_gossip_restart_last_voted_fork_slots_t * self, fd_bincode_destroy_ctx_t * ctx ) { + fd_pubkey_destroy( &self->from, ctx ); + fd_restart_slots_offsets_destroy( &self->offsets, ctx ); + fd_hash_destroy( &self->last_voted_hash, ctx ); +} + +ulong fd_gossip_restart_last_voted_fork_slots_footprint( void ){ return FD_GOSSIP_RESTART_LAST_VOTED_FORK_SLOTS_FOOTPRINT; } +ulong fd_gossip_restart_last_voted_fork_slots_align( void ){ return FD_GOSSIP_RESTART_LAST_VOTED_FORK_SLOTS_ALIGN; } + +void fd_gossip_restart_last_voted_fork_slots_walk( void * w, fd_gossip_restart_last_voted_fork_slots_t const * self, fd_types_walk_fn_t fun, const char *name, uint level ) { + fun( w, self, name, FD_FLAMENCO_TYPE_MAP, "fd_gossip_restart_last_voted_fork_slots", level++ ); + fd_pubkey_walk( w, &self->from, fun, "from", level ); + fun( w, &self->wallclock, "wallclock", FD_FLAMENCO_TYPE_ULONG, "ulong", level ); + fd_restart_slots_offsets_walk( w, &self->offsets, fun, "offsets", level ); + fun( w, &self->last_voted_slot, "last_voted_slot", FD_FLAMENCO_TYPE_ULONG, "ulong", level ); + fd_hash_walk( w, &self->last_voted_hash, fun, "last_voted_hash", level ); + fun( w, &self->shred_version, "shred_version", FD_FLAMENCO_TYPE_USHORT, "ushort", level ); + fun( w, self, name, FD_FLAMENCO_TYPE_MAP_END, "fd_gossip_restart_last_voted_fork_slots", level-- ); +} +ulong fd_gossip_restart_last_voted_fork_slots_size( fd_gossip_restart_last_voted_fork_slots_t const * self ) { + ulong size = 0; + size += fd_pubkey_size( &self->from ); + size += sizeof(ulong); + size += fd_restart_slots_offsets_size( &self->offsets ); + size += sizeof(ulong); + size += fd_hash_size( &self->last_voted_hash ); + size += sizeof(ushort); + return size; +} + +int fd_gossip_restart_heaviest_fork_decode( fd_gossip_restart_heaviest_fork_t * self, fd_bincode_decode_ctx_t * ctx ) { + void const * data = ctx->data; + int err = fd_gossip_restart_heaviest_fork_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + ctx->data = data; + if( !fd_is_null_alloc_virtual( ctx->valloc ) ) { + fd_gossip_restart_heaviest_fork_new( self ); + } + fd_gossip_restart_heaviest_fork_decode_unsafe( self, ctx ); + return FD_BINCODE_SUCCESS; +} +int fd_gossip_restart_heaviest_fork_decode_preflight( fd_bincode_decode_ctx_t * ctx ) { + int err; + err = fd_bincode_bytes_decode_preflight( 32, ctx ); + if( FD_UNLIKELY( err ) ) return err; + err = fd_bincode_uint64_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + err = fd_bincode_uint64_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + err = fd_hash_decode_preflight( ctx ); + if( FD_UNLIKELY( err ) ) return err; + err = fd_bincode_uint64_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + err = fd_bincode_uint16_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + return FD_BINCODE_SUCCESS; +} +void fd_gossip_restart_heaviest_fork_decode_unsafe( fd_gossip_restart_heaviest_fork_t * self, fd_bincode_decode_ctx_t * ctx ) { + fd_pubkey_decode_unsafe( &self->from, ctx ); + fd_bincode_uint64_decode_unsafe( &self->wallclock, ctx ); + fd_bincode_uint64_decode_unsafe( &self->last_slot, ctx ); + fd_hash_decode_unsafe( &self->last_slot_hash, ctx ); + fd_bincode_uint64_decode_unsafe( &self->observed_stake, ctx ); + fd_bincode_uint16_decode_unsafe( &self->shred_version, ctx ); +} +int fd_gossip_restart_heaviest_fork_encode( fd_gossip_restart_heaviest_fork_t const * self, fd_bincode_encode_ctx_t * ctx ) { + int err; + err = fd_pubkey_encode( &self->from, ctx ); + if( FD_UNLIKELY( err ) ) return err; + err = fd_bincode_uint64_encode( self->wallclock, ctx ); + if( FD_UNLIKELY( err ) ) return err; + err = fd_bincode_uint64_encode( self->last_slot, ctx ); + if( FD_UNLIKELY( err ) ) return err; + err = fd_hash_encode( &self->last_slot_hash, ctx ); + if( FD_UNLIKELY( err ) ) return err; + err = fd_bincode_uint64_encode( self->observed_stake, ctx ); + if( FD_UNLIKELY( err ) ) return err; + err = fd_bincode_uint16_encode( self->shred_version, ctx ); + if( FD_UNLIKELY( err ) ) return err; + return FD_BINCODE_SUCCESS; +} +int fd_gossip_restart_heaviest_fork_decode_offsets( fd_gossip_restart_heaviest_fork_off_t * self, fd_bincode_decode_ctx_t * ctx ) { + uchar const * data = ctx->data; + int err; + self->from_off = (uint)( (ulong)ctx->data - (ulong)data ); + err = fd_bincode_bytes_decode_preflight( 32, ctx ); + if( FD_UNLIKELY( err ) ) return err; + self->wallclock_off = (uint)( (ulong)ctx->data - (ulong)data ); + err = fd_bincode_uint64_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + self->last_slot_off = (uint)( (ulong)ctx->data - (ulong)data ); + err = fd_bincode_uint64_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + self->last_slot_hash_off = (uint)( (ulong)ctx->data - (ulong)data ); + err = fd_hash_decode_preflight( ctx ); + if( FD_UNLIKELY( err ) ) return err; + self->observed_stake_off = (uint)( (ulong)ctx->data - (ulong)data ); + err = fd_bincode_uint64_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + self->shred_version_off = (uint)( (ulong)ctx->data - (ulong)data ); + err = fd_bincode_uint16_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + return FD_BINCODE_SUCCESS; +} +void fd_gossip_restart_heaviest_fork_new(fd_gossip_restart_heaviest_fork_t * self) { + fd_memset( self, 0, sizeof(fd_gossip_restart_heaviest_fork_t) ); + fd_pubkey_new( &self->from ); + fd_hash_new( &self->last_slot_hash ); +} +void fd_gossip_restart_heaviest_fork_destroy( fd_gossip_restart_heaviest_fork_t * self, fd_bincode_destroy_ctx_t * ctx ) { + fd_pubkey_destroy( &self->from, ctx ); + fd_hash_destroy( &self->last_slot_hash, ctx ); +} + +ulong fd_gossip_restart_heaviest_fork_footprint( void ){ return FD_GOSSIP_RESTART_HEAVIEST_FORK_FOOTPRINT; } +ulong fd_gossip_restart_heaviest_fork_align( void ){ return FD_GOSSIP_RESTART_HEAVIEST_FORK_ALIGN; } + +void fd_gossip_restart_heaviest_fork_walk( void * w, fd_gossip_restart_heaviest_fork_t const * self, fd_types_walk_fn_t fun, const char *name, uint level ) { + fun( w, self, name, FD_FLAMENCO_TYPE_MAP, "fd_gossip_restart_heaviest_fork", level++ ); + fd_pubkey_walk( w, &self->from, fun, "from", level ); + fun( w, &self->wallclock, "wallclock", FD_FLAMENCO_TYPE_ULONG, "ulong", level ); + fun( w, &self->last_slot, "last_slot", FD_FLAMENCO_TYPE_ULONG, "ulong", level ); + fd_hash_walk( w, &self->last_slot_hash, fun, "last_slot_hash", level ); + fun( w, &self->observed_stake, "observed_stake", FD_FLAMENCO_TYPE_ULONG, "ulong", level ); + fun( w, &self->shred_version, "shred_version", FD_FLAMENCO_TYPE_USHORT, "ushort", level ); + fun( w, self, name, FD_FLAMENCO_TYPE_MAP_END, "fd_gossip_restart_heaviest_fork", level-- ); +} +ulong fd_gossip_restart_heaviest_fork_size( fd_gossip_restart_heaviest_fork_t const * self ) { + ulong size = 0; + size += fd_pubkey_size( &self->from ); + size += sizeof(ulong); + size += sizeof(ulong); + size += fd_hash_size( &self->last_slot_hash ); + size += sizeof(ulong); + size += sizeof(ushort); + return size; +} + FD_FN_PURE uchar fd_crds_data_is_contact_info_v1(fd_crds_data_t const * self) { return self->discriminant == 0; } @@ -25763,6 +26520,12 @@ FD_FN_PURE uchar fd_crds_data_is_incremental_snapshot_hashes(fd_crds_data_t cons FD_FN_PURE uchar fd_crds_data_is_contact_info_v2(fd_crds_data_t const * self) { return self->discriminant == 11; } +FD_FN_PURE uchar fd_crds_data_is_restart_last_voted_fork_slots(fd_crds_data_t const * self) { + return self->discriminant == 12; +} +FD_FN_PURE uchar fd_crds_data_is_restart_heaviest_fork(fd_crds_data_t const * self) { + return self->discriminant == 13; +} void fd_crds_data_inner_new( fd_crds_data_inner_t * self, uint discriminant ); int fd_crds_data_inner_decode_preflight( uint discriminant, fd_bincode_decode_ctx_t * ctx ) { int err; @@ -25827,6 +26590,16 @@ int fd_crds_data_inner_decode_preflight( uint discriminant, fd_bincode_decode_ct if( FD_UNLIKELY( err ) ) return err; return FD_BINCODE_SUCCESS; } + case 12: { + err = fd_gossip_restart_last_voted_fork_slots_decode_preflight( ctx ); + if( FD_UNLIKELY( err ) ) return err; + return FD_BINCODE_SUCCESS; + } + case 13: { + err = fd_gossip_restart_heaviest_fork_decode_preflight( ctx ); + if( FD_UNLIKELY( err ) ) return err; + return FD_BINCODE_SUCCESS; + } default: return FD_BINCODE_ERR_ENCODING; } } @@ -25880,6 +26653,14 @@ void fd_crds_data_inner_decode_unsafe( fd_crds_data_inner_t * self, uint discrim fd_gossip_contact_info_v2_decode_unsafe( &self->contact_info_v2, ctx ); break; } + case 12: { + fd_gossip_restart_last_voted_fork_slots_decode_unsafe( &self->restart_last_voted_fork_slots, ctx ); + break; + } + case 13: { + fd_gossip_restart_heaviest_fork_decode_unsafe( &self->restart_heaviest_fork, ctx ); + break; + } } } int fd_crds_data_decode( fd_crds_data_t * self, fd_bincode_decode_ctx_t * ctx ) { @@ -25953,6 +26734,14 @@ void fd_crds_data_inner_new( fd_crds_data_inner_t * self, uint discriminant ) { fd_gossip_contact_info_v2_new( &self->contact_info_v2 ); break; } + case 12: { + fd_gossip_restart_last_voted_fork_slots_new( &self->restart_last_voted_fork_slots ); + break; + } + case 13: { + fd_gossip_restart_heaviest_fork_new( &self->restart_heaviest_fork ); + break; + } default: break; // FD_LOG_ERR(( "unhandled type")); } } @@ -26014,6 +26803,14 @@ void fd_crds_data_inner_destroy( fd_crds_data_inner_t * self, uint discriminant, fd_gossip_contact_info_v2_destroy( &self->contact_info_v2, ctx ); break; } + case 12: { + fd_gossip_restart_last_voted_fork_slots_destroy( &self->restart_last_voted_fork_slots, ctx ); + break; + } + case 13: { + fd_gossip_restart_heaviest_fork_destroy( &self->restart_heaviest_fork, ctx ); + break; + } default: break; // FD_LOG_ERR(( "unhandled type" )); } } @@ -26087,6 +26884,16 @@ void fd_crds_data_walk( void * w, fd_crds_data_t const * self, fd_types_walk_fn_ fd_gossip_contact_info_v2_walk( w, &self->inner.contact_info_v2, fun, "contact_info_v2", level ); break; } + case 12: { + fun( w, self, "restart_last_voted_fork_slots", FD_FLAMENCO_TYPE_ENUM_DISC, "discriminant", level ); + fd_gossip_restart_last_voted_fork_slots_walk( w, &self->inner.restart_last_voted_fork_slots, fun, "restart_last_voted_fork_slots", level ); + break; + } + case 13: { + fun( w, self, "restart_heaviest_fork", FD_FLAMENCO_TYPE_ENUM_DISC, "discriminant", level ); + fd_gossip_restart_heaviest_fork_walk( w, &self->inner.restart_heaviest_fork, fun, "restart_heaviest_fork", level ); + break; + } } fun( w, self, name, FD_FLAMENCO_TYPE_ENUM_END, "fd_crds_data", level-- ); } @@ -26142,6 +26949,14 @@ ulong fd_crds_data_size( fd_crds_data_t const * self ) { size += fd_gossip_contact_info_v2_size( &self->inner.contact_info_v2 ); break; } + case 12: { + size += fd_gossip_restart_last_voted_fork_slots_size( &self->inner.restart_last_voted_fork_slots ); + break; + } + case 13: { + size += fd_gossip_restart_heaviest_fork_size( &self->inner.restart_heaviest_fork ); + break; + } } return size; } @@ -26209,6 +27024,16 @@ int fd_crds_data_inner_encode( fd_crds_data_inner_t const * self, uint discrimin if( FD_UNLIKELY( err ) ) return err; break; } + case 12: { + err = fd_gossip_restart_last_voted_fork_slots_encode( &self->restart_last_voted_fork_slots, ctx ); + if( FD_UNLIKELY( err ) ) return err; + break; + } + case 13: { + err = fd_gossip_restart_heaviest_fork_encode( &self->restart_heaviest_fork, ctx ); + if( FD_UNLIKELY( err ) ) return err; + break; + } } return FD_BINCODE_SUCCESS; } diff --git a/src/flamenco/types/fd_types.h b/src/flamenco/types/fd_types.h index 68ba401793..7a6fe1a67c 100644 --- a/src/flamenco/types/fd_types.h +++ b/src/flamenco/types/fd_types.h @@ -4124,6 +4124,150 @@ typedef struct fd_gossip_contact_info_v2_off fd_gossip_contact_info_v2_off_t; #define FD_GOSSIP_CONTACT_INFO_V2_OFF_FOOTPRINT sizeof(fd_gossip_contact_info_v2_off_t) #define FD_GOSSIP_CONTACT_INFO_V2_OFF_ALIGN (8UL) +/* Encoded Size: Dynamic */ +struct __attribute__((aligned(8UL))) fd_restart_run_length_encoding_inner { + ushort bits; +}; +typedef struct fd_restart_run_length_encoding_inner fd_restart_run_length_encoding_inner_t; +#define FD_RESTART_RUN_LENGTH_ENCODING_INNER_FOOTPRINT sizeof(fd_restart_run_length_encoding_inner_t) +#define FD_RESTART_RUN_LENGTH_ENCODING_INNER_ALIGN (8UL) + +struct __attribute__((aligned(8UL))) fd_restart_run_length_encoding_inner_off { + uint bits_off; +}; +typedef struct fd_restart_run_length_encoding_inner_off fd_restart_run_length_encoding_inner_off_t; +#define FD_RESTART_RUN_LENGTH_ENCODING_INNER_OFF_FOOTPRINT sizeof(fd_restart_run_length_encoding_inner_off_t) +#define FD_RESTART_RUN_LENGTH_ENCODING_INNER_OFF_ALIGN (8UL) + +/* Encoded Size: Dynamic */ +struct __attribute__((aligned(8UL))) fd_restart_run_length_encoding { + ulong offsets_len; + fd_restart_run_length_encoding_inner_t * offsets; +}; +typedef struct fd_restart_run_length_encoding fd_restart_run_length_encoding_t; +#define FD_RESTART_RUN_LENGTH_ENCODING_FOOTPRINT sizeof(fd_restart_run_length_encoding_t) +#define FD_RESTART_RUN_LENGTH_ENCODING_ALIGN (8UL) + +struct __attribute__((aligned(8UL))) fd_restart_run_length_encoding_off { + uint offsets_off; +}; +typedef struct fd_restart_run_length_encoding_off fd_restart_run_length_encoding_off_t; +#define FD_RESTART_RUN_LENGTH_ENCODING_OFF_FOOTPRINT sizeof(fd_restart_run_length_encoding_off_t) +#define FD_RESTART_RUN_LENGTH_ENCODING_OFF_ALIGN (8UL) + +/* Encoded Size: Dynamic */ +struct __attribute__((aligned(8UL))) fd_restart_raw_offsets_bitvec_u8_inner { + ulong bits_len; + uchar* bits; +}; +typedef struct fd_restart_raw_offsets_bitvec_u8_inner fd_restart_raw_offsets_bitvec_u8_inner_t; +#define FD_RESTART_RAW_OFFSETS_BITVEC_U8_INNER_FOOTPRINT sizeof(fd_restart_raw_offsets_bitvec_u8_inner_t) +#define FD_RESTART_RAW_OFFSETS_BITVEC_U8_INNER_ALIGN (8UL) + +struct __attribute__((aligned(8UL))) fd_restart_raw_offsets_bitvec_u8_inner_off { + uint bits_off; +}; +typedef struct fd_restart_raw_offsets_bitvec_u8_inner_off fd_restart_raw_offsets_bitvec_u8_inner_off_t; +#define FD_RESTART_RAW_OFFSETS_BITVEC_U8_INNER_OFF_FOOTPRINT sizeof(fd_restart_raw_offsets_bitvec_u8_inner_off_t) +#define FD_RESTART_RAW_OFFSETS_BITVEC_U8_INNER_OFF_ALIGN (8UL) + +/* Encoded Size: Dynamic */ +struct __attribute__((aligned(8UL))) fd_restart_raw_offsets_bitvec { + fd_restart_raw_offsets_bitvec_u8_inner_t bits; + uchar has_bits; + ulong len; +}; +typedef struct fd_restart_raw_offsets_bitvec fd_restart_raw_offsets_bitvec_t; +#define FD_RESTART_RAW_OFFSETS_BITVEC_FOOTPRINT sizeof(fd_restart_raw_offsets_bitvec_t) +#define FD_RESTART_RAW_OFFSETS_BITVEC_ALIGN (8UL) + +struct __attribute__((aligned(8UL))) fd_restart_raw_offsets_bitvec_off { + uint bits_off; + uint len_off; +}; +typedef struct fd_restart_raw_offsets_bitvec_off fd_restart_raw_offsets_bitvec_off_t; +#define FD_RESTART_RAW_OFFSETS_BITVEC_OFF_FOOTPRINT sizeof(fd_restart_raw_offsets_bitvec_off_t) +#define FD_RESTART_RAW_OFFSETS_BITVEC_OFF_ALIGN (8UL) + +/* Encoded Size: Dynamic */ +struct __attribute__((aligned(8UL))) fd_restart_raw_offsets { + fd_restart_raw_offsets_bitvec_t offsets; +}; +typedef struct fd_restart_raw_offsets fd_restart_raw_offsets_t; +#define FD_RESTART_RAW_OFFSETS_FOOTPRINT sizeof(fd_restart_raw_offsets_t) +#define FD_RESTART_RAW_OFFSETS_ALIGN (8UL) + +struct __attribute__((aligned(8UL))) fd_restart_raw_offsets_off { + uint offsets_off; +}; +typedef struct fd_restart_raw_offsets_off fd_restart_raw_offsets_off_t; +#define FD_RESTART_RAW_OFFSETS_OFF_FOOTPRINT sizeof(fd_restart_raw_offsets_off_t) +#define FD_RESTART_RAW_OFFSETS_OFF_ALIGN (8UL) + +union fd_restart_slots_offsets_inner { + fd_restart_run_length_encoding_t run_length_encoding; + fd_restart_raw_offsets_t raw_offsets; +}; +typedef union fd_restart_slots_offsets_inner fd_restart_slots_offsets_inner_t; + +struct fd_restart_slots_offsets { + uint discriminant; + fd_restart_slots_offsets_inner_t inner; +}; +typedef struct fd_restart_slots_offsets fd_restart_slots_offsets_t; +#define FD_RESTART_SLOTS_OFFSETS_FOOTPRINT sizeof(fd_restart_slots_offsets_t) +#define FD_RESTART_SLOTS_OFFSETS_ALIGN (8UL) + +/* Encoded Size: Dynamic */ +struct __attribute__((aligned(8UL))) fd_gossip_restart_last_voted_fork_slots { + fd_pubkey_t from; + ulong wallclock; + fd_restart_slots_offsets_t offsets; + ulong last_voted_slot; + fd_hash_t last_voted_hash; + ushort shred_version; +}; +typedef struct fd_gossip_restart_last_voted_fork_slots fd_gossip_restart_last_voted_fork_slots_t; +#define FD_GOSSIP_RESTART_LAST_VOTED_FORK_SLOTS_FOOTPRINT sizeof(fd_gossip_restart_last_voted_fork_slots_t) +#define FD_GOSSIP_RESTART_LAST_VOTED_FORK_SLOTS_ALIGN (8UL) + +struct __attribute__((aligned(8UL))) fd_gossip_restart_last_voted_fork_slots_off { + uint from_off; + uint wallclock_off; + uint offsets_off; + uint last_voted_slot_off; + uint last_voted_hash_off; + uint shred_version_off; +}; +typedef struct fd_gossip_restart_last_voted_fork_slots_off fd_gossip_restart_last_voted_fork_slots_off_t; +#define FD_GOSSIP_RESTART_LAST_VOTED_FORK_SLOTS_OFF_FOOTPRINT sizeof(fd_gossip_restart_last_voted_fork_slots_off_t) +#define FD_GOSSIP_RESTART_LAST_VOTED_FORK_SLOTS_OFF_ALIGN (8UL) + +/* Encoded Size: Dynamic */ +struct __attribute__((aligned(8UL))) fd_gossip_restart_heaviest_fork { + fd_pubkey_t from; + ulong wallclock; + ulong last_slot; + fd_hash_t last_slot_hash; + ulong observed_stake; + ushort shred_version; +}; +typedef struct fd_gossip_restart_heaviest_fork fd_gossip_restart_heaviest_fork_t; +#define FD_GOSSIP_RESTART_HEAVIEST_FORK_FOOTPRINT sizeof(fd_gossip_restart_heaviest_fork_t) +#define FD_GOSSIP_RESTART_HEAVIEST_FORK_ALIGN (8UL) + +struct __attribute__((aligned(8UL))) fd_gossip_restart_heaviest_fork_off { + uint from_off; + uint wallclock_off; + uint last_slot_off; + uint last_slot_hash_off; + uint observed_stake_off; + uint shred_version_off; +}; +typedef struct fd_gossip_restart_heaviest_fork_off fd_gossip_restart_heaviest_fork_off_t; +#define FD_GOSSIP_RESTART_HEAVIEST_FORK_OFF_FOOTPRINT sizeof(fd_gossip_restart_heaviest_fork_off_t) +#define FD_GOSSIP_RESTART_HEAVIEST_FORK_OFF_ALIGN (8UL) + union fd_crds_data_inner { fd_gossip_contact_info_v1_t contact_info_v1; fd_gossip_vote_t vote; @@ -4137,6 +4281,8 @@ union fd_crds_data_inner { fd_gossip_duplicate_shred_t duplicate_shred; fd_gossip_incremental_snapshot_hashes_t incremental_snapshot_hashes; fd_gossip_contact_info_v2_t contact_info_v2; + fd_gossip_restart_last_voted_fork_slots_t restart_last_voted_fork_slots; + fd_gossip_restart_heaviest_fork_t restart_heaviest_fork; }; typedef union fd_crds_data_inner fd_crds_data_inner_t; @@ -7257,6 +7403,108 @@ ulong fd_gossip_contact_info_v2_size( fd_gossip_contact_info_v2_t const * self ) ulong fd_gossip_contact_info_v2_footprint( void ); ulong fd_gossip_contact_info_v2_align( void ); +void fd_restart_run_length_encoding_inner_new( fd_restart_run_length_encoding_inner_t * self ); +int fd_restart_run_length_encoding_inner_decode( fd_restart_run_length_encoding_inner_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_restart_run_length_encoding_inner_decode_preflight( fd_bincode_decode_ctx_t * ctx ); +void fd_restart_run_length_encoding_inner_decode_unsafe( fd_restart_run_length_encoding_inner_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_restart_run_length_encoding_inner_decode_offsets( fd_restart_run_length_encoding_inner_off_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_restart_run_length_encoding_inner_encode( fd_restart_run_length_encoding_inner_t const * self, fd_bincode_encode_ctx_t * ctx ); +void fd_restart_run_length_encoding_inner_destroy( fd_restart_run_length_encoding_inner_t * self, fd_bincode_destroy_ctx_t * ctx ); +void fd_restart_run_length_encoding_inner_walk( void * w, fd_restart_run_length_encoding_inner_t const * self, fd_types_walk_fn_t fun, const char *name, uint level ); +ulong fd_restart_run_length_encoding_inner_size( fd_restart_run_length_encoding_inner_t const * self ); +ulong fd_restart_run_length_encoding_inner_footprint( void ); +ulong fd_restart_run_length_encoding_inner_align( void ); + +void fd_restart_run_length_encoding_new( fd_restart_run_length_encoding_t * self ); +int fd_restart_run_length_encoding_decode( fd_restart_run_length_encoding_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_restart_run_length_encoding_decode_preflight( fd_bincode_decode_ctx_t * ctx ); +void fd_restart_run_length_encoding_decode_unsafe( fd_restart_run_length_encoding_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_restart_run_length_encoding_decode_offsets( fd_restart_run_length_encoding_off_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_restart_run_length_encoding_encode( fd_restart_run_length_encoding_t const * self, fd_bincode_encode_ctx_t * ctx ); +void fd_restart_run_length_encoding_destroy( fd_restart_run_length_encoding_t * self, fd_bincode_destroy_ctx_t * ctx ); +void fd_restart_run_length_encoding_walk( void * w, fd_restart_run_length_encoding_t const * self, fd_types_walk_fn_t fun, const char *name, uint level ); +ulong fd_restart_run_length_encoding_size( fd_restart_run_length_encoding_t const * self ); +ulong fd_restart_run_length_encoding_footprint( void ); +ulong fd_restart_run_length_encoding_align( void ); + +void fd_restart_raw_offsets_bitvec_u8_inner_new( fd_restart_raw_offsets_bitvec_u8_inner_t * self ); +int fd_restart_raw_offsets_bitvec_u8_inner_decode( fd_restart_raw_offsets_bitvec_u8_inner_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_restart_raw_offsets_bitvec_u8_inner_decode_preflight( fd_bincode_decode_ctx_t * ctx ); +void fd_restart_raw_offsets_bitvec_u8_inner_decode_unsafe( fd_restart_raw_offsets_bitvec_u8_inner_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_restart_raw_offsets_bitvec_u8_inner_decode_offsets( fd_restart_raw_offsets_bitvec_u8_inner_off_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_restart_raw_offsets_bitvec_u8_inner_encode( fd_restart_raw_offsets_bitvec_u8_inner_t const * self, fd_bincode_encode_ctx_t * ctx ); +void fd_restart_raw_offsets_bitvec_u8_inner_destroy( fd_restart_raw_offsets_bitvec_u8_inner_t * self, fd_bincode_destroy_ctx_t * ctx ); +void fd_restart_raw_offsets_bitvec_u8_inner_walk( void * w, fd_restart_raw_offsets_bitvec_u8_inner_t const * self, fd_types_walk_fn_t fun, const char *name, uint level ); +ulong fd_restart_raw_offsets_bitvec_u8_inner_size( fd_restart_raw_offsets_bitvec_u8_inner_t const * self ); +ulong fd_restart_raw_offsets_bitvec_u8_inner_footprint( void ); +ulong fd_restart_raw_offsets_bitvec_u8_inner_align( void ); + +void fd_restart_raw_offsets_bitvec_new( fd_restart_raw_offsets_bitvec_t * self ); +int fd_restart_raw_offsets_bitvec_decode( fd_restart_raw_offsets_bitvec_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_restart_raw_offsets_bitvec_decode_preflight( fd_bincode_decode_ctx_t * ctx ); +void fd_restart_raw_offsets_bitvec_decode_unsafe( fd_restart_raw_offsets_bitvec_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_restart_raw_offsets_bitvec_decode_offsets( fd_restart_raw_offsets_bitvec_off_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_restart_raw_offsets_bitvec_encode( fd_restart_raw_offsets_bitvec_t const * self, fd_bincode_encode_ctx_t * ctx ); +void fd_restart_raw_offsets_bitvec_destroy( fd_restart_raw_offsets_bitvec_t * self, fd_bincode_destroy_ctx_t * ctx ); +void fd_restart_raw_offsets_bitvec_walk( void * w, fd_restart_raw_offsets_bitvec_t const * self, fd_types_walk_fn_t fun, const char *name, uint level ); +ulong fd_restart_raw_offsets_bitvec_size( fd_restart_raw_offsets_bitvec_t const * self ); +ulong fd_restart_raw_offsets_bitvec_footprint( void ); +ulong fd_restart_raw_offsets_bitvec_align( void ); + +void fd_restart_raw_offsets_new( fd_restart_raw_offsets_t * self ); +int fd_restart_raw_offsets_decode( fd_restart_raw_offsets_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_restart_raw_offsets_decode_preflight( fd_bincode_decode_ctx_t * ctx ); +void fd_restart_raw_offsets_decode_unsafe( fd_restart_raw_offsets_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_restart_raw_offsets_decode_offsets( fd_restart_raw_offsets_off_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_restart_raw_offsets_encode( fd_restart_raw_offsets_t const * self, fd_bincode_encode_ctx_t * ctx ); +void fd_restart_raw_offsets_destroy( fd_restart_raw_offsets_t * self, fd_bincode_destroy_ctx_t * ctx ); +void fd_restart_raw_offsets_walk( void * w, fd_restart_raw_offsets_t const * self, fd_types_walk_fn_t fun, const char *name, uint level ); +ulong fd_restart_raw_offsets_size( fd_restart_raw_offsets_t const * self ); +ulong fd_restart_raw_offsets_footprint( void ); +ulong fd_restart_raw_offsets_align( void ); + +void fd_restart_slots_offsets_new_disc( fd_restart_slots_offsets_t * self, uint discriminant ); +void fd_restart_slots_offsets_new( fd_restart_slots_offsets_t * self ); +int fd_restart_slots_offsets_decode( fd_restart_slots_offsets_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_restart_slots_offsets_decode_preflight( fd_bincode_decode_ctx_t * ctx ); +void fd_restart_slots_offsets_decode_unsafe( fd_restart_slots_offsets_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_restart_slots_offsets_encode( fd_restart_slots_offsets_t const * self, fd_bincode_encode_ctx_t * ctx ); +void fd_restart_slots_offsets_destroy( fd_restart_slots_offsets_t * self, fd_bincode_destroy_ctx_t * ctx ); +void fd_restart_slots_offsets_walk( void * w, fd_restart_slots_offsets_t const * self, fd_types_walk_fn_t fun, const char *name, uint level ); +ulong fd_restart_slots_offsets_size( fd_restart_slots_offsets_t const * self ); +ulong fd_restart_slots_offsets_footprint( void ); +ulong fd_restart_slots_offsets_align( void ); + +FD_FN_PURE uchar fd_restart_slots_offsets_is_run_length_encoding( fd_restart_slots_offsets_t const * self ); +FD_FN_PURE uchar fd_restart_slots_offsets_is_raw_offsets( fd_restart_slots_offsets_t const * self ); +enum { +fd_restart_slots_offsets_enum_run_length_encoding = 0, +fd_restart_slots_offsets_enum_raw_offsets = 1, +}; +void fd_gossip_restart_last_voted_fork_slots_new( fd_gossip_restart_last_voted_fork_slots_t * self ); +int fd_gossip_restart_last_voted_fork_slots_decode( fd_gossip_restart_last_voted_fork_slots_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_gossip_restart_last_voted_fork_slots_decode_preflight( fd_bincode_decode_ctx_t * ctx ); +void fd_gossip_restart_last_voted_fork_slots_decode_unsafe( fd_gossip_restart_last_voted_fork_slots_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_gossip_restart_last_voted_fork_slots_decode_offsets( fd_gossip_restart_last_voted_fork_slots_off_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_gossip_restart_last_voted_fork_slots_encode( fd_gossip_restart_last_voted_fork_slots_t const * self, fd_bincode_encode_ctx_t * ctx ); +void fd_gossip_restart_last_voted_fork_slots_destroy( fd_gossip_restart_last_voted_fork_slots_t * self, fd_bincode_destroy_ctx_t * ctx ); +void fd_gossip_restart_last_voted_fork_slots_walk( void * w, fd_gossip_restart_last_voted_fork_slots_t const * self, fd_types_walk_fn_t fun, const char *name, uint level ); +ulong fd_gossip_restart_last_voted_fork_slots_size( fd_gossip_restart_last_voted_fork_slots_t const * self ); +ulong fd_gossip_restart_last_voted_fork_slots_footprint( void ); +ulong fd_gossip_restart_last_voted_fork_slots_align( void ); + +void fd_gossip_restart_heaviest_fork_new( fd_gossip_restart_heaviest_fork_t * self ); +int fd_gossip_restart_heaviest_fork_decode( fd_gossip_restart_heaviest_fork_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_gossip_restart_heaviest_fork_decode_preflight( fd_bincode_decode_ctx_t * ctx ); +void fd_gossip_restart_heaviest_fork_decode_unsafe( fd_gossip_restart_heaviest_fork_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_gossip_restart_heaviest_fork_decode_offsets( fd_gossip_restart_heaviest_fork_off_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_gossip_restart_heaviest_fork_encode( fd_gossip_restart_heaviest_fork_t const * self, fd_bincode_encode_ctx_t * ctx ); +void fd_gossip_restart_heaviest_fork_destroy( fd_gossip_restart_heaviest_fork_t * self, fd_bincode_destroy_ctx_t * ctx ); +void fd_gossip_restart_heaviest_fork_walk( void * w, fd_gossip_restart_heaviest_fork_t const * self, fd_types_walk_fn_t fun, const char *name, uint level ); +ulong fd_gossip_restart_heaviest_fork_size( fd_gossip_restart_heaviest_fork_t const * self ); +ulong fd_gossip_restart_heaviest_fork_footprint( void ); +ulong fd_gossip_restart_heaviest_fork_align( void ); + void fd_crds_data_new_disc( fd_crds_data_t * self, uint discriminant ); void fd_crds_data_new( fd_crds_data_t * self ); int fd_crds_data_decode( fd_crds_data_t * self, fd_bincode_decode_ctx_t * ctx ); @@ -7281,6 +7529,8 @@ FD_FN_PURE uchar fd_crds_data_is_node_instance( fd_crds_data_t const * self ); FD_FN_PURE uchar fd_crds_data_is_duplicate_shred( fd_crds_data_t const * self ); FD_FN_PURE uchar fd_crds_data_is_incremental_snapshot_hashes( fd_crds_data_t const * self ); FD_FN_PURE uchar fd_crds_data_is_contact_info_v2( fd_crds_data_t const * self ); +FD_FN_PURE uchar fd_crds_data_is_restart_last_voted_fork_slots( fd_crds_data_t const * self ); +FD_FN_PURE uchar fd_crds_data_is_restart_heaviest_fork( fd_crds_data_t const * self ); enum { fd_crds_data_enum_contact_info_v1 = 0, fd_crds_data_enum_vote = 1, @@ -7294,6 +7544,8 @@ fd_crds_data_enum_node_instance = 8, fd_crds_data_enum_duplicate_shred = 9, fd_crds_data_enum_incremental_snapshot_hashes = 10, fd_crds_data_enum_contact_info_v2 = 11, +fd_crds_data_enum_restart_last_voted_fork_slots = 12, +fd_crds_data_enum_restart_heaviest_fork = 13, }; void fd_crds_bloom_new( fd_crds_bloom_t * self ); int fd_crds_bloom_decode( fd_crds_bloom_t * self, fd_bincode_decode_ctx_t * ctx ); diff --git a/src/flamenco/types/fd_types.json b/src/flamenco/types/fd_types.json index 44e1585275..53bb36e133 100644 --- a/src/flamenco/types/fd_types.json +++ b/src/flamenco/types/fd_types.json @@ -1971,6 +1971,74 @@ { "name": "extensions", "type": "vector", "modifier": "compact", "element": "uint" } ] }, + { + "name": "restart_run_length_encoding_inner", + "type": "struct", + "fields": [ + { "name": "bits", "type": "ushort", "modifier": "varint" } + ] + }, + { + "name": "restart_run_length_encoding", + "type": "struct", + "fields": [ + { "name": "offsets", "type": "vector", "element": "restart_run_length_encoding_inner" } + ] + }, + { + "name": "restart_raw_offsets_bitvec_u8_inner", + "type": "struct", + "fields": [ + { "name": "bits", "type": "vector", "element": "uchar" } + ] + }, + { + "name": "restart_raw_offsets_bitvec", + "type": "struct", + "fields": [ + { "name": "bits", "type": "option", "element": "restart_raw_offsets_bitvec_u8_inner", "flat": true }, + { "name": "len", "type": "ulong" } + ] + }, + { + "name": "restart_raw_offsets", + "type": "struct", + "fields": [ + { "name": "offsets", "type": "restart_raw_offsets_bitvec" } + ] + }, + { + "name": "restart_slots_offsets", + "type": "enum", + "variants": [ + { "name": "run_length_encoding", "type": "restart_run_length_encoding" }, + { "name": "raw_offsets", "type": "restart_raw_offsets" } + ] + }, + { + "name": "gossip_restart_last_voted_fork_slots", + "type": "struct", + "fields": [ + { "name": "from", "type": "pubkey" }, + { "name": "wallclock", "type": "ulong" }, + { "name": "offsets", "type": "restart_slots_offsets" }, + { "name": "last_voted_slot", "type": "ulong" }, + { "name": "last_voted_hash", "type": "hash" }, + { "name": "shred_version", "type": "ushort" } + ] + }, + { + "name": "gossip_restart_heaviest_fork", + "type": "struct", + "fields": [ + { "name": "from", "type": "pubkey" }, + { "name": "wallclock", "type": "ulong" }, + { "name": "last_slot", "type": "ulong" }, + { "name": "last_slot_hash", "type": "hash" }, + { "name": "observed_stake", "type": "ulong" }, + { "name": "shred_version", "type": "ushort" } + ] + }, { "name": "crds_data", "type": "enum", @@ -1986,7 +2054,9 @@ { "name": "node_instance", "type": "gossip_node_instance" }, { "name": "duplicate_shred", "type": "gossip_duplicate_shred" }, { "name": "incremental_snapshot_hashes", "type": "gossip_incremental_snapshot_hashes" }, - { "name": "contact_info_v2", "type": "gossip_contact_info_v2" } + { "name": "contact_info_v2", "type": "gossip_contact_info_v2" }, + { "name": "restart_last_voted_fork_slots", "type": "gossip_restart_last_voted_fork_slots" }, + { "name": "restart_heaviest_fork", "type": "gossip_restart_heaviest_fork" } ] }, {