diff --git a/src/disco/gui/fd_gui_printf.c b/src/disco/gui/fd_gui_printf.c index c00d6d7a35a..db177ce8926 100644 --- a/src/disco/gui/fd_gui_printf.c +++ b/src/disco/gui/fd_gui_printf.c @@ -1152,8 +1152,8 @@ fd_gui_printf_peer( fd_gui_t * gui, } else { jsonp_open_object( gui->http, "gossip" ); - char version[ 32 ]; - FD_TEST( fd_cstr_printf( version, sizeof( version ), NULL, "%u.%u.%u", gui->gossip.peers[ gossip_idx ].version.major, gui->gossip.peers[ gossip_idx ].version.minor, gui->gossip.peers[ gossip_idx ].version.patch ) ); + char version[ 64UL ]; + FD_TEST( fd_gossip_version_cstr( gui->gossip.peers[ gossip_idx ].version.major, gui->gossip.peers[ gossip_idx ].version.minor, gui->gossip.peers[ gossip_idx ].version.patch, version, sizeof( version ) ) ); jsonp_string( gui->http, "version", version ); jsonp_null( gui->http, "client_id" ); /* TODO: Frankendancer support */ jsonp_ulong( gui->http, "feature_set", gui->gossip.peers[ gossip_idx ].version.feature_set ); @@ -1230,8 +1230,8 @@ peers_printf_node( fd_gui_peers_ctx_t * peers, jsonp_open_object( peers->http, "gossip" ); - char version[ 32 ]; - FD_TEST( fd_cstr_printf( version, sizeof( version ), NULL, "%u.%u.%u", peer->contact_info.version.major, peer->contact_info.version.minor, peer->contact_info.version.patch ) ); + char version[ 64UL ]; + FD_TEST( fd_gossip_version_cstr( peer->contact_info.version.major, peer->contact_info.version.minor, peer->contact_info.version.patch, version, sizeof( version ) ) ); jsonp_string( peers->http, "version", version ); jsonp_ulong( peers->http, "client_id", peer->contact_info.version.client ); jsonp_ulong( peers->http, "feature_set", peer->contact_info.version.feature_set ); diff --git a/src/discof/rpc/fd_rpc_tile.c b/src/discof/rpc/fd_rpc_tile.c index ca4d1cb79f9..a721d8f111c 100644 --- a/src/discof/rpc/fd_rpc_tile.c +++ b/src/discof/rpc/fd_rpc_tile.c @@ -1151,7 +1151,11 @@ getClusterNodes( fd_rpc_tile_t * ctx, } fd_http_server_printf( ctx->http, "\"pubkey\":\"%s\",", identity_cstr ); fd_http_server_printf( ctx->http, "\"shredVersion\":%u,", ele->ci->shred_version ); - fd_http_server_printf( ctx->http, "\"version\":\"%u.%u.%u\"", ele->ci->version.major, ele->ci->version.minor, ele->ci->version.patch ); + + char version[ 64UL ]; + FD_TEST( fd_gossip_version_cstr( ele->ci->version.major, ele->ci->version.minor, ele->ci->version.patch, version, sizeof( version ) ) ); + fd_http_server_printf( ctx->http, "\"version\":\"%s\"", version ); + if( FD_UNLIKELY( is_last ) ) fd_http_server_printf( ctx->http, "}" ); else fd_http_server_printf( ctx->http, "}," ); } diff --git a/src/flamenco/gossip/fd_gossip_message.h b/src/flamenco/gossip/fd_gossip_message.h index 3cac36db638..ef4f2e7d444 100644 --- a/src/flamenco/gossip/fd_gossip_message.h +++ b/src/flamenco/gossip/fd_gossip_message.h @@ -2,6 +2,7 @@ #define HEADER_fd_src_flamenco_gossip_fd_gossip_message_h #include "../../util/fd_util_base.h" +#include "../../util/cstr/fd_cstr.h" #include "fd_gossip_value.h" #include @@ -430,4 +431,43 @@ fd_gossip_pull_request_init( uchar * payload, ulong ** out_bloom_bits, ulong ** out_bits_set ); +/* fd_gossip_version_cstr converts gossip version fields to a null + terminated c-string. Returns 1 on success and 0 on failure (e.g. + small out_sz) + + The 16-bit minor field has a special encoding to support semver + prerelease notation. + - High 2 bits: prerelease channel (0=stable, 1=rc, 2=beta, 3=alpha) + - Low 14 bits: actual minor version number + + Patch field semantics: + - If prerelease_bits==0 (stable), `patch` is rendered as the + normal semver patch component: + `..`. + - If prerelease_bits!=0 (prerelease), the semver patch component + is forced to 0 and `patch` is interpreted as the prerelease + sequence number, rendered as: + `..0-.`. + + Note that due to Frankendancer's existing unique versioning hack, + future Frankendancer releases will all be stable (i.e. + prerelease_bits==0) and based on stable Agave versions. This is a + permissible compromise given Frankendancer is approaching EOL. */ +static inline int +fd_gossip_version_cstr( ushort major, + ushort minor, + ushort patch, + char * out, + ulong out_sz ) { + ushort prerelease_bits = (minor >> 14U) & 0x3U; + ushort minor_actual = minor & 0x3FFFU; + + if( FD_UNLIKELY( prerelease_bits ) ) { + const char * names[] = { "", "rc", "beta", "alpha" }; + return fd_cstr_printf_check( out, out_sz, NULL, "%hu.%hu.0-%s.%hu", major, minor_actual, names[ prerelease_bits ], patch ); + } else { + return fd_cstr_printf_check( out, out_sz, NULL, "%hu.%hu.%hu", major, minor_actual, patch ); + } +} + #endif /* HEADER_fd_src_flamenco_gossip_fd_gossip_message_h */