Line data Source code
1 : #define _GNU_SOURCE 2 : #include "../fd_config.h" 3 : #include "../fd_action.h" 4 : #include "../../../util/fd_util.h" 5 : #include "../../../ballet/base58/fd_base58.h" 6 : #include "../../../disco/shred/fd_shred_tile.h" 7 : #include "../../../disco/keyguard/fd_keyswitch.h" 8 : #include <unistd.h> 9 : 10 : void 11 : get_identity_cmd_fn( args_t * args FD_PARAM_UNUSED, 12 0 : config_t * config ) { 13 : /* Find the shred tile which is always present and has the current runtime identity */ 14 0 : ulong shred_tile_idx = fd_topo_find_tile( &config->topo, "shred", 0UL ); 15 0 : if( FD_UNLIKELY( shred_tile_idx==ULONG_MAX ) ) { 16 0 : FD_LOG_ERR(( "Shred tile not found in topology" )); 17 0 : } 18 : 19 0 : fd_topo_tile_t const * shred_tile = &config->topo.tiles[ shred_tile_idx ]; 20 : /* Access shred tile object to find its workspace */ 21 0 : if( FD_UNLIKELY( shred_tile->tile_obj_id==ULONG_MAX ) ) { 22 0 : FD_LOG_ERR(( "Shred tile object not found" )); 23 0 : } 24 : /* Find the workspace containing the shred tile object */ 25 0 : fd_topo_obj_t const * shred_obj = &config->topo.objs[ shred_tile->tile_obj_id ]; 26 0 : ulong shred_wksp_id = shred_obj->wksp_id; 27 : 28 : /* Join the workspace in read-only mode */ 29 0 : fd_topo_join_workspace( &config->topo, &config->topo.workspaces[ shred_wksp_id ], FD_SHMEM_JOIN_MODE_READ_ONLY, FD_TOPO_CORE_DUMP_LEVEL_DISABLED ); 30 : 31 : /* Cast to shred context structure */ 32 0 : fd_shred_shared_ctx_t const * shred_ctx = fd_topo_obj_laddr( &config->topo, shred_tile->tile_obj_id ); 33 0 : if( FD_UNLIKELY( !shred_ctx ) ) { 34 0 : fd_topo_leave_workspaces( &config->topo ); 35 0 : FD_LOG_ERR(( "Failed to access shred tile object" )); 36 0 : } 37 : /* Join the keyswitch to check for concurrent identity updates */ 38 0 : fd_keyswitch_t * keyswitch = fd_keyswitch_join( fd_topo_obj_laddr( &config->topo, shred_tile->id_keyswitch_obj_id ) ); 39 0 : if( FD_UNLIKELY( !keyswitch ) ) { 40 0 : fd_topo_leave_workspaces( &config->topo ); 41 0 : FD_LOG_ERR(( "Failed to join keyswitch" )); 42 0 : } 43 : 44 : /* Read identity key with retry if needed */ 45 0 : fd_pubkey_t identity_key; 46 : /* TODO: Consider adding a counter to detect multiple rapid identity switches 47 : that could cause us to read a stale identity between state checks. */ 48 0 : for( int retry = 0; retry < 2; retry++ ) { 49 : /* Peek the pre-read keyswitch state */ 50 0 : ulong switch_state0 = fd_keyswitch_state_query( keyswitch ); 51 : 52 : /* Speculatively read current key */ 53 0 : identity_key = FD_VOLATILE_CONST( *shred_ctx->identity_key ); 54 : 55 : /* Peek the post-read keyswitch state */ 56 0 : ulong switch_state1 = fd_keyswitch_state_query( keyswitch ); 57 : 58 : /* Check if we got a consistent read */ 59 0 : if( FD_LIKELY( switch_state0 == switch_state1 && 60 0 : switch_state0 != FD_KEYSWITCH_STATE_SWITCH_PENDING ) ) { 61 : /* Success - we have a consistent identity key */ 62 0 : break; 63 0 : } 64 : 65 : /* Key switch in progress or states don't match, retry after delay */ 66 0 : if( retry == 0 ) { 67 0 : usleep( 10000 ); /* 10ms delay */ 68 0 : } else { 69 0 : fd_keyswitch_leave( keyswitch ); 70 0 : fd_topo_leave_workspaces( &config->topo ); 71 0 : FD_LOG_ERR(( "Failed to read identity key - keyswitch in progress" )); 72 0 : } 73 0 : } 74 : 75 : /* Leave keyswitch */ 76 0 : fd_keyswitch_leave( keyswitch ); 77 : 78 : /* Convert to base58 and print */ 79 0 : char identity_key_str[ FD_BASE58_ENCODED_32_SZ ]; 80 0 : fd_base58_encode_32( identity_key.uc, NULL, identity_key_str ); 81 : 82 : FD_LOG_STDOUT(( "%s\n", identity_key_str )); 83 0 : } 84 : 85 : action_t fd_action_get_identity = { 86 : .name = "get-identity", 87 : .args = NULL, 88 : .fn = get_identity_cmd_fn, 89 : .require_config = 1, 90 : .perm = NULL, /* TODO: This command may require RLIMIT_MLOCK permissions 91 : to mlock(2) the workspace in memory. This should be 92 : addressed in future updates. */ 93 : .description = "Get the current active identity of the running validator", 94 : };