LCOV - code coverage report
Current view: top level - app/fdctl/commands - run_agave.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 195 0.0 %
Date: 2025-07-01 05:00:49 Functions: 0 7 0.0 %

          Line data    Source code
       1             : #define _GNU_SOURCE
       2             : #include "../../shared/commands/run/run.h"
       3             : 
       4             : #include "../../../util/net/fd_ip4.h"
       5             : #include "../../../util/tile/fd_tile_private.h"
       6             : 
       7             : #include <sched.h>
       8             : #include <stdlib.h> /* setenv */
       9             : #include <errno.h>
      10             : #include <unistd.h>
      11             : #include <pthread.h>
      12             : #include <sys/wait.h>
      13             : 
      14             : #define NAME "run-agave"
      15             : 
      16             : fd_topo_run_tile_t
      17             : fdctl_tile_run( fd_topo_tile_t const * tile );
      18             : 
      19             : extern void fd_ext_validator_main( const char ** args );
      20             : 
      21             : extern int * fd_log_private_shared_lock;
      22             : 
      23             : static void
      24           0 : clone_labs_memory_space_tiles( config_t * config ) {
      25             :   /* preload shared memory for all the agave tiles at once */
      26           0 :   for( ulong i=0; i<config->topo.wksp_cnt; i++ ) {
      27           0 :     fd_topo_wksp_t * wksp = &config->topo.workspaces[ i ];
      28           0 :     if( FD_LIKELY( !strcmp( wksp->name, "pack_bank" ) ||
      29           0 :                    !strcmp( wksp->name, "shred_store" ) ) ) {
      30           0 :       fd_topo_join_workspace( &config->topo, wksp, FD_SHMEM_JOIN_MODE_READ_ONLY );
      31           0 :     } else if( FD_LIKELY( !strcmp( wksp->name, "bank_poh" ) ||
      32           0 :                           !strcmp( wksp->name, "bank_pack" ) ||
      33           0 :                           !strcmp( wksp->name, "bank_busy" ) ||
      34           0 :                           !strcmp( wksp->name, "poh_shred" ) ||
      35           0 :                           !strcmp( wksp->name, "gossip_dedup" ) ||
      36           0 :                           !strcmp( wksp->name, "stake_out" ) ||
      37           0 :                           !strcmp( wksp->name, "metric_in" ) ||
      38           0 :                           !strcmp( wksp->name, "bank" ) ||
      39           0 :                           !strcmp( wksp->name, "poh" ) ||
      40           0 :                           !strcmp( wksp->name, "store" ) ) ) {
      41           0 :       fd_topo_join_workspace( &config->topo, wksp, FD_SHMEM_JOIN_MODE_READ_WRITE );
      42           0 :     }
      43           0 :   }
      44             : 
      45           0 :   fd_topo_run_single_process( &config->topo, 1, config->uid, config->gid, fdctl_tile_run, NULL );
      46           0 : }
      47             : 
      48             : static int _fd_ext_larger_max_cost_per_block, _fd_ext_larger_shred_limits_per_block, _fd_ext_disable_status_cache;
      49             : 
      50           0 : int fd_ext_larger_max_cost_per_block    ( void ) { return _fd_ext_larger_max_cost_per_block;     }
      51           0 : int fd_ext_larger_shred_limits_per_block( void ) { return _fd_ext_larger_shred_limits_per_block; }
      52           0 : int fd_ext_disable_status_cache         ( void ) { return _fd_ext_disable_status_cache;          }
      53             : 
      54             : void
      55           0 : agave_boot( config_t const * config ) {
      56           0 :   uint idx = 0;
      57           0 :   char const * argv[ 128 ];
      58           0 :   uint bufidx = 0;
      59           0 :   char buffer[ 32 ][ 16 ];
      60           0 : #define ADD1( arg ) do { argv[ idx++ ] = arg; } while( 0 )
      61           0 : #define ADD( arg, val ) do { argv[ idx++ ] = arg; argv[ idx++ ] = val; } while( 0 )
      62           0 : #define ADDU( arg, val ) do { argv[ idx++ ] = arg; FD_TEST( fd_cstr_printf_check( buffer[ bufidx ], 16, NULL, "%u", val ) ); argv[ idx++ ] = buffer[ bufidx++ ]; } while( 0 )
      63           0 : #define ADDH( arg, val ) do { argv[ idx++ ] = arg; FD_TEST( fd_cstr_printf_check( buffer[ bufidx ], 16, NULL, "%hu", val ) ); argv[ idx++ ] = buffer[ bufidx++ ]; } while( 0 )
      64             : 
      65           0 :   ADD1( "fdctl" );
      66           0 :   ADD( "--log", "-" );
      67             : 
      68             :   /* net */
      69           0 :   if( FD_UNLIKELY( strcmp( config->frankendancer.dynamic_port_range, "" ) ) )
      70           0 :     ADD( "--dynamic-port-range", config->frankendancer.dynamic_port_range );
      71             : 
      72           0 :   if( strcmp( config->net.bind_address, "" ) )
      73           0 :     ADD( "--bind-address", config->net.bind_address );
      74           0 :   ADDU( "--firedancer-tpu-port", config->tiles.quic.regular_transaction_listen_port );
      75           0 :   ADDU( "--firedancer-tvu-port", config->tiles.shred.shred_listen_port              );
      76             : 
      77             :   /* consensus */
      78           0 :   ADD( "--identity", config->paths.identity_key );
      79           0 :   if( strcmp( config->paths.vote_account, "" ) )
      80           0 :     ADD( "--vote-account", config->paths.vote_account );
      81           0 :   for( ulong i=0UL; i<config->frankendancer.paths.authorized_voter_paths_cnt; i++ )
      82           0 :     ADD( "--authorized-voter", config->frankendancer.paths.authorized_voter_paths[ i ] );
      83           0 :   if( !config->frankendancer.consensus.snapshot_fetch ) ADD1( "--no-snapshot-fetch" );
      84           0 :   if( !config->frankendancer.consensus.genesis_fetch  ) ADD1( "--no-genesis-fetch"  );
      85           0 :   if( !config->frankendancer.consensus.poh_speed_test ) ADD1( "--no-poh-speed-test" );
      86           0 :   if( strcmp( config->frankendancer.consensus.expected_genesis_hash, "" ) )
      87           0 :     ADD( "--expected-genesis-hash", config->frankendancer.consensus.expected_genesis_hash );
      88           0 :   if( config->frankendancer.consensus.wait_for_supermajority_at_slot ) {
      89           0 :     ADDU( "--wait-for-supermajority", config->frankendancer.consensus.wait_for_supermajority_at_slot );
      90           0 :     if( strcmp( config->frankendancer.consensus.expected_bank_hash, "" ) )
      91           0 :       ADD( "--expected-bank-hash", config->frankendancer.consensus.expected_bank_hash );
      92           0 :   }
      93             : 
      94           0 :   if( config->consensus.expected_shred_version )
      95           0 :     ADDH( "--expected-shred-version", config->consensus.expected_shred_version );
      96           0 :   if( !config->frankendancer.consensus.wait_for_vote_to_start_leader )
      97           0 :     ADD1( "--no-wait-for-vote-to-start-leader");
      98           0 :   for( uint const * p = config->frankendancer.consensus.hard_fork_at_slots; *p; p++ ) ADDU( "--hard-fork", *p );
      99           0 :   for( ulong i=0; i<config->frankendancer.consensus.known_validators_cnt; i++ )
     100           0 :     ADD( "--known-validator", config->frankendancer.consensus.known_validators[ i ] );
     101             : 
     102           0 :   ADD( "--snapshot-archive-format", config->frankendancer.ledger.snapshot_archive_format );
     103           0 :   if( FD_UNLIKELY( config->frankendancer.ledger.require_tower ) ) ADD1( "--require-tower" );
     104             : 
     105           0 :   if( FD_UNLIKELY( !config->frankendancer.consensus.os_network_limits_test ) )
     106           0 :     ADD1( "--no-os-network-limits-test" );
     107             : 
     108             :   /* ledger */
     109           0 :   ADD( "--ledger", config->paths.ledger );
     110           0 :   ADDU( "--limit-ledger-size", config->frankendancer.ledger.limit_size );
     111           0 :   if( strcmp( "", config->frankendancer.paths.accounts_path ) )
     112           0 :     ADD( "--accounts", config->frankendancer.paths.accounts_path );
     113           0 :   if( strcmp( "", config->frankendancer.ledger.accounts_index_path ) )
     114           0 :     ADD( "--accounts-index-path", config->frankendancer.ledger.accounts_index_path );
     115           0 :   if( strcmp( "", config->frankendancer.ledger.accounts_hash_cache_path ) )
     116           0 :     ADD( "--accounts-hash-cache-path", config->frankendancer.ledger.accounts_hash_cache_path );
     117           0 :   if( !config->frankendancer.ledger.enable_accounts_disk_index ) ADD1( "--disable-accounts-disk-index" );
     118           0 :   for( ulong i=0UL; i<config->frankendancer.ledger.account_indexes_cnt; i++ )
     119           0 :     ADD( "--account-index", config->frankendancer.ledger.account_indexes[ i ] );
     120           0 :   if( FD_LIKELY( !config->frankendancer.ledger.account_index_include_keys_cnt ) ) {
     121           0 :     for( ulong i=0UL; i<config->frankendancer.ledger.account_index_exclude_keys_cnt; i++ )
     122           0 :       ADD( "--account-index-exclude-key", config->frankendancer.ledger.account_index_exclude_keys[ i ] );
     123           0 :   } else {
     124           0 :     for( ulong i=0UL; i<config->frankendancer.ledger.account_index_include_keys_cnt; i++ )
     125           0 :       ADD( "--account-index-include-key", config->frankendancer.ledger.account_index_include_keys[ i ] );
     126           0 :   }
     127             : 
     128             :   /* gossip */
     129           0 :   for( ulong i=0UL; i<config->gossip.entrypoints_cnt; i++ ) ADD( "--entrypoint", config->gossip.entrypoints[ i ] );
     130           0 :   if( !config->frankendancer.gossip.port_check ) ADD1( "--no-port-check" );
     131           0 :   ADDH( "--gossip-port", config->gossip.port );
     132           0 :   char ip_addr[16]; /* ADD stored the address for later use, so ip_addr must be in scope */
     133           0 :   if( strcmp( config->frankendancer.gossip.host, "" ) ) {
     134           0 :     ADD( "--gossip-host", config->frankendancer.gossip.host );
     135           0 :   } else {
     136           0 :     FD_TEST( fd_cstr_printf_check( ip_addr, 16, NULL, FD_IP4_ADDR_FMT, FD_IP4_ADDR_FMT_ARGS(config->net.ip_addr) ) );
     137           0 :     ADD( "--gossip-host", ip_addr );
     138           0 :   }
     139           0 :   if( config->development.gossip.allow_private_address ) {
     140           0 :     ADD1( "--allow-private-addr" );
     141           0 :   }
     142             : 
     143             :   /* rpc */
     144           0 :   if( config->rpc.port ) ADDH( "--rpc-port", config->rpc.port );
     145           0 :   if( config->frankendancer.rpc.full_api ) ADD1( "--full-rpc-api" );
     146           0 :   if( config->frankendancer.rpc.private ) ADD1( "--private-rpc" );
     147           0 :   if( strcmp( config->frankendancer.rpc.bind_address, "" ) ) ADD( "--rpc-bind-address", config->frankendancer.rpc.bind_address );
     148           0 :   if( config->frankendancer.rpc.transaction_history ) ADD1( "--enable-rpc-transaction-history" );
     149           0 :   if( config->rpc.extended_tx_metadata_storage ) ADD1( "--enable-extended-tx-metadata-storage" );
     150           0 :   if( config->frankendancer.rpc.only_known ) ADD1( "--only-known-rpc" );
     151           0 :   if( config->frankendancer.rpc.pubsub_enable_block_subscription ) ADD1( "--rpc-pubsub-enable-block-subscription" );
     152           0 :   if( config->frankendancer.rpc.pubsub_enable_vote_subscription ) ADD1( "--rpc-pubsub-enable-vote-subscription" );
     153           0 :   if( config->frankendancer.rpc.bigtable_ledger_storage ) ADD1( "--enable-rpc-bigtable-ledger-storage" );
     154             : 
     155             :   /* snapshots */
     156           0 :   if( config->frankendancer.snapshots.enabled ) {
     157           0 :     if( config->frankendancer.snapshots.incremental_snapshots ) {
     158           0 :       ADDU( "--full-snapshot-interval-slots", config->frankendancer.snapshots.full_snapshot_interval_slots );
     159           0 :       ADDU( "--snapshot-interval-slots", config->frankendancer.snapshots.incremental_snapshot_interval_slots );
     160           0 :     } else {
     161           0 :       ADDU( "--snapshot-interval-slots", config->frankendancer.snapshots.full_snapshot_interval_slots );
     162           0 :     }
     163           0 :   } else {
     164           0 :     ADDU( "--snapshot-interval-slots", (uint)0 );
     165           0 :   }
     166           0 :   if( !config->frankendancer.snapshots.incremental_snapshots ) ADD1( "--no-incremental-snapshots" );
     167           0 :   ADD( "--snapshots", config->frankendancer.snapshots.path );
     168           0 :   if( strcmp( "", config->frankendancer.snapshots.incremental_path ) ) ADD( "--incremental-snapshot-archive-path", config->frankendancer.snapshots.incremental_path );
     169           0 :   ADDU( "--maximum-snapshots-to-retain", config->frankendancer.snapshots.maximum_full_snapshots_to_retain );
     170           0 :   ADDU( "--maximum-incremental-snapshots-to-retain", config->frankendancer.snapshots.maximum_incremental_snapshots_to_retain );
     171           0 :   ADDU( "--maximum-snapshot-download-abort", config->frankendancer.snapshots.maximum_snapshot_download_abort );
     172           0 :   ADDU( "--minimal-snapshot-download-speed", config->frankendancer.snapshots.minimum_snapshot_download_speed );
     173             : 
     174           0 :   if( config->frankendancer.layout.agave_unified_scheduler_handler_threads ) {
     175           0 :     if( FD_UNLIKELY( config->frankendancer.layout.agave_unified_scheduler_handler_threads>config->topo.agave_affinity_cnt ) ) {
     176           0 :       FD_LOG_ERR(( "Trying to spawn %u handler threads but the agave subprocess has %lu cores. "
     177           0 :                    "Either increase the number of cores in [layout.agave_affinity] or reduce "
     178           0 :                    "the number of threads in [layout.agave_unified_scheduler_handler_threads].",
     179           0 :                    config->frankendancer.layout.agave_unified_scheduler_handler_threads, config->topo.agave_affinity_cnt ));
     180           0 :     }
     181           0 :     ADDU( "--unified-scheduler-handler-threads", config->frankendancer.layout.agave_unified_scheduler_handler_threads );
     182           0 :   } else {
     183           0 :     ulong num_threads = fd_ulong_max( config->topo.agave_affinity_cnt-4UL, fd_ulong_min( config->topo.agave_affinity_cnt, 4UL ) );
     184           0 :     ADDU( "--unified-scheduler-handler-threads", (uint)num_threads );
     185           0 :   }
     186             : 
     187           0 :   argv[ idx ] = NULL;
     188             : 
     189           0 :   if( FD_LIKELY( strcmp( config->frankendancer.reporting.solana_metrics_config, "" ) ) ) {
     190           0 :     if( FD_UNLIKELY( setenv( "SOLANA_METRICS_CONFIG", config->frankendancer.reporting.solana_metrics_config, 1 ) ) )
     191           0 :       FD_LOG_ERR(( "setenv() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     192           0 :   }
     193             : 
     194           0 :   FD_LOG_INFO(( "Running Agave validator with the following arguments:" ));
     195           0 :   for( ulong j=0UL; j<idx; j++ ) FD_LOG_INFO(( "%s", argv[j] ));
     196             : 
     197           0 :   FD_CPUSET_DECL( floating_cpu_set );
     198           0 :   if( FD_UNLIKELY( fd_cpuset_getaffinity( 0, floating_cpu_set ) ) )
     199           0 :     FD_LOG_ERR(( "sched_getaffinity failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     200             : 
     201           0 :   FD_CPUSET_DECL( cpu_set );
     202           0 :   for( ulong i=0UL; i<config->topo.agave_affinity_cnt; i++ ) {
     203           0 :     fd_cpuset_insert( cpu_set, config->topo.agave_affinity_cpu_idx[ i ] );
     204           0 :   }
     205             : 
     206           0 :   if( FD_UNLIKELY( fd_cpuset_setaffinity( 0, cpu_set ) ) ) {
     207           0 :     if( FD_LIKELY( errno==EINVAL ) ) {
     208           0 :       FD_LOG_ERR(( "Unable to set the affinity for threads created by Agave. It is likely "
     209           0 :                     "that the affinity you have specified for Agave under [layout.agave_affinity] "
     210           0 :                     "in the configuration file contains CPUs which do not exist on this machine." ));
     211           0 :     } else {
     212           0 :       FD_LOG_ERR(( "sched_setaffinity failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     213           0 :     }
     214           0 :   }
     215             : 
     216             :   /* Consensus-breaking development-only CU and/or shred limit increase. */
     217           0 :   _fd_ext_larger_max_cost_per_block     = config->development.bench.larger_max_cost_per_block;
     218           0 :   _fd_ext_larger_shred_limits_per_block = config->development.bench.larger_shred_limits_per_block;
     219             :   /* Consensus-breaking bench-only option to disable status cache */
     220           0 :   _fd_ext_disable_status_cache           = config->development.bench.disable_status_cache;
     221           0 :   FD_COMPILER_MFENCE();
     222             : 
     223             :   /* agave_main will exit(1) if it fails, so no return code */
     224           0 :   fd_ext_validator_main( (const char **)argv );
     225           0 : }
     226             : 
     227             : int
     228           0 : agave_main( void * args ) {
     229           0 :   config_t * config = args;
     230             : 
     231           0 :   if( FD_UNLIKELY( config->development.debug_tile ) ) {
     232           0 :     if( FD_UNLIKELY( config->development.debug_tile==UINT_MAX ) ) {
     233           0 :       FD_LOG_WARNING(( "waiting for debugger to attach to tile agave pid:%lu", fd_sandbox_getpid() ));
     234           0 :       if( FD_UNLIKELY( -1==kill( getpid(), SIGSTOP ) ) )
     235           0 :         FD_LOG_ERR(( "kill(SIGSTOP) failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     236           0 :       fd_log_private_shared_lock[1] = 0;
     237           0 :     } else {
     238           0 :       while( FD_LIKELY( fd_log_private_shared_lock[1] ) ) FD_SPIN_PAUSE();
     239           0 :     }
     240           0 :   }
     241             : 
     242           0 :   clone_labs_memory_space_tiles( config );
     243             : 
     244           0 :   ulong pid = fd_sandbox_getpid(); /* Need to read /proc again.. we got a new PID from clone */
     245           0 :   fd_log_private_tid_set( pid );
     246           0 :   fd_log_private_stack_discover( FD_TILE_PRIVATE_STACK_SZ,
     247           0 :                                  &fd_tile_private_stack0, &fd_tile_private_stack1 );
     248           0 :   FD_LOG_NOTICE(( "booting agave pid:%lu", fd_log_group_id() ));
     249             : 
     250           0 :   fd_sandbox_switch_uid_gid( config->uid, config->gid );
     251             : 
     252           0 :   agave_boot( config );
     253           0 :   return 0;
     254           0 : }
     255             : 
     256             : void
     257             : run_agave_cmd_fn( args_t *   args FD_PARAM_UNUSED,
     258           0 :                   config_t * config ) {
     259           0 :   fd_log_thread_set( "agave" );
     260             : 
     261           0 :   void * stack = create_clone_stack();
     262             : 
     263             :   /* Also clone Agave into PID namespaces so it cannot signal
     264             :      other tile or the parent. */
     265           0 :   int flags = config->development.sandbox ? CLONE_NEWPID : 0;
     266           0 :   pid_t clone_pid = clone( agave_main, (uchar *)stack + FD_TILE_PRIVATE_STACK_SZ, flags, config );
     267           0 :   if( FD_UNLIKELY( clone_pid<0 ) ) FD_LOG_ERR(( "clone() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     268           0 : }
     269             : 
     270             : action_t fd_action_run_agave = {
     271             :   .name        = "run-agave",
     272             :   .args        = NULL,
     273             :   .fn          = run_agave_cmd_fn,
     274             :   .perm        = NULL,
     275             :   .description = "Start up the Agave side of a Firedancer validator",
     276             : };

Generated by: LCOV version 1.14