LCOV - code coverage report
Current view: top level - app/firedancer/commands - add_authorized_voter.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 82 0.0 %
Date: 2026-08-10 04:52:31 Functions: 0 4 0.0 %

          Line data    Source code
       1             : #include "adminctl_client.h"
       2             : #include "../../shared/fd_config.h"
       3             : #include "../../shared/fd_action.h"
       4             : 
       5             : #include "../../../disco/keyguard/fd_keyload.h"
       6             : #include "../../../ballet/base58/fd_base58.h"
       7             : #include "../../../ballet/ed25519/fd_ed25519.h"
       8             : 
       9             : #include <unistd.h>
      10             : 
      11             : void
      12             : add_authorized_voter_cmd_args( int *    pargc,
      13             :                                char *** pargv,
      14           0 :                                args_t * args ) {
      15             : 
      16           0 :   char const * name = fd_env_strip_cmdline_cstr( pargc, pargv, "--name", NULL, NULL );
      17           0 :   if( FD_UNLIKELY( name ) ) fd_cstr_ncpy( args->add_authorized_voter.name, name, sizeof(args->add_authorized_voter.name) );
      18             : 
      19           0 :   if( FD_UNLIKELY( *pargc<1 ) ) {
      20           0 :     FD_LOG_ERR(( "Usage: %s add-authorized-voter <keypair>", FD_BINARY_NAME ));
      21           0 :   }
      22             : 
      23           0 :   char const * path = *pargv[0];
      24           0 :   (*pargc)--;
      25           0 :   (*pargv)++;
      26             : 
      27           0 :   if( FD_UNLIKELY( !strcmp( path, "-" ) ) ) {
      28           0 :     uchar * keypair_wr = fd_keyload_alloc_protected_pages( 1UL, 2UL );
      29           0 :     FD_LOG_STDOUT(( "Reading authorized voter keypair from stdin.  Press Ctrl-D when done.\n" ));
      30           0 :     fd_keyload_read( STDIN_FILENO, "stdin", keypair_wr );
      31           0 :     args->add_authorized_voter.keypair = fd_keyload_mprotect_ro( keypair_wr, 0 );
      32           0 :   } else {
      33           0 :     args->add_authorized_voter.keypair = fd_keyload_load( path, 0 );
      34           0 :   }
      35           0 : }
      36             : 
      37             : static void FD_FN_SENSITIVE
      38             : add_authorized_voter( args_t *   args,
      39           0 :                       config_t * config ) {
      40             : 
      41           0 :   uchar       public_key[ 32 ];
      42           0 :   fd_sha512_t sha512[ 1 ];
      43           0 :   FD_TEST( fd_sha512_join( fd_sha512_new( sha512 ) ) );
      44             : 
      45           0 :   fd_ed25519_public_from_private( public_key, args->add_authorized_voter.keypair, sha512 );
      46           0 :   if( FD_UNLIKELY( memcmp( public_key, args->add_authorized_voter.keypair+32UL, 32UL ) ) ) {
      47           0 :     FD_LOG_ERR(( "The public key in the key file does not match the public key derived from the private key."
      48           0 :                  "Firedancer will not use the key pair to sign as it might leak the private key." ));
      49           0 :   }
      50             : 
      51           0 :   fd_adminctl_t * adminctl = adminctl_client_attach( config, args->add_authorized_voter.name );
      52             : 
      53           0 :   void * payload     = NULL;
      54           0 :   ulong  payload_max = 0UL;
      55           0 :   ulong  slot_idx    = fd_adminctl_reserve( adminctl, &payload, &payload_max );
      56           0 :   if( FD_UNLIKELY( slot_idx==ULONG_MAX ) ) {
      57           0 :     FD_LOG_ERR(( "Failed to process `add-authorized-voter` command as there are other pending "
      58           0 :                  "commands that are being processed.  Please wait for other commands to complete "
      59           0 :                  "or forcefully terminate the other processes and retry the command." ));
      60           0 :   }
      61             : 
      62           0 :   fd_adminctl_add_auth_voter_t * req = (fd_adminctl_add_auth_voter_t *)payload;
      63           0 :   req->version = FD_ADMINCTL_ADD_AUTH_VOTER_PAYLOAD_VERSION;
      64           0 :   memcpy( req->keypair, args->add_authorized_voter.keypair, 64UL );
      65             : 
      66           0 :   uchar * keypair_wr = fd_keyload_mprotect_wr( args->add_authorized_voter.keypair, 0 );
      67           0 :   fd_memzero_explicit( keypair_wr, 64UL );
      68           0 :   fd_keyload_mprotect_ro( keypair_wr, 0 );
      69             : 
      70           0 :   fd_adminctl_publish( adminctl, slot_idx, FD_ADMINCTL_CMD_ADD_AUTH_VOTER, sizeof(fd_adminctl_add_auth_voter_t) );
      71             : 
      72           0 :   ulong result = fd_adminctl_wait( adminctl, slot_idx );
      73           0 :   switch( result ) {
      74           0 :     case FD_ADMINCTL_RESULT_SUCCESS:
      75           0 :       {
      76           0 :       char voter_key_base58[ FD_BASE58_ENCODED_32_SZ ];
      77           0 :       fd_base58_encode_32( public_key, NULL, voter_key_base58 );
      78           0 :       FD_LOG_NOTICE(( "authorized voter key %s%s%s added successfully", fd_log_style_bold(), voter_key_base58, fd_log_style_normal() ));
      79           0 :       break;
      80           0 :     }
      81           0 :     case FD_ADMINCTL_RESULT_ABI_VERSION_MISMATCH:
      82           0 :     case FD_ADMINCTL_RESULT_ABI_SIZE_MISMATCH:
      83           0 :     case FD_ADD_AUTHORIZED_VOTER_RESULT_KEYPAIR_MISMATCH:
      84           0 :       FD_LOG_ERR(( "Failed to add authorized voter key: the command was not able to "
      85           0 :                    "successfully communicate with the running Firedancer process. It "
      86           0 :                    "is possible that you are running the command from an older or "
      87           0 :                    "newer version of Firedancer that is no longer compatible." ));
      88           0 :     case FD_ADD_AUTHORIZED_VOTER_RESULT_MAX_AUTH_VOTERS:
      89           0 :       FD_LOG_ERR(( "Failed to add authorized voter key: maximum number of authorized voters "
      90           0 :                    "supported by the validator has been reached" ));
      91           0 :     case FD_ADD_AUTHORIZED_VOTER_RESULT_DUPLICATE_AUTH_VOTER:
      92           0 :       FD_LOG_ERR(( "Failed to add authorized voter key: the authorized voter key exists in "
      93           0 :                    "the validator's authorized voter list" ));
      94           0 :     default:
      95           0 :       FD_LOG_ERR(( "Unexpected add-authorized-voter result %lu.  This can be a result "
      96           0 :                    "of a version mismatch between the command and the running Firedancer "
      97           0 :                    "process. Please report this to the Firedancer team for investigation.", result ));
      98           0 :   }
      99           0 : }
     100             : 
     101             : void
     102             : add_authorized_voter_cmd_fn( args_t *   args,
     103           0 :                              config_t * config ) {
     104           0 :   add_authorized_voter( args, config );
     105           0 : }
     106             : 
     107             : static void
     108           0 : add_authorized_voter_args_help( fd_action_help_t * help ) {
     109             :   fd_action_help_arg( help, "<keypair>", NULL,  "Path to the authorized voter keypair to add, in the standard Solana\n"
     110           0 :                                                 "keypair file format (the 64-byte JSON array).  The full keypair is\n"
     111           0 :                                                 "required, not just the public key, because the validator must sign\n"
     112           0 :                                                 "votes with it.  Pass `-` to read the same JSON array from stdin\n"
     113           0 :                                                 "instead of from a file" );
     114           0 :   fd_action_help_arg( help, "--name", "<name>", "Name of the validator instance to attach to, if more than one is\n"
     115           0 :                                                 "running on this host" );
     116           0 : }
     117             : 
     118             : action_t fd_action_add_authorized_voter = {
     119             :   .name           = "add-authorized-voter",
     120             :   .args           = add_authorized_voter_cmd_args,
     121             :   .fn             = add_authorized_voter_cmd_fn,
     122             :   .require_config = 0,
     123             :   .perm           = NULL,
     124             :   .description    = "Add an authorized voter to the validator",
     125             :   .detail         = "Registers an additional authorized voter key with an already running\n"
     126             :                     "validator so it can sign votes with that key, in addition to the identity\n"
     127             :                     "key and any voters already configured.  On success it prints `Authorized\n"
     128             :                     "voter key added successfully` and exits 0.  It fails (non-zero, with no change)\n"
     129             :                     "if the key is already an authorized voter, or if the validator already has\n"
     130             :                     "the maximum of 16 authorized voters.\n"
     131             :                     "\n"
     132             :                     "This command does not start a validator; it attaches to one that is already\n"
     133             :                     "running.  With no arguments it discovers the running validator automatically.\n"
     134             :                     "If multiple validators are running, pass --name to select one.  If --config is\n"
     135             :                     "given, the validator is instead located from the configuration file; only the\n"
     136             :                     "name and [hugetlbfs.mount_path] values are used, and they must match the\n"
     137             :                     "running validator.\n"
     138             :                     "\n"
     139             :                     "The change is live only: it is not written back to the config file, so the\n"
     140             :                     "voter is dropped on the validator's next restart.  To keep it across restarts,\n"
     141             :                     "also add the keypair path to [paths.authorized_voter_paths] in the config.",
     142             :   .usage          = "add-authorized-voter <keypair> [--name <name>]",
     143             :   .args_help      = add_authorized_voter_args_help,
     144             : };

Generated by: LCOV version 1.14