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